From a4c9aa43a567840b03bd4d3a4c70256d7b2856c3 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 28 Jul 2015 18:22:24 +0300 Subject: [PATCH] Experimental feature to show properties in completion after prefix with "get" or "set" --- .../idea/completion/CompletionSession.kt | 21 +++++++++++++++--- .../completion/KDocCompletionContributor.kt | 2 +- .../idea/completion/LookupElementFactory.kt | 22 ++++++++++++++----- .../basic/common/GetPrefixForProperties.kt | 18 +++++++++++++++ .../basic/common/SetPrefixForProperties.kt | 16 ++++++++++++++ .../ShowGetMethodWhenNothingElseMatch.kt | 5 ----- .../test/JSBasicCompletionTestGenerated.java | 18 ++++++++++----- .../test/JvmBasicCompletionTestGenerated.java | 18 ++++++++++----- 8 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt create mode 100644 idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt delete mode 100644 idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 7d5218d428c..409156c4eca 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -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( @@ -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) @@ -207,7 +222,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC referenceVariantsHelper.getReferenceVariants( nameExpression!!, descriptorKindFilter!!, - prefixMatcher.asNameFilter(), + descriptorNameFilter, filterOutJavaGettersAndSetters = configuration.filterOutJavaGettersAndSetters ).excludeNonInitializedVariable(nameExpression) } @@ -231,7 +246,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC protected fun getRuntimeReceiverTypeReferenceVariants(): Collection { 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) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt index 98984a5cde9..d34f2784f2a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt @@ -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(element) { override fun handleInsert(context: InsertionContext?) { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt index 1055b0a3b0f..70e0f9ad2df 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt @@ -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 @@ -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 @@ -255,6 +255,7 @@ 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() + "()" @@ -262,9 +263,8 @@ public class LookupElementFactory( 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() @@ -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) } diff --git a/idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt b/idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt new file mode 100644 index 00000000000..c346fc5f833 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt @@ -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 +} + +// EXIST: property1 +// EXIST: property2 +// EXIST: getPPP +// EXIST_JAVA_ONLY: priority +// ABSENT: getPriority +// ABSENT: xxx diff --git a/idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt b/idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt new file mode 100644 index 00000000000..aa4e52e4667 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt @@ -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 +} + +// ABSENT: property1 +// EXIST: property2 +// EXIST: setPPP +// ABSENT: xxx diff --git a/idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt b/idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt deleted file mode 100644 index bc619e05fd9..00000000000 --- a/idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt +++ /dev/null @@ -1,5 +0,0 @@ -fun foo(thread: Thread) { - thread.get -} - -// EXIST_JAVA_ONLY: getPriority diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index ecc898721c7..535fde8965e 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -253,6 +253,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes 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"); @@ -769,6 +775,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes 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"); @@ -1227,12 +1239,6 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes 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"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index e0c56e63211..42be488f5d7 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -253,6 +253,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT 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"); @@ -769,6 +775,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT 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"); @@ -1227,12 +1239,6 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT 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");