From c6391f929b603313fbdd401f2d6e4e611b097684 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Mon, 29 Jul 2024 17:27:46 +0200 Subject: [PATCH] KTIJ-25346 [kotlin] Handle typealiased constructors in K2 Import Optimizer Currently, due to KTIJ-26098, if the constructor is invoked via the typealias, the reference resolves directly to the constructed class, and not to the typealias. This prevented `UsedReferencesCollector` from properly recognizing such references. To handle this, we resolve the type explicitly when we see constructor calls by using code fragments. This works because type references work fine with typealiases (compared to constructor references). Also, add an explicit test for currently incorrect optimization of `kotlin.concurrent.Volatile` import. ^KTIJ-25346 Fixed GitOrigin-RevId: f531c00cba6d7e6687a45ae06aa9ac85a92262a3 --- .../imports/UsedReferencesCollector.kt | 37 ++++++++++++++++++- .../FirJvmOptimizeImportsTestGenerated.java | 20 ++++++++++ .../JsOptimizeImportsTestGenerated.java | 15 ++++++++ .../JvmOptimizeImportsTestGenerated.java | 20 ++++++++++ .../TypeAliasedConstructor.dependency.kt | 5 +++ .../common/TypeAliasedConstructor.kt | 8 ++++ .../common/TypeAliasedConstructor.kt.after | 7 ++++ ...liasedConstructor_annotation.dependency.kt | 5 +++ .../TypeAliasedConstructor_annotation.kt | 7 ++++ ...TypeAliasedConstructor_annotation.kt.after | 6 +++ ...AliasedConstructor_sameName.dependency1.kt | 3 ++ ...AliasedConstructor_sameName.dependency2.kt | 3 ++ .../common/TypeAliasedConstructor_sameName.kt | 8 ++++ .../TypeAliasedConstructor_sameName.kt.after | 7 ++++ .../TypeAliasedConstructor_sameName.kt.log | 3 ++ ...eAliasedConstructor_annotation_volatile.kt | 9 +++++ ...edConstructor_annotation_volatile.kt.after | 9 +++++ 17 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.dependency.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.dependency.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency1.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency2.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.after create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.log create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt.after diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/imports/UsedReferencesCollector.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/imports/UsedReferencesCollector.kt index 7d82426417e7..373397478dc7 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/imports/UsedReferencesCollector.kt +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/imports/UsedReferencesCollector.kt @@ -7,6 +7,8 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.analysis.api.KaSession import org.jetbrains.kotlin.analysis.api.resolution.* import org.jetbrains.kotlin.analysis.api.symbols.* +import org.jetbrains.kotlin.analysis.api.types.KaType +import org.jetbrains.kotlin.analysis.api.types.symbol import org.jetbrains.kotlin.idea.references.KDocReference import org.jetbrains.kotlin.idea.references.KtInvokeFunctionReference import org.jetbrains.kotlin.idea.references.KtReference @@ -123,7 +125,11 @@ internal class UsedReferencesCollector(private val file: KtFile) { (target as? KaNamedClassSymbol)?.containingSymbol } - target is KaConstructorSymbol -> target.containingSymbol + target is KaConstructorSymbol -> { + val targetClass = target.containingSymbol as? KaClassLikeSymbol + + targetClass?.let { resolveTypeAliasedConstructorReference(reference, it) } ?: targetClass + } else -> target } @@ -160,6 +166,35 @@ internal class UsedReferencesCollector(private val file: KtFile) { } } +/** + * Takes a [reference] pointing to a typealiased constructor call like `FooAlias()`, + * and [expandedClassSymbol] pointing to the expanded class `Foo`. + * + * Returns a `FooAlias` typealias symbol if it is resolvable at this position, and `null` otherwise. + * + * This is a workaround function until KTIJ-26098 is fixed. + */ +private fun KaSession.resolveTypeAliasedConstructorReference( + reference: KtReference, + expandedClassSymbol: KaClassLikeSymbol, +): KaClassLikeSymbol? { + val referencedType = resolveReferencedType(reference) ?: return null + if (referencedType.symbol != expandedClassSymbol) return null + + val typealiasType = referencedType.abbreviation ?: return null + + return typealiasType.symbol +} + +private fun KaSession.resolveReferencedType(reference: KtReference): KaType? { + val originalReferenceName = reference.resolvesByNames.singleOrNull() ?: return null + + val psiFactory = KtPsiFactory.contextual(reference.element) + val psiType = psiFactory.createTypeCodeFragment(originalReferenceName.asString(), context = reference.element).getContentElement() + + return psiType?.type +} + private fun collectImportAliases(file: KtFile): Map> = if (file.hasImportAlias()) { file.importDirectives .asSequence() diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/imports/FirJvmOptimizeImportsTestGenerated.java b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/imports/FirJvmOptimizeImportsTestGenerated.java index c49572468408..2ee01278c2b1 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/imports/FirJvmOptimizeImportsTestGenerated.java +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/imports/FirJvmOptimizeImportsTestGenerated.java @@ -284,6 +284,11 @@ public abstract class FirJvmOptimizeImportsTestGenerated extends AbstractFirJvmO runTest("../../idea/tests/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt"); } + @TestMetadata("TypeAliasedConstructor_annotation_volatile.kt") + public void testTypeAliasedConstructor_annotation_volatile() throws Exception { + runTest("../../idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt"); + } + @TestMetadata("UnusedImports.kt") public void testUnusedImports() throws Exception { runTest("../../idea/tests/testData/editor/optimizeImports/jvm/UnusedImports.kt"); @@ -779,6 +784,21 @@ public abstract class FirJvmOptimizeImportsTestGenerated extends AbstractFirJvmO runTest("../../idea/tests/testData/editor/optimizeImports/common/TwoConstructors.kt"); } + @TestMetadata("TypeAliasedConstructor.kt") + public void testTypeAliasedConstructor() throws Exception { + runTest("../../idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt"); + } + + @TestMetadata("TypeAliasedConstructor_annotation.kt") + public void testTypeAliasedConstructor_annotation() throws Exception { + runTest("../../idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt"); + } + + @TestMetadata("TypeAliasedConstructor_sameName.kt") + public void testTypeAliasedConstructor_sameName() throws Exception { + runTest("../../idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt"); + } + @TestMetadata("UnresolvedImport.kt") public void testUnresolvedImport() throws Exception { runTest("../../idea/tests/testData/editor/optimizeImports/common/UnresolvedImport.kt"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java index 61b4509377d4..392ad88e4e80 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java @@ -521,6 +521,21 @@ public abstract class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeI runTest("testData/editor/optimizeImports/common/TwoConstructors.kt"); } + @TestMetadata("TypeAliasedConstructor.kt") + public void testTypeAliasedConstructor() throws Exception { + runTest("testData/editor/optimizeImports/common/TypeAliasedConstructor.kt"); + } + + @TestMetadata("TypeAliasedConstructor_annotation.kt") + public void testTypeAliasedConstructor_annotation() throws Exception { + runTest("testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt"); + } + + @TestMetadata("TypeAliasedConstructor_sameName.kt") + public void testTypeAliasedConstructor_sameName() throws Exception { + runTest("testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt"); + } + @TestMetadata("UnresolvedImport.kt") public void testUnresolvedImport() throws Exception { runTest("testData/editor/optimizeImports/common/UnresolvedImport.kt"); diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java index 2ae010ad5cbe..88a6ce0c5fc2 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java @@ -284,6 +284,11 @@ public abstract class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimiz runTest("testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt"); } + @TestMetadata("TypeAliasedConstructor_annotation_volatile.kt") + public void testTypeAliasedConstructor_annotation_volatile() throws Exception { + runTest("testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt"); + } + @TestMetadata("UnusedImports.kt") public void testUnusedImports() throws Exception { runTest("testData/editor/optimizeImports/jvm/UnusedImports.kt"); @@ -784,6 +789,21 @@ public abstract class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimiz runTest("testData/editor/optimizeImports/common/TwoConstructors.kt"); } + @TestMetadata("TypeAliasedConstructor.kt") + public void testTypeAliasedConstructor() throws Exception { + runTest("testData/editor/optimizeImports/common/TypeAliasedConstructor.kt"); + } + + @TestMetadata("TypeAliasedConstructor_annotation.kt") + public void testTypeAliasedConstructor_annotation() throws Exception { + runTest("testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt"); + } + + @TestMetadata("TypeAliasedConstructor_sameName.kt") + public void testTypeAliasedConstructor_sameName() throws Exception { + runTest("testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt"); + } + @TestMetadata("UnresolvedImport.kt") public void testUnresolvedImport() throws Exception { runTest("testData/editor/optimizeImports/common/UnresolvedImport.kt"); diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.dependency.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.dependency.kt new file mode 100644 index 000000000000..672ad5323edd --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.dependency.kt @@ -0,0 +1,5 @@ +package dependency + +class Foo + +typealias TypeAliasedFoo = Foo \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt new file mode 100644 index 000000000000..08fc90ee6ccf --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt @@ -0,0 +1,8 @@ +package test + +import dependency.Foo +import dependency.TypeAliasedFoo + +fun usage() { + TypeAliasedFoo() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt.after b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt.after new file mode 100644 index 000000000000..824b31d3b378 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor.kt.after @@ -0,0 +1,7 @@ +package test + +import dependency.TypeAliasedFoo + +fun usage() { + TypeAliasedFoo() +} diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.dependency.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.dependency.kt new file mode 100644 index 000000000000..2c94d5a5face --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.dependency.kt @@ -0,0 +1,5 @@ +package dependency + +annotation class Foo + +typealias TypeAliasedFoo = Foo \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt new file mode 100644 index 000000000000..49c7769e1c63 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt @@ -0,0 +1,7 @@ +package test + +import dependency.Foo +import dependency.TypeAliasedFoo + +@TypeAliasedFoo +fun usage() {} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt.after b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt.after new file mode 100644 index 000000000000..2a0031f788e0 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_annotation.kt.after @@ -0,0 +1,6 @@ +package test + +import dependency.TypeAliasedFoo + +@TypeAliasedFoo +fun usage() {} diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency1.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency1.kt new file mode 100644 index 000000000000..25e403690ec6 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency1.kt @@ -0,0 +1,3 @@ +package dependency1 + +typealias Foo = dependency2.Foo \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency2.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency2.kt new file mode 100644 index 000000000000..ec735f892dcd --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.dependency2.kt @@ -0,0 +1,3 @@ +package dependency2 + +class Foo diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt new file mode 100644 index 000000000000..30e7d2a96329 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt @@ -0,0 +1,8 @@ +package test + +import dependency1.Foo +import dependency2.* + +fun usage() { + Foo() +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.after b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.after new file mode 100644 index 000000000000..7f53ba5c6516 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.after @@ -0,0 +1,7 @@ +package test + +import dependency1.Foo + +fun usage() { + Foo() +} diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.log b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.log new file mode 100644 index 000000000000..8e3ac2a60e64 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/common/TypeAliasedConstructor_sameName.kt.log @@ -0,0 +1,3 @@ +Additional checking of reference Getter: Foo +Additional checking of reference KtSimpleNameReference: Foo +Additional checking of reference KtInvokeFunctionReference: Foo() diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt new file mode 100644 index 000000000000..b332e93b7b96 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt @@ -0,0 +1,9 @@ +// IGNORE_K2 +package test + +import kotlin.concurrent.Volatile + +class Foo { + @Volatile + var property: Int = 10 +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt.after b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt.after new file mode 100644 index 000000000000..d62a7a534fd7 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/optimizeImports/jvm/TypeAliasedConstructor_annotation_volatile.kt.after @@ -0,0 +1,9 @@ +// IGNORE_K2 +package test + +import kotlin.concurrent.Volatile + +class Foo { + @Volatile + var property: Int = 10 +}