Fixed filtering of shadowed declarations after changes in extensions treatment

This commit is contained in:
Valentin Kipyatkov
2015-10-28 18:25:03 +03:00
parent be5569d31a
commit 9feed9c3ef
8 changed files with 93 additions and 49 deletions
@@ -58,10 +58,11 @@ class ReferenceVariantsHelper(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
filterOutJavaGettersAndSetters: Boolean = false,
filterOutShadowed: Boolean = true,
useRuntimeReceiverType: Boolean = false
): Collection<DeclarationDescriptor>
= getReferenceVariants(expression, CallTypeAndReceiver.detect(expression),
kindFilter, nameFilter, filterOutJavaGettersAndSetters, useRuntimeReceiverType)
kindFilter, nameFilter, filterOutJavaGettersAndSetters, filterOutShadowed, useRuntimeReceiverType)
fun getReferenceVariants(
contextElement: PsiElement,
@@ -69,32 +70,39 @@ class ReferenceVariantsHelper(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
filterOutJavaGettersAndSetters: Boolean = false,
filterOutShadowed: Boolean = true,
useRuntimeReceiverType: Boolean = false
): Collection<DeclarationDescriptor> {
var variants: Collection<DeclarationDescriptor>
= getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useRuntimeReceiverType)
.filter { !it.isAnnotatedAsHidden() && visibilityFilter(it) }
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, contextElement, callTypeAndReceiver)?.let {
variants = it.filter(variants)
if (filterOutShadowed) {
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, contextElement, callTypeAndReceiver)?.let {
variants = it.filter(variants)
}
}
if (filterOutJavaGettersAndSetters) {
val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
for (variant in variants) {
if (variant is SyntheticJavaPropertyDescriptor) {
accessorMethodsToRemove.add(variant.getMethod.original)
accessorMethodsToRemove.addIfNotNull(variant.setMethod?.original)
}
}
variants = variants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove }
variants = filterOutJavaGettersAndSetters(variants)
}
return variants
}
fun filterOutJavaGettersAndSetters(variants: Collection<DeclarationDescriptor>): Collection<DeclarationDescriptor> {
val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
for (variant in variants) {
if (variant is SyntheticJavaPropertyDescriptor) {
accessorMethodsToRemove.add(variant.getMethod.original)
accessorMethodsToRemove.addIfNotNull(variant.setMethod?.original)
}
}
return variants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove }
}
private fun getReferenceVariantsNoVisibilityFilter(
contextElement: PsiElement,
kindFilter: DescriptorKindFilter,
@@ -209,7 +209,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
collector.addElements(additionalItems)
}
collector.addDescriptorElements(referenceVariants)
referenceVariants?.let {
val (imported, notImported) = it
collector.addDescriptorElements(imported)
collector.addDescriptorElements(notImported, notImported = true)
}
completeKeywords()
@@ -233,13 +237,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
flushToResultSet()
if (completionKind == CompletionKind.ALL && callTypeAndReceiver.shouldCompleteCallableExtensions()) {
for (extension in getCallableTopLevelExtensions()) {
collector.addDescriptorElements(extension, !isImportableDescriptorImported(extension))
}
flushToResultSet()
}
if (completionKind != CompletionKind.KEYWORDS_ONLY) {
completeNonImported()
@@ -411,7 +408,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
}
if (callTypeAndReceiver.receiver != null) {
val referenceVariantsSet = referenceVariants.toSet()
val referenceVariantsSet = referenceVariants!!.imported.toSet()
superClasses = superClasses.filter { it in referenceVariantsSet }
}
@@ -260,18 +260,41 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
return context
}
protected val referenceVariants: Collection<DeclarationDescriptor> by lazy(LazyThreadSafetyMode.NONE) {
if (descriptorKindFilter != null) {
referenceVariantsHelper.getReferenceVariants(
nameExpression!!,
descriptorKindFilter!!,
descriptorNameFilter,
filterOutJavaGettersAndSetters = configuration.filterOutJavaGettersAndSetters
).excludeNonInitializedVariable(nameExpression)
/* TODO: not protected because of KT-9809 */
data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>)
protected val referenceVariants: ReferenceVariants? by lazy {
if (descriptorKindFilter == null) return@lazy null
var variants = referenceVariantsHelper.getReferenceVariants(
nameExpression!!,
descriptorKindFilter!!,
descriptorNameFilter,
filterOutJavaGettersAndSetters = false,
filterOutShadowed = false)
variants = variants.excludeNonInitializedVariable(nameExpression)
val shadowedDeclarationsFilter = ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, position, callTypeAndReceiver)
var notImportedExtensions: Collection<CallableDescriptor> = emptyList()
if (callTypeAndReceiver.shouldCompleteCallableExtensions()) {
val extensions = indicesHelper.getCallableTopLevelExtensions({ prefixMatcher.prefixMatches(it) }, callTypeAndReceiver, expression!!, bindingContext)
val pair = extensions.partition { isImportableDescriptorImported(it) }
variants += pair.first
notImportedExtensions = pair.second
}
else {
emptyList()
if (shadowedDeclarationsFilter != null) {
variants = shadowedDeclarationsFilter.filter(variants)
notImportedExtensions = shadowedDeclarationsFilter.filterNonImported(notImportedExtensions, variants)
}
if (configuration.filterOutJavaGettersAndSetters) {
variants = referenceVariantsHelper.filterOutJavaGettersAndSetters(variants)
}
ReferenceVariants(variants, notImportedExtensions)
}
// filters out variable inside its initializer
@@ -296,7 +319,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
filterOutJavaGettersAndSetters = configuration.filterOutJavaGettersAndSetters
).excludeNonInitializedVariable(nameExpression)
return descriptors.filter { descriptor ->
referenceVariants.none { compareDescriptors(project, it, descriptor) }
referenceVariants!!.imported.none { compareDescriptors(project, it, descriptor) }
}
}
@@ -317,14 +340,9 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
&& this !is CallTypeAndReceiver.IMPORT_DIRECTIVE
}
protected fun getCallableTopLevelExtensions(): Collection<CallableDescriptor> {
return indicesHelper.getCallableTopLevelExtensions({ prefixMatcher.prefixMatches(it) }, callTypeAndReceiver, expression!!, bindingContext)
.filterShadowedNonImported() //TODO: not correct!
}
private fun Collection<CallableDescriptor>.filterShadowedNonImported(): Collection<CallableDescriptor> {
val filter = ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression!!, callTypeAndReceiver)
return if (filter != null) filter.filterNonImported(this, referenceVariants) else this
return if (filter != null) filter.filterNonImported(this, referenceVariants!!.imported) else this
}
protected fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean) {
@@ -73,17 +73,9 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
if (nameExpression != null) {
val filter = smartCompletion!!.descriptorFilter
if (filter != null) {
referenceVariants.forEach { collector.addElements(filter(it)) }
flushToResultSet()
if (callTypeAndReceiver.shouldCompleteCallableExtensions()) {
for (extension in getCallableTopLevelExtensions()) {
val elements = filter(extension)
if (elements.isNotEmpty()) {
collector.addElements(elements, !isImportableDescriptorImported(extension))
}
}
}
val (imported, notImported) = referenceVariants!!
imported.forEach { collector.addElements(filter(it)) }
notImported.forEach { collector.addElements(filter(it), notImported = true) }
flushToResultSet()
@@ -0,0 +1,3 @@
package dependency1
fun Any.xxx(): Int = 1
@@ -0,0 +1,3 @@
package dependency2
fun ppp.C.xxx(): Int = 1
@@ -0,0 +1,17 @@
package ppp
import dependency1.xxx
import dependency2.xxx
interface I
fun I.xxx() {}
class C : I {
fun foo() {
xx<caret>
}
}
// EXIST: { lookupString: "xxx", itemText: "xxx", tailText: "() for C in dependency2", typeText: "Int" }
// NOTHING_ELSE
@@ -311,6 +311,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
doTest(fileName);
}
@TestMetadata("PreferMoreSpecificExtension3")
public void testPreferMoreSpecificExtension3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PreferMoreSpecificExtension3/");
doTest(fileName);
}
@TestMetadata("PropertyKeysEmptyString")
public void testPropertyKeysEmptyString() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/PropertyKeysEmptyString/");