From ef095dd5599a0fdd96054269a8d2bfa2b2ef28f8 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 31 Jul 2015 15:48:10 +0200 Subject: [PATCH] better filtering of elements in KDoc link completion --- .../kotlin/resolve/scopes/JetScope.kt | 4 ++-- .../kotlin/idea/kdoc/KDocReference.kt | 3 +++ .../completion/KDocCompletionContributor.kt | 22 ++++++++++++++++++- .../testData/kdoc/MemberLink.kt | 18 +++++++++++++++ .../test/KDocCompletionTestGenerated.java | 6 +++++ 5 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 idea/idea-completion/testData/kdoc/MemberLink.kt diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt index 8c03d7b4bc6..fa578d78a60 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt @@ -92,8 +92,8 @@ public interface JetScope { * The same as getDescriptors(kindFilter, nameFilter) but the result is guaranteed to be filtered by kind and name. */ public fun JetScope.getDescriptorsFiltered( - kindFilter: DescriptorKindFilter, - nameFilter: (Name) -> Boolean + kindFilter: DescriptorKindFilter = DescriptorKindFilter.ALL, + nameFilter: (Name) -> Boolean = { true } ): Collection { if (kindFilter.kindMask == 0) return listOf() return getDescriptors(kindFilter, nameFilter).filter { kindFilter.accepts(it) && nameFilter(it.getName()) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocReference.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocReference.kt index d57575e72b9..86193674c8f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocReference.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/kdoc/KDocReference.kt @@ -154,6 +154,9 @@ public fun getResolutionScope(resolutionFacade: ResolutionFacade, descriptor: De is PackageViewDescriptor -> descriptor.memberScope + is ClassDescriptorWithResolutionScopes -> + descriptor.getScopeForMemberDeclarationResolution() + is ClassDescriptor -> getClassInnerScope(getOuterScope(descriptor, resolutionFacade), 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 d34f2784f2a..ea3039e1684 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 @@ -23,9 +23,12 @@ import com.intellij.codeInsight.lookup.LookupElementDecorator import com.intellij.patterns.PlatformPatterns.psiElement import com.intellij.patterns.StandardPatterns import com.intellij.util.ProcessingContext +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.kdoc.getParamDescriptors import org.jetbrains.kotlin.idea.kdoc.getResolutionScope +import org.jetbrains.kotlin.idea.util.CallType +import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable import org.jetbrains.kotlin.kdoc.lexer.KDocTokens import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink @@ -33,7 +36,10 @@ import org.jetbrains.kotlin.kdoc.psi.impl.KDocName import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered class KDocCompletionContributor(): CompletionContributor() { init { @@ -86,7 +92,21 @@ class KDocNameCompletionSession(parameters: CompletionParameters, private fun addLinkCompletions(declarationDescriptor: DeclarationDescriptor) { val scope = getResolutionScope(resolutionFacade, declarationDescriptor) - scope.getDescriptors(nameFilter = descriptorNameFilter).forEach { + val implicitReceivers = scope.getImplicitReceiversHierarchy().map { it.value } + + fun isApplicable(descriptor: DeclarationDescriptor): Boolean { + if (descriptor is CallableDescriptor) { + val extensionReceiver = descriptor.getExtensionReceiverParameter() + if (extensionReceiver != null) { + val substituted = descriptor.substituteExtensionIfCallable(implicitReceivers, bindingContext, DataFlowInfo.EMPTY, + CallType.NORMAL, moduleDescriptor) + return !substituted.isEmpty() + } + } + return true + } + + scope.getDescriptorsFiltered(nameFilter = descriptorNameFilter).filter(::isApplicable).forEach { val element = lookupElementFactory.createLookupElement(it, false) collector.addElement(object: LookupElementDecorator(element) { override fun handleInsert(context: InsertionContext?) { diff --git a/idea/idea-completion/testData/kdoc/MemberLink.kt b/idea/idea-completion/testData/kdoc/MemberLink.kt new file mode 100644 index 00000000000..debe6b6faf1 --- /dev/null +++ b/idea/idea-completion/testData/kdoc/MemberLink.kt @@ -0,0 +1,18 @@ +class Foo { + /** + * [] + */ + fun xyzzy() { + + } + + fun bar() { + + } +} + +fun Foo.quux() { +} + +// EXIST: bar +// EXIST: quux diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KDocCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KDocCompletionTestGenerated.java index fdc99d4315b..ea729a08e8d 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KDocCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KDocCompletionTestGenerated.java @@ -41,6 +41,12 @@ public class KDocCompletionTestGenerated extends AbstractJvmBasicCompletionTest doTest(fileName); } + @TestMetadata("MemberLink.kt") + public void testMemberLink() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/kdoc/MemberLink.kt"); + doTest(fileName); + } + @TestMetadata("NotTagName.kt") public void testNotTagName() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/kdoc/NotTagName.kt");