KT-9500 Prohibit java.lang.Deprecated in completion + no duplicates for built-ins in completion

#KT-9500 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-10-09 12:47:26 +03:00
parent 7b2d63cfb9
commit 21b2631558
9 changed files with 84 additions and 17 deletions
@@ -55,6 +55,7 @@ public class ShadowedDeclarationsFilter private constructor(
is CallTypeAndReceiver.DOT -> callTypeAndReceiver.receiver
is CallTypeAndReceiver.SAFE -> callTypeAndReceiver.receiver
is CallTypeAndReceiver.INFIX -> callTypeAndReceiver.receiver
is CallTypeAndReceiver.TYPE -> null // need filtering of classes with the same FQ-name
else -> return null // TODO: support shadowed declarations filtering for callable references
}
@@ -98,7 +99,8 @@ public class ShadowedDeclarationsFilter private constructor(
private fun signature(descriptor: DeclarationDescriptor): Any {
return when (descriptor) {
is SimpleFunctionDescriptor -> FunctionSignature(descriptor)
is VariableDescriptor -> descriptor.getName()
is VariableDescriptor -> descriptor.name
is ClassDescriptor -> descriptor.importableFqName ?: descriptor
else -> descriptor
}
}
@@ -109,9 +111,14 @@ public class ShadowedDeclarationsFilter private constructor(
descriptors: Collection<TDescriptor>,
descriptorsToImport: Collection<TDescriptor> = emptyList()
): Collection<TDescriptor> {
if (descriptors.size() == 1) return descriptors
if (descriptors.size == 1) return descriptors
val first = descriptors.first()
if (first is ClassDescriptor) { // for classes with the same FQ-name we simply take the first one
return listOf<TDescriptor>(first)
}
val isFunction = first is FunctionDescriptor
val name = first.getName()
val parameters = (first as CallableDescriptor).getValueParameters()
@@ -39,8 +39,13 @@ class AllClassesCompletion(private val parameters: CompletionParameters,
) {
fun collect(classDescriptorCollector: (ClassDescriptor) -> Unit, javaClassCollector: (PsiClass) -> Unit) {
//TODO: this is a temporary hack until we have built-ins in indices
collectClassesFromScope(classDescriptorCollector, resolutionFacade.moduleDescriptor.builtIns.builtInsPackageScope)
//TODO: this is a temporary solution until we have built-ins in indices
// we need only nested classes because top-level built-ins are all added through default imports
collectClassesFromScope(resolutionFacade.moduleDescriptor.builtIns.builtInsPackageScope) {
if (it.containingDeclaration is ClassDescriptor) {
classDescriptorCollector(it)
}
}
kotlinIndicesHelper
.getKotlinClasses({ prefixMatcher.prefixMatches(it) }, kindFilter)
@@ -51,14 +56,14 @@ class AllClassesCompletion(private val parameters: CompletionParameters,
}
}
private fun collectClassesFromScope(collector: (ClassDescriptor) -> Unit, scope: JetScope) {
private fun collectClassesFromScope(scope: JetScope, collector: (ClassDescriptor) -> Unit) {
for (descriptor in scope.getDescriptorsFiltered(DescriptorKindFilter.CLASSIFIERS)) {
if (descriptor is ClassDescriptor) {
if (kindFilter(descriptor.kind) && prefixMatcher.prefixMatches(descriptor.name.asString())) {
collector(descriptor)
}
collectClassesFromScope(collector, descriptor.unsubstitutedInnerClassesScope)
collectClassesFromScope(descriptor.unsubstitutedInnerClassesScope, collector)
}
}
}
@@ -53,13 +53,15 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
class CompletionSessionConfiguration(
val completeNonImportedDeclarations: Boolean,
val completeNonAccessibleDeclarations: Boolean,
val filterOutJavaGettersAndSetters: Boolean
val filterOutJavaGettersAndSetters: Boolean,
val completeJavaClassesNotToBeUsed: Boolean
)
fun CompletionSessionConfiguration(parameters: CompletionParameters) = CompletionSessionConfiguration(
completeNonImportedDeclarations = parameters.getInvocationCount() >= 2,
completeNonAccessibleDeclarations = parameters.getInvocationCount() >= 2,
filterOutJavaGettersAndSetters = parameters.getInvocationCount() < 2
completeNonImportedDeclarations = parameters.invocationCount >= 2,
completeNonAccessibleDeclarations = parameters.invocationCount >= 2,
filterOutJavaGettersAndSetters = parameters.invocationCount < 2,
completeJavaClassesNotToBeUsed = parameters.invocationCount >= 2
)
abstract class CompletionSession(protected val configuration: CompletionSessionConfiguration,
@@ -150,7 +152,12 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
protected val toFromOriginalFileMapper: ToFromOriginalFileMapper
= ToFromOriginalFileMapper(parameters.originalFile as JetFile, position.containingFile as JetFile, parameters.offset)
protected fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean {
private fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean {
if (!configuration.completeJavaClassesNotToBeUsed && descriptor is ClassDescriptor) {
val classification = descriptor.importableFqName?.let { importableFqNameClassifier.classify(it, isPackage = false) }
if (classification == ImportableFqNameClassifier.Classification.notToBeUsedInKotlin) return false
}
if (descriptor is TypeParameterDescriptor && !isTypeParameterVisible(descriptor)) return false
if (descriptor is DeclarationDescriptorWithVisibility) {
@@ -199,11 +206,11 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
protected abstract val expectedInfos: Collection<ExpectedInfo>
protected val importableFqNameClassifier = ImportableFqNameClassifier(file)
protected open fun createSorter(): CompletionSorter {
var sorter = CompletionSorter.defaultSorter(parameters, prefixMatcher)!!
val importableFqNameClassifier = ImportableFqNameClassifier(file)
sorter = sorter.weighBefore("stats", DeprecatedWeigher, PriorityWeigher, NotImportedWeigher(importableFqNameClassifier), KindWeigher, CallableWeigher)
sorter = sorter.weighAfter("stats", VariableOrFunctionWeigher, ImportedWeigher(importableFqNameClassifier))
@@ -261,9 +261,11 @@ public class KotlinCompletionContributor : CompletionContributor() {
val somethingAdded = session.complete()
if (!somethingAdded && parameters.getInvocationCount() < 2) {
// Rerun completion if nothing was found
val newConfiguration = CompletionSessionConfiguration(completeNonImportedDeclarations = true,
completeNonAccessibleDeclarations = false,
filterOutJavaGettersAndSetters = false)
val newConfiguration = CompletionSessionConfiguration(
completeNonImportedDeclarations = true,
completeNonAccessibleDeclarations = false,
filterOutJavaGettersAndSetters = false,
completeJavaClassesNotToBeUsed = false)
BasicCompletionSession(newConfiguration, parameters, result).complete()
}
}
@@ -0,0 +1,6 @@
@Dep<caret>
fun foo() { }
// INVOCATION_COUNT: 1
// EXIST: { itemText: "Deprecated", tailText: " (kotlin)" }
// NOTHING_ELSE
@@ -0,0 +1,8 @@
@Dep<caret>
fun foo() { }
// INVOCATION_COUNT: 2
// WITH_ORDER
// EXIST: { itemText: "Deprecated", tailText: " (kotlin)" }
// EXIST_JAVA_ONLY: { itemText: "Deprecated", tailText: " (java.lang)" }
// NOTHING_ELSE
@@ -735,6 +735,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
doTest(fileName);
}
@TestMetadata("Deprecated.kt")
public void testDeprecated() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/annotations/Deprecated.kt");
doTest(fileName);
}
@TestMetadata("Deprecated2.kt")
public void testDeprecated2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/annotations/Deprecated2.kt");
doTest(fileName);
}
@TestMetadata("FunctionAnnotation1.kt")
public void testFunctionAnnotation1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/annotations/FunctionAnnotation1.kt");
@@ -735,6 +735,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName);
}
@TestMetadata("Deprecated.kt")
public void testDeprecated() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/annotations/Deprecated.kt");
doTest(fileName);
}
@TestMetadata("Deprecated2.kt")
public void testDeprecated2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/annotations/Deprecated2.kt");
doTest(fileName);
}
@TestMetadata("FunctionAnnotation1.kt")
public void testFunctionAnnotation1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/annotations/FunctionAnnotation1.kt");
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.core
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.load.java.components.JavaAnnotationMapper
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.psi.JetFile
@@ -65,12 +66,19 @@ class ImportableFqNameClassifier(private val file: JetFile) {
}
return when {
JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty() -> Classification.notToBeUsedInKotlin
JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty()
|| JavaAnnotationMapper.javaToKotlinNameMap[fqName] != null -> Classification.notToBeUsedInKotlin
fqName.parent() == file.packageFqName -> Classification.fromCurrentPackage
ImportInsertHelper.getInstance(file.project).isImportedWithDefault(importPath, file) -> Classification.defaultImport
isImportedWithPreciseImport(fqName) -> Classification.preciseImport
isImportedWithAllUnderImport(fqName) -> Classification.allUnderImport
hasPreciseImportFromPackage(fqName.parent()) -> Classification.hasImportFromSamePackage
else -> Classification.notImported
}
}