diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt index b48cb677b8a..7d1d6647b4e 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.util import com.intellij.openapi.project.Project import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.di.InjectorForMacros -import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DelegatingBindingTrace @@ -35,13 +34,12 @@ import org.jetbrains.kotlin.resolve.scopes.ChainedScope import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.types.TypeUtils -import java.util.ArrayList +import java.util.* public class ShadowedDeclarationsFilter( private val bindingContext: BindingContext, private val moduleDescriptor: ModuleDescriptor, - private val project: Project, - private val importDeclarations: Boolean = false + private val project: Project ) { private val psiFactory = JetPsiFactory(project) private val dummyExpressionFactory = DummyExpressionFactory(psiFactory) @@ -51,7 +49,27 @@ public class ShadowedDeclarationsFilter( return declarations .groupBy { signature(it) } - .flatMap { filterEqualSignatureGroup(it.value, call) } + .values() + .flatMap { group -> filterEqualSignatureGroup(group, call) } + } + + public fun filterNonImported( + declarations: Collection, + importedDeclarations: Collection, + expression: JetSimpleNameExpression + ): Collection { + val importedDeclarationsSet = importedDeclarations.toSet() + val nonImportedDeclarations = declarations.filter { it !in importedDeclarationsSet } + + val call = expression.getCall(bindingContext) ?: return nonImportedDeclarations + + val notShadowed = nonImportedDeclarations + .groupBy { signature(it) } + .values() + .flatMapTo(HashSet()) { group -> + filterEqualSignatureGroup(group + importedDeclarations, call, descriptorsToImport = group) + } + return declarations.filter { it in notShadowed } } private fun signature(descriptor: DeclarationDescriptor): Any { @@ -62,7 +80,11 @@ public class ShadowedDeclarationsFilter( } } - private fun filterEqualSignatureGroup(descriptors: Collection, call: Call): Collection { + private fun filterEqualSignatureGroup( + descriptors: Collection, + call: Call, + descriptorsToImport: Collection = emptyList() + ): Collection { if (descriptors.size() == 1) return descriptors val first = descriptors.first() @@ -128,10 +150,9 @@ public class ShadowedDeclarationsFilter( val calleeExpression = call.getCalleeExpression() ?: return descriptors var resolutionScope = bindingContext.correctedResolutionScope(calleeExpression) ?: return descriptors - if (importDeclarations) { - val importableDescriptors = descriptors.filter { it.canBeReferencedViaImport() } + if (descriptorsToImport.isNotEmpty()) { resolutionScope = ChainedScope(resolutionScope.getContainingDeclaration(), "Scope with explicitly imported descriptors", - ExplicitImportsScope(importableDescriptors), resolutionScope) + ExplicitImportsScope(descriptorsToImport), resolutionScope) } val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression) 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 3175623feaf..24b04f0cefe 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 @@ -226,8 +226,7 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess protected fun getTopLevelExtensions(): Collection { val extensions = indicesHelper.getCallableTopLevelExtensions({ prefixMatcher.prefixMatches(it) }, reference!!.expression) //TODO: it filters out too much - //TODO: not filtered out dominated by members - return ShadowedDeclarationsFilter(bindingContext, moduleDescriptor, project, importDeclarations = true).filter(extensions, reference.expression) + return ShadowedDeclarationsFilter(bindingContext, moduleDescriptor, project).filterNonImported(extensions, referenceVariants, reference.expression) } protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) { diff --git a/idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/PreferMemberToExtension.dependency.kt b/idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/PreferMemberToExtension.dependency.kt new file mode 100644 index 00000000000..8d16711b4fa --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/PreferMemberToExtension.dependency.kt @@ -0,0 +1,3 @@ +package dependency + +fun Any.xxx(): Int = 1 diff --git a/idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/PreferMemberToExtension.kt b/idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/PreferMemberToExtension.kt new file mode 100644 index 00000000000..81cadfdf6e4 --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/PreferMemberToExtension.kt @@ -0,0 +1,14 @@ +package ppp + +import dependency.* + +class C { + private fun xxx() {} + + fun foo() { + xx + } +} + +// EXIST: { lookupString: "xxx", itemText: "xxx", tailText: "()", typeText: "Unit" } +// NOTHING_ELSE diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java index 06669c31a53..0881e552f59 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java @@ -215,6 +215,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ doTest(fileName); } + @TestMetadata("PreferMemberToExtension") + public void testPreferMemberToExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/"); + doTest(fileName); + } + @TestMetadata("PreferMoreSpecificExtension1") public void testPreferMoreSpecificExtension1() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PreferMoreSpecificExtension1/");