diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt index 51dfa19dee1..58851d75f53 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt @@ -67,7 +67,7 @@ abstract class DeclarationLookupObjectImpl( } // This function is kind of a hack to avoid using DeprecationResolver as it's hard to preserve same resolutionFacade for descriptor -private fun isDeprecatedAtCallSite(descriptor: DeclarationDescriptor, languageVersionSettings: LanguageVersionSettings?): Boolean { +fun isDeprecatedAtCallSite(descriptor: DeclarationDescriptor, languageVersionSettings: LanguageVersionSettings?): Boolean { val isDeprecatedAtDeclarationSite = KotlinBuiltIns.isDeprecated(descriptor) if (languageVersionSettings == null) return isDeprecatedAtDeclarationSite diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index 1e441a85c54..99701d8de5c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -33,7 +33,7 @@ import com.intellij.psi.statistics.StatisticsManager import com.intellij.psi.util.proximity.PsiProximityComparator import com.intellij.ui.popup.list.ListPopupImpl import com.intellij.ui.popup.list.PopupListElementRenderer -import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PackageViewDescriptor @@ -42,8 +42,10 @@ import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.completion.KotlinStatisticsInfo +import org.jetbrains.kotlin.idea.completion.isDeprecatedAtCallSite import org.jetbrains.kotlin.idea.core.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors @@ -69,7 +71,7 @@ internal fun createSingleImportAction( val prioritizer = Prioritizer(element.containingKtFile) val variants = fqNames.mapNotNull { fqName -> val sameFqNameDescriptors = file.resolveImportReference(fqName) - val priority = sameFqNameDescriptors.map { prioritizer.priority(it) }.min() ?: return@mapNotNull null + val priority = sameFqNameDescriptors.map { prioritizer.priority(it, file.languageVersionSettings) }.min() ?: return@mapNotNull null Prioritizer.VariantWithPriority(SingleImportVariant(fqName, sameFqNameDescriptors), priority) }.sortedBy { it.priority }.map { it.variant } @@ -89,7 +91,8 @@ internal fun createSingleImportActionForConstructor( .filterIsInstance() .flatMap { it.constructors } - val priority = sameFqNameDescriptors.asSequence().map { prioritizer.priority(it) }.min() ?: return@mapNotNull null + val priority = + sameFqNameDescriptors.asSequence().map { prioritizer.priority(it, file.languageVersionSettings) }.min() ?: return@mapNotNull null Prioritizer.VariantWithPriority(SingleImportVariant(fqName, sameFqNameDescriptors), priority) }.sortedBy { it.priority }.map { it.variant } return KotlinAddImportAction(project, editor, element, variants) @@ -116,7 +119,7 @@ internal fun createGroupedImportsAction( SingleImportVariant(samePackageFqNames.first(), descriptors) } - val priority = prioritizer.priority(descriptors) + val priority = prioritizer.priority(descriptors, file.languageVersionSettings) DescriptorGroupPrioritizer.VariantWithPriority(variant, priority) } .sortedBy { @@ -272,8 +275,8 @@ private class Prioritizer(private val file: KtFile, private val compareNames: Bo private val classifier = ImportableFqNameClassifier(file) private val proximityComparator = PsiProximityComparator(file) - inner class Priority(descriptor: DeclarationDescriptor) : Comparable { - private val isDeprecated = KotlinBuiltIns.isDeprecated(descriptor) + inner class Priority(descriptor: DeclarationDescriptor, languageVersionSettings: LanguageVersionSettings) : Comparable { + private val isDeprecated = isDeprecatedAtCallSite(descriptor, languageVersionSettings) private val fqName = descriptor.importableFqName!! private val classification = classifier.classify(fqName, false) private val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) @@ -297,7 +300,8 @@ private class Prioritizer(private val file: KtFile, private val compareNames: Bo } } - fun priority(descriptor: DeclarationDescriptor) = Priority(descriptor) + fun priority(descriptor: DeclarationDescriptor, languageVersionSettings: LanguageVersionSettings) = + Priority(descriptor, languageVersionSettings) data class VariantWithPriority(val variant: AutoImportVariant, val priority: Priority) } @@ -305,8 +309,11 @@ private class Prioritizer(private val file: KtFile, private val compareNames: Bo private class DescriptorGroupPrioritizer(file: KtFile) { private val prioritizer = Prioritizer(file, false) - inner class Priority(val descriptors: List) : Comparable { - val ownDescriptorsPriority = descriptors.asSequence().map { prioritizer.priority(it) }.max()!! + inner class Priority( + val descriptors: List, + languageVersionSettings: LanguageVersionSettings + ) : Comparable { + val ownDescriptorsPriority = descriptors.asSequence().map { prioritizer.priority(it, languageVersionSettings) }.max()!! override fun compareTo(other: Priority): Int { val c1 = ownDescriptorsPriority.compareTo(other.ownDescriptorsPriority) @@ -316,7 +323,8 @@ private class DescriptorGroupPrioritizer(file: KtFile) { } } - fun priority(descriptors: List) = Priority(descriptors) + fun priority(descriptors: List, languageVersionSettings: LanguageVersionSettings) = + Priority(descriptors, languageVersionSettings) data class VariantWithPriority(val variant: AutoImportVariant, val priority: Priority) } diff --git a/idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceApplicable.test b/idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceApplicable.test new file mode 100644 index 00000000000..b6a8bde4704 --- /dev/null +++ b/idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceApplicable.test @@ -0,0 +1,50 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Destructuring declaration initializer of type Some must have a 'component1()' function + +package testing + +import aaa.Some + +fun testing() { + val (a) = Some() +} +//----------------------- + + +// FILE: second.kt + +package aaa + +public class Some + +@Deprecated("Bad, use from package other") +@DeprecatedSinceKotlin(warningSince = "1.0") +operator fun Some.component1() = 1 +//----------------------- + +// FILE: other_second.kt + +package other + +import aaa.Some + +operator fun Some.component1() = 1 +//----------------------- + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Destructuring declaration initializer of type Some must have a 'component1()' function + +package testing + +import aaa.Some +import other.component1 + +fun testing() { + val (a) = Some() +} +//----------------------- + + diff --git a/idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceNotApplicable.test b/idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceNotApplicable.test new file mode 100644 index 00000000000..01ad0d6625d --- /dev/null +++ b/idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceNotApplicable.test @@ -0,0 +1,50 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Destructuring declaration initializer of type Some must have a 'component1()' function + +package testing + +import aaa.Some + +fun testing() { + val (a) = Some() +} +//----------------------- + + +// FILE: second.kt + +package aaa + +public class Some + +@Deprecated("Good") +@DeprecatedSinceKotlin(warningSince = "999.999") +operator fun Some.component1() = 1 +//----------------------- + +// FILE: other_second.kt + +package other + +import aaa.Some + +operator fun Some.component1() = 1 +//----------------------- + + +// FILE: first.after.kt +// "Import" "true" +// ERROR: Destructuring declaration initializer of type Some must have a 'component1()' function + +package testing + +import aaa.Some +import aaa.component1 + +fun testing() { + val (a) = Some() +} +//----------------------- + + diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 607d7243e97..091eb3ddf94 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -641,6 +641,16 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes runTest("idea/testData/quickfix/autoImports/extensionFunctionImportImplicitReceiver.before.Main.kt"); } + @TestMetadata("extensionPreferDeprecatedSinceApplicable.test") + public void testExtensionPreferDeprecatedSinceApplicable() throws Exception { + runTest("idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceApplicable.test"); + } + + @TestMetadata("extensionPreferDeprecatedSinceNotApplicable.test") + public void testExtensionPreferDeprecatedSinceNotApplicable() throws Exception { + runTest("idea/testData/quickfix/autoImports/extensionPreferDeprecatedSinceNotApplicable.test"); + } + @TestMetadata("extensionPropertyImport.before.Main.kt") public void testExtensionPropertyImport() throws Exception { runTest("idea/testData/quickfix/autoImports/extensionPropertyImport.before.Main.kt");