KT-9500 Prohibit java.lang.Deprecated in completion + no duplicates for built-ins in completion
#KT-9500 Fixed
This commit is contained in:
@@ -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()
|
||||
|
||||
+9
-4
@@ -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))
|
||||
|
||||
+5
-3
@@ -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
|
||||
+12
@@ -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");
|
||||
|
||||
+12
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user