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
This commit is contained in:
Roman Golyshev
2024-07-29 17:27:46 +02:00
committed by intellij-monorepo-bot
parent 03019cbc52
commit c6391f929b
17 changed files with 171 additions and 1 deletions

View File

@@ -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<FqName, List<Name>> = if (file.hasImportAlias()) {
file.importDirectives
.asSequence()

View File

@@ -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");

View File

@@ -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");

View File

@@ -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");

View File

@@ -0,0 +1,5 @@
package dependency
class Foo
typealias TypeAliasedFoo = Foo

View File

@@ -0,0 +1,8 @@
package test
import dependency.Foo
import dependency.TypeAliasedFoo
fun usage() {
TypeAliasedFoo()
}

View File

@@ -0,0 +1,7 @@
package test
import dependency.TypeAliasedFoo
fun usage() {
TypeAliasedFoo()
}

View File

@@ -0,0 +1,5 @@
package dependency
annotation class Foo
typealias TypeAliasedFoo = Foo

View File

@@ -0,0 +1,7 @@
package test
import dependency.Foo
import dependency.TypeAliasedFoo
@TypeAliasedFoo
fun usage() {}

View File

@@ -0,0 +1,6 @@
package test
import dependency.TypeAliasedFoo
@TypeAliasedFoo
fun usage() {}

View File

@@ -0,0 +1,3 @@
package dependency1
typealias Foo = dependency2.Foo

View File

@@ -0,0 +1,8 @@
package test
import dependency1.Foo
import dependency2.*
fun usage() {
Foo()
}

View File

@@ -0,0 +1,7 @@
package test
import dependency1.Foo
fun usage() {
Foo()
}

View File

@@ -0,0 +1,3 @@
Additional checking of reference Getter: Foo
Additional checking of reference KtSimpleNameReference: Foo
Additional checking of reference KtInvokeFunctionReference: Foo()

View File

@@ -0,0 +1,9 @@
// IGNORE_K2
package test
import kotlin.concurrent.Volatile
class Foo {
@Volatile
var property: Int = 10
}

View File

@@ -0,0 +1,9 @@
// IGNORE_K2
package test
import kotlin.concurrent.Volatile
class Foo {
@Volatile
var property: Int = 10
}