Skip to content

Commit

Permalink
Experimental feature to show properties in completion after prefix wi…
Browse files Browse the repository at this point in the history
…th "get" or "set"
  • Loading branch information
valentinkip committed Jul 30, 2015
1 parent 23dca52 commit a4c9aa4
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 27 deletions.
Expand Up @@ -42,14 +42,17 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance

class CompletionSessionConfiguration(
Expand Down Expand Up @@ -120,6 +123,18 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC

protected val prefixMatcher: PrefixMatcher = CamelHumpMatcher(prefix)

protected val descriptorNameFilter: (Name) -> Boolean = run {
val nameFilter = prefixMatcher.asNameFilter()
val getOrSetPrefix = listOf("get", "set").firstOrNull { prefix.startsWith(it) }
if (getOrSetPrefix != null)
nameFilter or prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmart()).asNameFilter()
else
nameFilter
}

private fun ((Name) -> Boolean).or(otherFilter: (Name) -> Boolean): (Name) -> Boolean
= { this(it) || otherFilter(it) }

protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it) }

protected val referenceVariantsHelper: ReferenceVariantsHelper = ReferenceVariantsHelper(bindingContext, moduleDescriptor, project, isVisibleFilter)
Expand Down Expand Up @@ -207,7 +222,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
referenceVariantsHelper.getReferenceVariants(
nameExpression!!,
descriptorKindFilter!!,
prefixMatcher.asNameFilter(),
descriptorNameFilter,
filterOutJavaGettersAndSetters = configuration.filterOutJavaGettersAndSetters
).excludeNonInitializedVariable(nameExpression)
}
Expand All @@ -231,7 +246,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC

protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
val restrictedKindFilter = descriptorKindFilter!!.restrictedToKinds(DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK) // optimization
val descriptors = referenceVariantsHelper.getReferenceVariants(nameExpression!!, restrictedKindFilter, prefixMatcher.asNameFilter(), useRuntimeReceiverType = true)
val descriptors = referenceVariantsHelper.getReferenceVariants(nameExpression!!, restrictedKindFilter, descriptorNameFilter, useRuntimeReceiverType = true)
return descriptors.filter { descriptor ->
referenceVariants.none { comparePossiblyOverridingDescriptors(project, it, descriptor) }
}
Expand Down
Expand Up @@ -86,7 +86,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,

private fun addLinkCompletions(declarationDescriptor: DeclarationDescriptor) {
val scope = getResolutionScope(resolutionFacade, declarationDescriptor)
scope.getDescriptors(nameFilter = prefixMatcher.asNameFilter()).forEach {
scope.getDescriptors(nameFilter = descriptorNameFilter).forEach {
val element = lookupElementFactory.createLookupElement(it, false)
collector.addElement(object: LookupElementDecorator<LookupElement>(element) {
override fun handleInsert(context: InsertionContext?) {
Expand Down
Expand Up @@ -29,8 +29,7 @@ import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.completion.handlers.*
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
import org.jetbrains.kotlin.types.typeUtil.nullability
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.psiUtil.parents
Expand All @@ -40,7 +39,8 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import javax.swing.Icon
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
import org.jetbrains.kotlin.types.typeUtil.nullability

public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObject {
override val psiElement: PsiElement? get() = null
Expand Down Expand Up @@ -255,16 +255,16 @@ public class LookupElementFactory(

if (descriptor is CallableDescriptor) {
val original = descriptor.original
val extensionReceiver = original.extensionReceiverParameter
when {
original is SyntheticJavaPropertyDescriptor -> {
var from = original.getMethod.getName().asString() + "()"
original.setMethod?.let { from += "/" + it.getName().asString() + "()" }
element = element.appendTailText(" (from $from)", true)
}

descriptor.getExtensionReceiverParameter() != null -> {
val originalReceiver = descriptor.getOriginal().getExtensionReceiverParameter()!!
val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(originalReceiver.getType())
extensionReceiver != null -> {
val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type)
element = element.appendTailText(" for $receiverPresentation", true)

val container = descriptor.getContainingDeclaration()
Expand All @@ -289,6 +289,16 @@ public class LookupElementFactory(
}
}

if (descriptor is PropertyDescriptor) {
val getterName = JvmAbi.getterName(name)
if (getterName != name) {
element = element.withLookupString(getterName)
}
if (descriptor.isVar) {
element = element.withLookupString(JvmAbi.setterName(name))
}
}

if (lookupObject.isDeprecated) {
element = element.withStrikeoutness(true)
}
Expand Down
@@ -0,0 +1,18 @@
class C : Thread() {
val property1: Int = 0
var property2: Int = 0
var xxx: Int = 0

fun getPPP() = 1
}

fun foo(c: C) {
c.getP<caret>
}

// EXIST: property1
// EXIST: property2
// EXIST: getPPP
// EXIST_JAVA_ONLY: priority
// ABSENT: getPriority
// ABSENT: xxx
@@ -0,0 +1,16 @@
class C {
val property1: Int = 0
var property2: Int = 0
var xxx: Int = 0

fun setPPP(){}
}

fun foo(c: C) {
c.setP<caret>
}

// ABSENT: property1
// EXIST: property2
// EXIST: setPPP
// ABSENT: xxx

This file was deleted.

Expand Up @@ -253,6 +253,12 @@ public void testGenericKotlinClass() throws Exception {
doTest(fileName);
}

@TestMetadata("GetPrefixForProperties.kt")
public void testGetPrefixForProperties() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt");
doTest(fileName);
}

@TestMetadata("HigherOrderFunction1.kt")
public void testHigherOrderFunction1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt");
Expand Down Expand Up @@ -769,6 +775,12 @@ public void testSafeCallAfterNullable() throws Exception {
doTest(fileName);
}

@TestMetadata("SetPrefixForProperties.kt")
public void testSetPrefixForProperties() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt");
doTest(fileName);
}

@TestMetadata("ShortClassNamesInTypePosition.kt")
public void testShortClassNamesInTypePosition() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ShortClassNamesInTypePosition.kt");
Expand Down Expand Up @@ -1227,12 +1239,6 @@ public void testNoMemberExtensionsFromCompanionObject() throws Exception {
doTest(fileName);
}

@TestMetadata("ShowGetMethodWhenNothingElseMatch.kt")
public void testShowGetMethodWhenNothingElseMatch() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt");
doTest(fileName);
}

@TestMetadata("ShowGetSetOnSecondCompletion.kt")
public void testShowGetSetOnSecondCompletion() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetSetOnSecondCompletion.kt");
Expand Down
Expand Up @@ -253,6 +253,12 @@ public void testGenericKotlinClass() throws Exception {
doTest(fileName);
}

@TestMetadata("GetPrefixForProperties.kt")
public void testGetPrefixForProperties() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt");
doTest(fileName);
}

@TestMetadata("HigherOrderFunction1.kt")
public void testHigherOrderFunction1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt");
Expand Down Expand Up @@ -769,6 +775,12 @@ public void testSafeCallAfterNullable() throws Exception {
doTest(fileName);
}

@TestMetadata("SetPrefixForProperties.kt")
public void testSetPrefixForProperties() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt");
doTest(fileName);
}

@TestMetadata("ShortClassNamesInTypePosition.kt")
public void testShortClassNamesInTypePosition() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ShortClassNamesInTypePosition.kt");
Expand Down Expand Up @@ -1227,12 +1239,6 @@ public void testNoMemberExtensionsFromCompanionObject() throws Exception {
doTest(fileName);
}

@TestMetadata("ShowGetMethodWhenNothingElseMatch.kt")
public void testShowGetMethodWhenNothingElseMatch() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt");
doTest(fileName);
}

@TestMetadata("ShowGetSetOnSecondCompletion.kt")
public void testShowGetSetOnSecondCompletion() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetSetOnSecondCompletion.kt");
Expand Down

0 comments on commit a4c9aa4

Please sign in to comment.