Non-imported extensions are excluded when shadowed by members or something
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package dependency
|
||||||
|
|
||||||
|
fun Any.xxx(): Int = 1
|
||||||
Vendored
+14
@@ -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
|
||||||
+6
@@ -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/");
|
||||||
|
|||||||
Reference in New Issue
Block a user