Non-imported extensions are excluded when shadowed by members or something

This commit is contained in:
Valentin Kipyatkov
2015-06-10 17:48:55 +03:00
parent f089d1ef55
commit 8d11ab9866
5 changed files with 54 additions and 11 deletions
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.util
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.di.InjectorForMacros import org.jetbrains.kotlin.di.InjectorForMacros
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace 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.scopes.ExplicitImportsScope
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import java.util.ArrayList import java.util.*
public class ShadowedDeclarationsFilter( public class ShadowedDeclarationsFilter(
private val bindingContext: BindingContext, private val bindingContext: BindingContext,
private val moduleDescriptor: ModuleDescriptor, private val moduleDescriptor: ModuleDescriptor,
private val project: Project, private val project: Project
private val importDeclarations: Boolean = false
) { ) {
private val psiFactory = JetPsiFactory(project) private val psiFactory = JetPsiFactory(project)
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory) private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
@@ -51,7 +49,27 @@ public class ShadowedDeclarationsFilter(
return declarations return declarations
.groupBy { signature(it) } .groupBy { signature(it) }
.flatMap { filterEqualSignatureGroup(it.value, call) } .values()
.flatMap { group -> filterEqualSignatureGroup(group, call) }
}
public fun <TDescriptor : DeclarationDescriptor> filterNonImported(
declarations: Collection<TDescriptor>,
importedDeclarations: Collection<DeclarationDescriptor>,
expression: JetSimpleNameExpression
): Collection<TDescriptor> {
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<DeclarationDescriptor>()) { group ->
filterEqualSignatureGroup(group + importedDeclarations, call, descriptorsToImport = group)
}
return declarations.filter { it in notShadowed }
} }
private fun signature(descriptor: DeclarationDescriptor): Any { private fun signature(descriptor: DeclarationDescriptor): Any {
@@ -62,7 +80,11 @@ public class ShadowedDeclarationsFilter(
} }
} }
private fun <TDescriptor : DeclarationDescriptor> filterEqualSignatureGroup(descriptors: Collection<TDescriptor>, call: Call): Collection<TDescriptor> { private fun <TDescriptor : DeclarationDescriptor> filterEqualSignatureGroup(
descriptors: Collection<TDescriptor>,
call: Call,
descriptorsToImport: Collection<TDescriptor> = emptyList()
): Collection<TDescriptor> {
if (descriptors.size() == 1) return descriptors if (descriptors.size() == 1) return descriptors
val first = descriptors.first() val first = descriptors.first()
@@ -128,10 +150,9 @@ public class ShadowedDeclarationsFilter(
val calleeExpression = call.getCalleeExpression() ?: return descriptors val calleeExpression = call.getCalleeExpression() ?: return descriptors
var resolutionScope = bindingContext.correctedResolutionScope(calleeExpression) ?: return descriptors var resolutionScope = bindingContext.correctedResolutionScope(calleeExpression) ?: return descriptors
if (importDeclarations) { if (descriptorsToImport.isNotEmpty()) {
val importableDescriptors = descriptors.filter { it.canBeReferencedViaImport() }
resolutionScope = ChainedScope(resolutionScope.getContainingDeclaration(), "Scope with explicitly imported descriptors", resolutionScope = ChainedScope(resolutionScope.getContainingDeclaration(), "Scope with explicitly imported descriptors",
ExplicitImportsScope(importableDescriptors), resolutionScope) ExplicitImportsScope(descriptorsToImport), resolutionScope)
} }
val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression) val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression)
@@ -226,8 +226,7 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
protected fun getTopLevelExtensions(): Collection<CallableDescriptor> { protected fun getTopLevelExtensions(): Collection<CallableDescriptor> {
val extensions = indicesHelper.getCallableTopLevelExtensions({ prefixMatcher.prefixMatches(it) }, reference!!.expression) val extensions = indicesHelper.getCallableTopLevelExtensions({ prefixMatcher.prefixMatches(it) }, reference!!.expression)
//TODO: it filters out too much //TODO: it filters out too much
//TODO: not filtered out dominated by members return ShadowedDeclarationsFilter(bindingContext, moduleDescriptor, project).filterNonImported(extensions, referenceVariants, reference.expression)
return ShadowedDeclarationsFilter(bindingContext, moduleDescriptor, project, importDeclarations = true).filter(extensions, reference.expression)
} }
protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) { protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) {
@@ -0,0 +1,3 @@
package dependency
fun Any.xxx(): Int = 1
@@ -0,0 +1,14 @@
package ppp
import dependency.*
class C {
private fun xxx() {}
fun foo() {
xx<caret>
}
}
// EXIST: { lookupString: "xxx", itemText: "xxx", tailText: "()", typeText: "Unit" }
// NOTHING_ELSE
@@ -215,6 +215,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
doTest(fileName); doTest(fileName);
} }
@TestMetadata("PreferMemberToExtension")
public void testPreferMemberToExtension() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PreferMemberToExtension/");
doTest(fileName);
}
@TestMetadata("PreferMoreSpecificExtension1") @TestMetadata("PreferMoreSpecificExtension1")
public void testPreferMoreSpecificExtension1() throws Exception { public void testPreferMoreSpecificExtension1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PreferMoreSpecificExtension1/"); String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PreferMoreSpecificExtension1/");