More correct shadowed declarations filtering in completion

This commit is contained in:
Valentin Kipyatkov
2015-10-30 20:13:13 +03:00
parent 67cf9f9510
commit c11bf32594
7 changed files with 37 additions and 11 deletions
@@ -53,20 +53,22 @@ class ReferenceVariantsHelper(
expression: KtSimpleNameExpression, expression: KtSimpleNameExpression,
kindFilter: DescriptorKindFilter, kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean, nameFilter: (Name) -> Boolean,
filterOutJavaGettersAndSetters: Boolean = false, filterOutJavaGettersAndSetters: Boolean = true,
filterOutShadowed: Boolean = true, filterOutShadowed: Boolean = true,
excludeNonInitializedVariable: Boolean = true,
useReceiverType: KotlinType? = null useReceiverType: KotlinType? = null
): Collection<DeclarationDescriptor> ): Collection<DeclarationDescriptor>
= getReferenceVariants(expression, CallTypeAndReceiver.detect(expression), = getReferenceVariants(expression, CallTypeAndReceiver.detect(expression),
kindFilter, nameFilter, filterOutJavaGettersAndSetters, filterOutShadowed, useReceiverType) kindFilter, nameFilter, filterOutJavaGettersAndSetters, filterOutShadowed, excludeNonInitializedVariable, useReceiverType)
fun getReferenceVariants( fun getReferenceVariants(
contextElement: PsiElement, contextElement: PsiElement,
callTypeAndReceiver: CallTypeAndReceiver<*, *>, callTypeAndReceiver: CallTypeAndReceiver<*, *>,
kindFilter: DescriptorKindFilter, kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean, nameFilter: (Name) -> Boolean,
filterOutJavaGettersAndSetters: Boolean = false, filterOutJavaGettersAndSetters: Boolean = true,
filterOutShadowed: Boolean = true, filterOutShadowed: Boolean = true,
excludeNonInitializedVariable: Boolean = true,
useReceiverType: KotlinType? = null useReceiverType: KotlinType? = null
): Collection<DeclarationDescriptor> { ): Collection<DeclarationDescriptor> {
var variants: Collection<DeclarationDescriptor> var variants: Collection<DeclarationDescriptor>
@@ -79,12 +81,13 @@ class ReferenceVariantsHelper(
} }
} }
if (filterOutJavaGettersAndSetters && kindFilter.kindMask.and(DescriptorKindFilter.FUNCTIONS_MASK) != 0) {
if (filterOutJavaGettersAndSetters) {
variants = filterOutJavaGettersAndSetters(variants) variants = filterOutJavaGettersAndSetters(variants)
} }
variants = variants.excludeNonInitializedVariable(contextElement) if (excludeNonInitializedVariable && kindFilter.kindMask.and(DescriptorKindFilter.VARIABLES_MASK) != 0) {
variants = excludeNonInitializedVariable(variants, contextElement)
}
return variants return variants
} }
@@ -102,16 +105,16 @@ class ReferenceVariantsHelper(
} }
// filters out variable inside its initializer // filters out variable inside its initializer
private fun Collection<DeclarationDescriptor>.excludeNonInitializedVariable(contextElement: PsiElement): Collection<DeclarationDescriptor> { fun excludeNonInitializedVariable(variants: Collection<DeclarationDescriptor>, contextElement: PsiElement): Collection<DeclarationDescriptor> {
for (element in contextElement.parentsWithSelf) { for (element in contextElement.parentsWithSelf) {
val parent = element.parent val parent = element.parent
if (parent is KtVariableDeclaration && element == parent.initializer) { if (parent is KtVariableDeclaration && element == parent.initializer) {
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, parent] val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, parent]
return this.filter { it != descriptor } return variants.filter { it != descriptor }
} }
if (element is KtDeclaration) break // we can use variable inside lambda or anonymous object located in its initializer if (element is KtDeclaration) break // we can use variable inside lambda or anonymous object located in its initializer
} }
return this return variants
} }
private fun getReferenceVariantsNoVisibilityFilter( private fun getReferenceVariantsNoVisibilityFilter(
@@ -172,7 +172,7 @@ class BasicCompletionSession(
val contextVariableTypesForSmartCompletion = withCollectRequiredContextVariableTypes(::completeWithSmartCompletion) val contextVariableTypesForSmartCompletion = withCollectRequiredContextVariableTypes(::completeWithSmartCompletion)
fun completeReferenceVariants(lookupElementFactory: LookupElementFactory) { fun completeReferenceVariants(lookupElementFactory: LookupElementFactory) {
val (imported, notImported) = referenceVariants!! val (imported, notImported) = referenceVariantsWithNonInitializedVarExcluded!!
collector.addDescriptorElements(imported, lookupElementFactory) collector.addDescriptorElements(imported, lookupElementFactory)
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true) collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true)
} }
@@ -284,6 +284,9 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
if (nameExpression != null && descriptorKindFilter != null) collectReferenceVariants(descriptorKindFilter!!, nameExpression) else null if (nameExpression != null && descriptorKindFilter != null) collectReferenceVariants(descriptorKindFilter!!, nameExpression) else null
} }
protected val referenceVariantsWithNonInitializedVarExcluded: ReferenceVariants? by lazy {
referenceVariants?.let { ReferenceVariants(referenceVariantsHelper.excludeNonInitializedVariable(it.imported, position), it.notImportedExtensions) }
}
private fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter, nameExpression: KtSimpleNameExpression, runtimeReceiver: ExpressionReceiver? = null): ReferenceVariants { private fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter, nameExpression: KtSimpleNameExpression, runtimeReceiver: ExpressionReceiver? = null): ReferenceVariants {
var variants = referenceVariantsHelper.getReferenceVariants( var variants = referenceVariantsHelper.getReferenceVariants(
@@ -292,6 +295,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
descriptorNameFilter, descriptorNameFilter,
filterOutJavaGettersAndSetters = false, filterOutJavaGettersAndSetters = false,
filterOutShadowed = false, filterOutShadowed = false,
excludeNonInitializedVariable = false,
useReceiverType = runtimeReceiver?.type) useReceiverType = runtimeReceiver?.type)
val shadowedDeclarationsFilter = if (runtimeReceiver != null) val shadowedDeclarationsFilter = if (runtimeReceiver != null)
@@ -78,7 +78,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
val filter = smartCompletion!!.descriptorFilter val filter = smartCompletion!!.descriptorFilter
var contextVariableTypesForReferenceVariants = filter?.let { var contextVariableTypesForReferenceVariants = filter?.let {
withCollectRequiredContextVariableTypes { lookupElementFactory -> withCollectRequiredContextVariableTypes { lookupElementFactory ->
val (imported, notImported) = referenceVariants ?: return@withCollectRequiredContextVariableTypes val (imported, notImported) = referenceVariantsWithNonInitializedVarExcluded ?: return@withCollectRequiredContextVariableTypes
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) } imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) } notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
} }
@@ -0,0 +1,7 @@
val xxx: String = ""
class C {
val xxx = x<caret>
}
// ABSENT: xxx
@@ -1929,6 +1929,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("InInitializer7.kt")
public void testInInitializer7() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer7.kt");
doTest(fileName);
}
@TestMetadata("Locals1.kt") @TestMetadata("Locals1.kt")
public void testLocals1() throws Exception { public void testLocals1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt"); String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt");
@@ -1929,6 +1929,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName); doTest(fileName);
} }
@TestMetadata("InInitializer7.kt")
public void testInInitializer7() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/InInitializer7.kt");
doTest(fileName);
}
@TestMetadata("Locals1.kt") @TestMetadata("Locals1.kt")
public void testLocals1() throws Exception { public void testLocals1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt"); String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/shadowing/Locals1.kt");