K2: Update reference shortener to handle import alias

The existing reference shortener does not use import alias when it
shortens a symbol. Instead, it adds a new import directive for the
symbol that is already imported. This commit updates reference shortener
to let it reuse the existing import alias rather than adding a new one:

 1. When shortening a symbol, check whether the symbol is already
    imported.
 2. If it is already imported by an import alias, keep the symbol
    reference expression and the import alias as a string together in
    `ShortenCommand`.

The actual PSI update (shortening) based on the ShortenCommand is done
by IntelliJ.

^KTIJ-27205
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ReferenceShortener.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ReferenceShortener.kt
index 85271b8..3a002fd 100644
--- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ReferenceShortener.kt
+++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10ReferenceShortener.kt
@@ -8,10 +8,7 @@
 import com.intellij.openapi.util.TextRange
 import com.intellij.psi.SmartPointerManager
 import com.intellij.psi.SmartPsiElementPointer
-import org.jetbrains.kotlin.analysis.api.components.KtReferenceShortener
-import org.jetbrains.kotlin.analysis.api.components.ShortenCommand
-import org.jetbrains.kotlin.analysis.api.components.ShortenOptions
-import org.jetbrains.kotlin.analysis.api.components.ShortenStrategy
+import org.jetbrains.kotlin.analysis.api.components.*
 import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession
 import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent
 import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
@@ -19,9 +16,7 @@
 import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
 import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
 import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
 import org.jetbrains.kotlin.psi.KtFile
-import org.jetbrains.kotlin.psi.KtUserType
 
 internal class KtFe10ReferenceShortener(
     override val analysisSession: KtFe10AnalysisSession,
@@ -44,8 +39,8 @@
             override val targetFile: SmartPsiElementPointer<KtFile> get() = ktFilePointer
             override val importsToAdd: Set<FqName> get() = emptySet()
             override val starImportsToAdd: Set<FqName> get() = emptySet()
-            override val typesToShorten: List<SmartPsiElementPointer<KtUserType>> get() = emptyList()
-            override val qualifiersToShorten: List<SmartPsiElementPointer<KtDotQualifiedExpression>> get() = emptyList()
+            override val listOfTypeToShortenInfo: List<TypeToShortenInfo> get() = emptyList()
+            override val listOfQualifierToShortenInfo: List<QualifierToShortenInfo> get() = emptyList()
             override val kDocQualifiersToShorten: List<SmartPsiElementPointer<KDocName>> get() = emptyList()
 
             override val isEmpty: Boolean get() = true
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt
index 8e7b450..998887f 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirReferenceShortener.kt
@@ -10,10 +10,7 @@
 import com.intellij.psi.PsiFile
 import com.intellij.psi.SmartPsiElementPointer
 import org.jetbrains.kotlin.KtFakeSourceElementKind
-import org.jetbrains.kotlin.analysis.api.components.KtReferenceShortener
-import org.jetbrains.kotlin.analysis.api.components.ShortenCommand
-import org.jetbrains.kotlin.analysis.api.components.ShortenOptions
-import org.jetbrains.kotlin.analysis.api.components.ShortenStrategy
+import org.jetbrains.kotlin.analysis.api.components.*
 import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
 import org.jetbrains.kotlin.analysis.api.fir.components.ElementsToShortenCollector.PartialOrderOfScope.Companion.toPartialOrder
 import org.jetbrains.kotlin.analysis.api.fir.isImplicitDispatchReceiver
@@ -92,8 +89,8 @@
             file.createSmartPointer(),
             importsToAdd = emptySet(),
             starImportsToAdd = emptySet(),
-            typesToShorten = emptyList(),
-            qualifiersToShorten = emptyList(),
+            listOfTypeToShortenInfo = emptyList(),
+            listOfQualifierToShortenInfo = emptyList(),
             kDocQualifiersToShorten = emptyList(),
         )
 
@@ -134,9 +131,10 @@
             file.createSmartPointer(),
             additionalImports.simpleImports,
             additionalImports.starImports,
-            collector.typesToShorten.map { it.element }.distinct().map { it.createSmartPointer() },
-            collector.qualifiersToShorten.map { it.element }.distinct().map { it.createSmartPointer() },
-            kDocCollector.kDocQualifiersToShorten.map { it.element }.distinct().map { it.createSmartPointer() },
+            collector.typesToShorten.distinctBy { it.element }.map { TypeToShortenInfo(it.element.createSmartPointer(), it.shortenedRef) },
+            collector.qualifiersToShorten.distinctBy { it.element }
+                .map { QualifierToShortenInfo(it.element.createSmartPointer(), it.shortenedRef) },
+            kDocCollector.kDocQualifiersToShorten.distinctBy { it.element }.map { it.element.createSmartPointer() },
         )
     }
 
@@ -388,12 +386,14 @@
 
 private class ShortenType(
     val element: KtUserType,
+    val shortenedRef: String? = null,
     override val nameToImport: FqName? = null,
     override val importAllInParent: Boolean = false,
 ) : ElementToShorten()
 
 private class ShortenQualifier(
     val element: KtDotQualifiedExpression,
+    val shortenedRef: String? = null,
     override val nameToImport: FqName? = null,
     override val importAllInParent: Boolean = false
 ) : ElementToShorten()
@@ -774,6 +774,19 @@
         return !element.containingFile.hasImportDirectiveForDifferentSymbolWithSameName(classId)
     }
 
+    private fun shortenIfAlreadyImportedAsAlias(referenceExpression: KtElement, referencedSymbolFqName: FqName): ElementToShorten? {
+        val importDirectiveForReferencedSymbol = referenceExpression.containingKtFile.importDirectives.firstOrNull {
+            it.importedFqName == referencedSymbolFqName && it.alias != null
+        } ?: return null
+        return when (referenceExpression) {
+            is KtUserType -> ShortenType(referenceExpression, shortenedRef = importDirectiveForReferencedSymbol.alias?.name)
+            is KtDotQualifiedExpression -> ShortenQualifier(
+                referenceExpression, shortenedRef = importDirectiveForReferencedSymbol.alias?.name
+            )
+            else -> error("Unexpected ${referenceExpression::class}")
+        }
+    }
+
     private fun findClassifierElementsToShorten(
         positionScopes: List<FirScope>,
         allClassIds: Sequence<ClassId>,
@@ -787,6 +800,8 @@
             // If its parent has a type parameter, we do not shorten it ATM because it will lose its type parameter. See KTIJ-26072
             if (classSymbol.hasTypeParameterFromParent()) continue
 
+            shortenIfAlreadyImportedAsAlias(element, classId.asSingleFqName())?.let { return it }
+
             if (shortenClassifierIfAlreadyImported(classId, element, classSymbol, positionScopes)) {
                 return createElementToShorten(element, null, false)
             }
@@ -829,8 +844,8 @@
 
     private fun createElementToShorten(element: KtElement, nameToImport: FqName?, importAllInParent: Boolean): ElementToShorten {
         return when (element) {
-            is KtUserType -> ShortenType(element, nameToImport, importAllInParent)
-            is KtDotQualifiedExpression -> ShortenQualifier(element, nameToImport, importAllInParent)
+            is KtUserType -> ShortenType(element, shortenedRef = null, nameToImport, importAllInParent)
+            is KtDotQualifiedExpression -> ShortenQualifier(element, shortenedRef = null, nameToImport, importAllInParent)
             else -> error("Unexpected ${element::class}")
         }
     }
@@ -1039,6 +1054,11 @@
         val option = callableShortenStrategy(propertySymbol)
         if (option == ShortenStrategy.DO_NOT_SHORTEN) return
 
+        shortenIfAlreadyImportedAsAlias(qualifiedProperty, propertySymbol.callableId.asSingleFqName())?.let {
+            addElementToShorten(it)
+            return
+        }
+
         val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, getNamesToImport(), towerContextProvider) ?: return
         val availableCallables = shorteningContext.findPropertiesInScopes(scopes, propertySymbol.name)
         if (availableCallables.isNotEmpty() && shortenIfAlreadyImported(firPropertyAccess, propertySymbol, qualifiedProperty)) {
@@ -1085,6 +1105,11 @@
         val option = callableShortenStrategy(calledSymbol)
         if (option == ShortenStrategy.DO_NOT_SHORTEN) return
 
+        shortenIfAlreadyImportedAsAlias(qualifiedCallExpression, calledSymbol.callableId.asSingleFqName())?.let {
+            addElementToShorten(it)
+            return
+        }
+
         val scopes = shorteningContext.findScopesAtPosition(callExpression, getNamesToImport(), towerContextProvider) ?: return
         val availableCallables = shorteningContext.findFunctionsInScopes(scopes, calledSymbol.name)
         if (availableCallables.isNotEmpty() && shortenIfAlreadyImported(functionCall, calledSymbol, callExpression)) {
@@ -1123,13 +1148,14 @@
                         if (nameToImport == null || option == ShortenStrategy.SHORTEN_IF_ALREADY_IMPORTED) return
                         ShortenQualifier(
                             qualifiedCallExpression,
+                            shortenedRef = null,
                             nameToImport,
                             importAllInParent = option == ShortenStrategy.SHORTEN_AND_STAR_IMPORT
                         )
                     }
                     // Respect caller's request to star import this symbol.
                     matchedCallables.any { it.importKind == ImportKind.EXPLICIT } && option == ShortenStrategy.SHORTEN_AND_STAR_IMPORT ->
-                        ShortenQualifier(qualifiedCallExpression, nameToImport, importAllInParent = true)
+                        ShortenQualifier(qualifiedCallExpression, null, nameToImport, importAllInParent = true)
                     else -> ShortenQualifier(qualifiedCallExpression)
                 }
             }
@@ -1201,13 +1227,17 @@
         }
     }
 
-    private fun addElementToShorten(element: KtElement, nameToImport: FqName?, isImportWithStar: Boolean) {
+    private fun addElementToShorten(element: KtElement, shortenedRef: String?, nameToImport: FqName?, isImportWithStar: Boolean) {
         val qualifier = element.getQualifier() ?: return
         if (!qualifier.isAlreadyCollected()) {
             removeRedundantElements(qualifier)
             when (element) {
-                is KtUserType -> typesToShorten.add(ShortenType(element, nameToImport, isImportWithStar))
-                is KtDotQualifiedExpression -> qualifiersToShorten.add(ShortenQualifier(element, nameToImport, isImportWithStar))
+                is KtUserType -> typesToShorten.add(ShortenType(element, shortenedRef, nameToImport, isImportWithStar))
+                is KtDotQualifiedExpression -> qualifiersToShorten.add(
+                    ShortenQualifier(
+                        element, shortenedRef, nameToImport, isImportWithStar
+                    )
+                )
             }
         }
     }
@@ -1219,9 +1249,15 @@
             elementInfoToShorten.nameToImport to false
         }
         when (elementInfoToShorten) {
-            is ShortenType -> addElementToShorten(elementInfoToShorten.element, nameToImport, isImportWithStar)
-            is ShortenQualifier -> addElementToShorten(elementInfoToShorten.element, nameToImport, isImportWithStar)
-            is ShortenKDocQualifier -> addElementToShorten(elementInfoToShorten.element, nameToImport, isImportWithStar)
+            is ShortenType -> addElementToShorten(
+                elementInfoToShorten.element, elementInfoToShorten.shortenedRef, nameToImport, isImportWithStar
+            )
+            is ShortenQualifier -> addElementToShorten(
+                elementInfoToShorten.element, elementInfoToShorten.shortenedRef, nameToImport, isImportWithStar
+            )
+            is ShortenKDocQualifier -> addElementToShorten(
+                elementInfoToShorten.element, shortenedRef = null, nameToImport, isImportWithStar
+            )
         }
     }
 
@@ -1366,8 +1402,8 @@
     override val targetFile: SmartPsiElementPointer<KtFile>,
     override val importsToAdd: Set<FqName>,
     override val starImportsToAdd: Set<FqName>,
-    override val typesToShorten: List<SmartPsiElementPointer<KtUserType>>,
-    override val qualifiersToShorten: List<SmartPsiElementPointer<KtDotQualifiedExpression>>,
+    override val listOfTypeToShortenInfo: List<TypeToShortenInfo>,
+    override val listOfQualifierToShortenInfo: List<QualifierToShortenInfo>,
     override val kDocQualifiersToShorten: List<SmartPsiElementPointer<KDocName>>,
 ) : ShortenCommand
 
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
index 9b09e01..254416b 100644
--- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
+++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
@@ -275,6 +275,36 @@
     }
 
     @Test
+    @TestMetadata("importAliasAndStarImport.kt")
+    public void testImportAliasAndStarImport() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForFunction.kt")
+    public void testImportAliasForFunction() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForProperty.kt")
+    public void testImportAliasForProperty() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForType.kt")
+    public void testImportAliasForType() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForTypeQualifier.kt")
+    public void testImportAliasForTypeQualifier() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.kt");
+    }
+
+    @Test
     @TestMetadata("kdoc.kt")
     public void testKdoc() throws Exception {
         runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdoc.kt");
@@ -311,6 +341,18 @@
     }
 
     @Test
+    @TestMetadata("multipleImportAlias.kt")
+    public void testMultipleImportAlias() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.kt");
+    }
+
+    @Test
+    @TestMetadata("multipleImportAlias2.kt")
+    public void testMultipleImportAlias2() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.kt");
+    }
+
+    @Test
     @TestMetadata("nestedClass.kt")
     public void testNestedClass() throws Exception {
         runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt");
@@ -491,6 +533,12 @@
     }
 
     @Test
+    @TestMetadata("starImport.kt")
+    public void testStarImport() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.kt");
+    }
+
+    @Test
     @TestMetadata("staticMethodFromBaseClassConflict.kt")
     public void testStaticMethodFromBaseClassConflict() throws Exception {
         runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/staticMethodFromBaseClassConflict.kt");
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceShortenerTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceShortenerTest.kt
index dde180d..d561c2e 100644
--- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceShortenerTest.kt
+++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceShortenerTest.kt
@@ -23,6 +23,7 @@
  * Note that it tests shortening only a single expression between <expr> and </expr> in the first file.
  */
 abstract class AbstractReferenceShortenerTest : AbstractAnalysisApiBasedSingleModuleTest() {
+
     override fun doTestByFileStructure(ktFiles: List<KtFile>, module: TestModule, testServices: TestServices) {
         val element = testServices.expressionMarkerProvider.getSelectedElementOfType<KtElement>(ktFiles.first())
 
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/ShorteningResultsRenderer.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/ShorteningResultsRenderer.kt
index 5372ce8..3833efe 100644
--- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/ShorteningResultsRenderer.kt
+++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/ShorteningResultsRenderer.kt
@@ -14,14 +14,14 @@
             return
         }
 
-        shortening.typesToShorten.forEach { userType ->
+        shortening.listOfTypeToShortenInfo.forEach { (userType, shortenedRef) ->
             userType.element?.text?.let {
-                appendLine("[type] $it")
+                appendLine("[type] $it${shortenedRef?.let { ref -> " -> $ref" } ?: ""}")
             }
         }
-        shortening.qualifiersToShorten.forEach { qualifier ->
+        shortening.listOfQualifierToShortenInfo.forEach { (qualifier, shortenedRef) ->
             qualifier.element?.text?.let {
-                appendLine("[qualifier] $it")
+                appendLine("[qualifier] $it${shortenedRef?.let { ref -> " -> $ref" } ?: ""}")
             }
         }
         shortening.kDocQualifiersToShorten.forEach { kdoc ->
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
index 627ae59..58b8607 100644
--- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
@@ -275,6 +275,36 @@
     }
 
     @Test
+    @TestMetadata("importAliasAndStarImport.kt")
+    public void testImportAliasAndStarImport() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForFunction.kt")
+    public void testImportAliasForFunction() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForProperty.kt")
+    public void testImportAliasForProperty() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForType.kt")
+    public void testImportAliasForType() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.kt");
+    }
+
+    @Test
+    @TestMetadata("importAliasForTypeQualifier.kt")
+    public void testImportAliasForTypeQualifier() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.kt");
+    }
+
+    @Test
     @TestMetadata("kdoc.kt")
     public void testKdoc() throws Exception {
         runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/kdoc.kt");
@@ -311,6 +341,18 @@
     }
 
     @Test
+    @TestMetadata("multipleImportAlias.kt")
+    public void testMultipleImportAlias() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.kt");
+    }
+
+    @Test
+    @TestMetadata("multipleImportAlias2.kt")
+    public void testMultipleImportAlias2() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.kt");
+    }
+
+    @Test
     @TestMetadata("nestedClass.kt")
     public void testNestedClass() throws Exception {
         runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt");
@@ -491,6 +533,12 @@
     }
 
     @Test
+    @TestMetadata("starImport.kt")
+    public void testStarImport() throws Exception {
+        runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.kt");
+    }
+
+    @Test
     @TestMetadata("staticMethodFromBaseClassConflict.kt")
     public void testStaticMethodFromBaseClassConflict() throws Exception {
         runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/staticMethodFromBaseClassConflict.kt");
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtReferenceShortener.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtReferenceShortener.kt
index 59ba609..d5a36d2 100644
--- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtReferenceShortener.kt
+++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/components/KtReferenceShortener.kt
@@ -152,14 +152,41 @@
         }
 }
 
+/**
+ * A class to keep a [KtUserType] to shorten and what shape the shortened result has to be. [shortenedReference] is the expected result of
+ * shortening in a string form. If [shortenedReference] is null, it means the shortening will simply delete the qualifier. Note that
+ * currently the only usage of [shortenedReference] is the case we have the import-alias. For example, [shortenedReference] will be
+ * "AliasType" when we shorten:
+ * ```
+ * import my.package.NewType as AliasType
+ * ... my.package.Ne<caret>wType ... // -> we can replace this with `AliasType`.
+ * ```
+ */
+public data class TypeToShortenInfo(val typeToShorten: SmartPsiElementPointer<KtUserType>, val shortenedReference: String?)
+
+/**
+ * A class to keep a [KtDotQualifiedExpression] to shorten and what shape the shortened result has to be. [shortenedReference] is the
+ * expected result of shortening in a string form. If [shortenedReference] is null, it means the shortening will simply delete the
+ * qualifier. Note that currently the only usage of [shortenedReference] is the case we have the import-alias. For example,
+ * [shortenedReference] will be "bar" when we shorten:
+ * ```
+ * import my.package.foo as bar
+ * ... my.package.fo<caret>o ... // -> we can replace this with `bar`.
+ * ```
+ */
+public data class QualifierToShortenInfo(
+    val qualifierToShorten: SmartPsiElementPointer<KtDotQualifiedExpression>,
+    val shortenedReference: String?,
+)
+
 public interface ShortenCommand {
     public val targetFile: SmartPsiElementPointer<KtFile>
     public val importsToAdd: Set<FqName>
     public val starImportsToAdd: Set<FqName>
-    public val typesToShorten: List<SmartPsiElementPointer<KtUserType>>
-    public val qualifiersToShorten: List<SmartPsiElementPointer<KtDotQualifiedExpression>>
+    public val listOfTypeToShortenInfo: List<TypeToShortenInfo>
+    public val listOfQualifierToShortenInfo: List<QualifierToShortenInfo>
     public val kDocQualifiersToShorten: List<SmartPsiElementPointer<KDocName>>
 
     public val isEmpty: Boolean
-        get() = typesToShorten.isEmpty() && qualifiersToShorten.isEmpty() && kDocQualifiersToShorten.isEmpty()
+        get() = listOfTypeToShortenInfo.isEmpty() && listOfQualifierToShortenInfo.isEmpty() && kDocQualifiersToShorten.isEmpty()
 }
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.kt
new file mode 100644
index 0000000..73fde0e
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.kt
@@ -0,0 +1,12 @@
+// FILE: main.kt
+package test
+
+import com.dependency.bar as bar1
+import com.dependency.*
+
+fun foo() = <expr>com.dependency.bar</expr>
+
+// FILE: dependency.kt
+package com.dependency
+
+val bar = 3
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.txt
new file mode 100644
index 0000000..46cba81
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasAndStarImport.txt
@@ -0,0 +1,8 @@
+Before shortening: com.dependency.bar
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_IMPORT:
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] com.dependency.bar -> bar1
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.kt
new file mode 100644
index 0000000..73acd3b
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.kt
@@ -0,0 +1,11 @@
+// FILE: main.kt
+package test
+
+import com.dependency.bar as bar1
+
+fun foo() = <expr>com.dependency.bar()</expr>
+
+// FILE: dependency.kt
+package com.dependency
+
+fun bar() = 3
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.txt
new file mode 100644
index 0000000..09b5081
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForFunction.txt
@@ -0,0 +1,8 @@
+Before shortening: com.dependency.bar()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] com.dependency.bar() -> bar1
+with SHORTEN_AND_IMPORT:
+[qualifier] com.dependency.bar() -> bar1
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] com.dependency.bar() -> bar1
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.kt
new file mode 100644
index 0000000..1028b8c
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.kt
@@ -0,0 +1,11 @@
+// FILE: main.kt
+package test
+
+import com.dependency.bar as bar1
+
+fun foo() = <expr>com.dependency.bar</expr>
+
+// FILE: dependency.kt
+package com.dependency
+
+val bar = 3
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.txt
new file mode 100644
index 0000000..46cba81
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForProperty.txt
@@ -0,0 +1,8 @@
+Before shortening: com.dependency.bar
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_IMPORT:
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] com.dependency.bar -> bar1
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.kt
new file mode 100644
index 0000000..b843071
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.kt
@@ -0,0 +1,11 @@
+// FILE: main.kt
+package test
+
+import com.dependency.Bar as Bar1
+
+fun foo(): <expr>com.dependency.Bar</expr> = Bar1()
+
+// FILE: dependency.kt
+package com.dependency
+
+class Bar
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.txt
new file mode 100644
index 0000000..8f5a9ce
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForType.txt
@@ -0,0 +1,8 @@
+Before shortening: com.dependency.Bar
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[type] com.dependency.Bar -> Bar1
+with SHORTEN_AND_IMPORT:
+[type] com.dependency.Bar -> Bar1
+with SHORTEN_AND_STAR_IMPORT:
+[type] com.dependency.Bar -> Bar1
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.kt
new file mode 100644
index 0000000..b357956
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.kt
@@ -0,0 +1,17 @@
+// FILE: main.kt
+package test
+
+import com.dependency.Bar as Bar1
+
+fun foo() = <expr>com.dependency.Bar.bar()</expr>
+
+// FILE: dependency.kt
+package com.dependency
+
+class Bar {
+    companion object
+}
+
+fun Bar.bar(): Bar {
+    return this
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.txt
new file mode 100644
index 0000000..3b58757
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/importAliasForTypeQualifier.txt
@@ -0,0 +1,8 @@
+Before shortening: com.dependency.Bar.bar()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] com.dependency.Bar -> Bar1
+with SHORTEN_AND_IMPORT:
+[qualifier] com.dependency.Bar -> Bar1
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] com.dependency.Bar -> Bar1
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.kt
new file mode 100644
index 0000000..68fbfa7
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.kt
@@ -0,0 +1,20 @@
+// FILE: main.kt
+package test
+
+import com.dependency.*
+import com.dependency.bar as bar1
+import com.dependency.bar as bar2
+import com.dependency.bar as bar3
+import com.dependency.bar
+
+fun foo(a: Int) = <expr>when (a) {
+    1 -> bar1
+    2 -> bar2
+    3 -> bar3
+    else -> com.dependency.bar
+}</expr>
+
+// FILE: dependency.kt
+package com.dependency
+
+val bar = 3
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.txt
new file mode 100644
index 0000000..af96e61
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias.txt
@@ -0,0 +1,13 @@
+Before shortening: when (a) {
+    1 -> bar1
+    2 -> bar2
+    3 -> bar3
+    else -> com.dependency.bar
+}
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_IMPORT:
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] com.dependency.bar -> bar1
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.kt
new file mode 100644
index 0000000..9935669
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.kt
@@ -0,0 +1,18 @@
+// FILE: main.kt
+package test
+
+import com.dependency.bar as bar1
+import com.dependency.bar as bar2
+import com.dependency.bar as bar3
+
+fun foo(a: Int) = <expr>when (a) {
+    1 -> bar1
+    2 -> com.dependency.bar
+    3 -> bar3
+    else -> com.dependency.bar
+}</expr>
+
+// FILE: dependency.kt
+package com.dependency
+
+val bar = 3
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.txt
new file mode 100644
index 0000000..198a23f
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/multipleImportAlias2.txt
@@ -0,0 +1,16 @@
+Before shortening: when (a) {
+    1 -> bar1
+    2 -> com.dependency.bar
+    3 -> bar3
+    else -> com.dependency.bar
+}
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] com.dependency.bar -> bar1
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_IMPORT:
+[qualifier] com.dependency.bar -> bar1
+[qualifier] com.dependency.bar -> bar1
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] com.dependency.bar -> bar1
+[qualifier] com.dependency.bar -> bar1
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.kt
new file mode 100644
index 0000000..4951aa3
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.kt
@@ -0,0 +1,11 @@
+// FILE: main.kt
+package test
+
+import com.dependency.*
+
+fun foo() = <expr>com.dependency.bar()</expr>
+
+// FILE: dependency.kt
+package com.dependency
+
+fun bar() = 3
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.txt
new file mode 100644
index 0000000..5fc57b4
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/starImport.txt
@@ -0,0 +1,8 @@
+Before shortening: com.dependency.bar()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] com.dependency.bar()
+with SHORTEN_AND_IMPORT:
+[qualifier] com.dependency.bar()
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] com.dependency.bar()
diff --git a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt
index 3d7652b..bf79937 100644
--- a/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt
+++ b/generators/analysis-api-generator/tests/org/jetbrains/kotlin/generators/tests/analysis/api/analysisApi.kt
@@ -52,10 +52,7 @@
 import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeProvider.AbstractHasCommonSubtypeTest
 import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeProvider.AbstractTypeReferenceTest
 import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceImportAliasTest
-import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceResolveTest
-import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceResolveWithResolveExtensionTest
-import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceShortenerForWholeFileTest
-import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceShortenerTest
+import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.*
 import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.*
 import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractAnalysisApiSubstitutorsTest
 import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.types.AbstractBuiltInTypeTest