Handle SHORTEN_IF_ALEADY_IMPORTED case of KtFirReferenceShortener
For the following example, when we run the reference shortener, it
drops `a.b.c` qualifier, because it matches "FOURTH".
```
package a.b.c
fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() // FIRST
fun <E> E.foo() = hashCode() // SECOND
object Receiver {
fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() // THIRD
fun foo(a: Int, b: Boolean, c: String) = a.hashCode() + b.hashCode() + c.hashCode() // FOURTH
fun test(): Int {
fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c // FIFTH
return <expr>a.b.c.foo(1, false, "bar")</expr>
}
}
```
As shown in the above example, when SHORTEN_IF_ALEADY_IMPORTED option is
given from a user, the reference shortener has to check whether it can
drop the qualifier without changing the referenced symbol and if it is
possible to do that without adding a new import directive, it deletes
the qualifier.
It needs two steps:
1. Collect all candidate symbols matching the signature e.g., function
arguments / type arguments
2. Determine whether the referenced symbol has the highest reference
priority when we drops the qualifier depending on scopes
This commit uses `AllCandidatesResolver(shorteningContext.analysisSession.useSiteSession).
getAllCandidates( .. fake FIR call/property-access ..)` for step1.
For step2, we use a heuristic based on scopes of candidates. If a
candidate symbol is under the same scope with the target expression, it
has a `FirLocalScope` which has the high priority. So when we have a
candidate under a `FirLocalScope` and the actual referenced symbol is
different from the candidate, we must avoid dropping its qualifier
because the shortening will change its semantics i.e., reference.
The order of scopes depending on their scope types is:
1. FirLocalScope
2. FirClassUseSiteMemberScope / FirNestedClassifierScope
3. FirExplicitSimpleImportingScope
4. FirPackageMemberScope
5. others
Note that for "others" the above rule can be wrong. Please update it if
you find other scopes that have a priority higher than the specified
scopes.
One of non-trivial parts is the priority among multiple
FirClassUseSiteMemberScope and FirNestedClassifierScope. They are
basically scopes for class declarations. We decide their priorities
based on the distance of class declaration from the target expression.
Note that we take a strict approach to reject all false positive. For
example, when we are not sure, we don't shorten it to avoid changing its
semantics.
TODO: One corner case is handling receivers. We have to update
```
private fun shortenIfAlreadyImported(
firQualifiedAccess: FirQualifiedAccess,
calledSymbol: FirCallableSymbol<*>,
expressionInScope: KtExpression,
): Boolean
```
The current implementation cannot handle the following example:
```
package foo
class Foo {
fun test() {
// It references FIRST. Removing `foo` lets it reference SECOND.
<caret>foo.myRun {
42
}
}
}
inline fun <R> myRun(block: () -> R): R = block() // FIRST
inline fun <T, R> T.myRun(block: T.() -> R): R = block() // SECOND
```
Tests related to TODO:
- analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt
- analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt
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 2dba2e8..8711f84 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
@@ -6,15 +6,18 @@
package org.jetbrains.kotlin.analysis.api.descriptors.components
import com.intellij.openapi.util.TextRange
+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.ShortenOption
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
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
-import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
+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
@@ -34,6 +37,10 @@
override val isEmpty: Boolean
get() = true
+ override fun getTypesToShorten(): List<SmartPsiElementPointer<KtUserType>> = emptyList()
+
+ override fun getQualifiersToShorten(): List<SmartPsiElementPointer<KtDotQualifiedExpression>> = emptyList()
+
override fun invokeShortening() {}
}
}
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 94262b6..e0bd02b 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
@@ -5,38 +5,42 @@
package org.jetbrains.kotlin.analysis.api.fir.components
-import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiFile
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.ShortenOption
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.utils.addImportToFile
import org.jetbrains.kotlin.analysis.api.fir.utils.computeImportableName
+import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
-import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
-import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
+import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
+import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
+import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildImport
import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport
-import org.jetbrains.kotlin.fir.expressions.FirErrorResolvedQualifier
-import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
-import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
+import org.jetbrains.kotlin.fir.declarations.utils.classId
+import org.jetbrains.kotlin.fir.expressions.*
+import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
+import org.jetbrains.kotlin.fir.expressions.builder.buildPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
-import org.jetbrains.kotlin.fir.resolve.ScopeSession
+import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
@@ -48,17 +52,14 @@
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
+import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
-import org.jetbrains.kotlin.name.ClassId
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.name.Name
-import org.jetbrains.kotlin.name.parentOrNull
+import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.psi.*
-import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
-import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
-import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
+import org.jetbrains.kotlin.psi.psiUtil.*
+import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
import org.jetbrains.kotlin.utils.addIfNotNull
internal class KtFirReferenceShortener(
@@ -77,7 +78,9 @@
val declarationToVisit = file.findSmallestDeclarationContainingSelection(selection)
?: file.withDeclarationsResolvedToBodyResolve()
- val firDeclaration = declarationToVisit.getOrBuildFirOfType<FirDeclaration>(firResolveSession)
+ val firDeclaration = declarationToVisit.getOrBuildFir(firResolveSession) as? FirDeclaration ?: return ShortenCommandImpl(
+ file.createSmartPointer(), emptyList(), emptyList(), emptyList(), emptyList(),
+ )
val towerContext =
LowLevelFirApiFacadeForResolveOnAir.onAirGetTowerContextProvider(firResolveSession, declarationToVisit)
@@ -169,6 +172,8 @@
private val firSession: FirSession
get() = firResolveSession.useSiteFirSession
+ class ClassifierCandidate(val scope: FirScope, val availableSymbol: AvailableSymbol<ClassId>)
+
fun findFirstClassifierInScopesByName(positionScopes: List<FirScope>, targetClassName: Name): AvailableSymbol<ClassId>? {
for (scope in positionScopes) {
val classifierSymbol = scope.findFirstClassifierByName(targetClassName) ?: continue
@@ -180,11 +185,26 @@
return null
}
- fun findFunctionsInScopes(scopes: List<FirScope>, name: Name): List<AvailableSymbol<FirNamedFunctionSymbol>> {
+ fun findClassifiersInScopesByName(scopes: List<FirScope>, targetClassName: Name): List<ClassifierCandidate> =
+ scopes.mapNotNull { scope ->
+ val classifierSymbol = scope.findFirstClassifierByName(targetClassName) ?: return@mapNotNull null
+ val classifierLookupTag = classifierSymbol.toLookupTag() as? ConeClassLikeLookupTag ?: return@mapNotNull null
+
+ ClassifierCandidate(scope, AvailableSymbol(classifierLookupTag.classId, ImportKind.fromScope(scope)))
+ }
+
+ fun findFunctionsInScopes(scopes: List<FirScope>, name: Name): List<AvailableSymbol<FirFunctionSymbol<*>>> {
return scopes.flatMap { scope ->
val importKind = ImportKind.fromScope(scope)
- scope.getFunctions(name).map {
- AvailableSymbol(it, importKind)
+ buildList {
+ // Collect constructors
+ scope.findFirstClassifierByName(name)?.let { classifierSymbol ->
+ val classSymbol = classifierSymbol as? FirClassSymbol ?: return@let null
+ classSymbol.declarationSymbols.filterIsInstance<FirConstructorSymbol>()
+ }?.forEach { add(AvailableSymbol(it, importKind)) }
+
+ // Collect functions
+ addAll(scope.getFunctions(name).map { AvailableSymbol(it, importKind) })
}
}
}
@@ -217,7 +237,10 @@
): List<FirScope>? {
val towerDataContext = towerContextProvider.getClosestAvailableParentContext(position) ?: return null
val result = buildList {
- addAll(towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope })
+ addAll(towerDataContext.nonLocalTowerDataElements.mapNotNull {
+ // We must use `it.getAvailableScope()` instead of `it.scope` to check scopes of companion objects as well.
+ it.getAvailableScope()
+ })
addIfNotNull(createFakeImportingScope(newImports))
addAll(towerDataContext.localScopes)
}
@@ -418,18 +441,210 @@
)
}
- private inline fun <E> findClassifierElementsToShorten(
+ /**
+ * Returns true if the class symbol has a type parameter that is supposed to be provided for its parent class.
+ *
+ * Example:
+ * class Outer<T> {
+ * inner class Inner // Inner has an implicit type parameter `T`.
+ * }
+ */
+ private fun FirClassLikeSymbol<*>.hasTypeParameterFromParent(): Boolean = typeParameterSymbols.orEmpty().any {
+ it.containingDeclarationSymbol != this
+ }
+
+ private fun FirScope.correspondingClassIdIfExists(): ClassId = when (this) {
+ is FirNestedClassifierScope -> klass.classId
+ is FirClassUseSiteMemberScope -> classId
+ else -> error("FirScope `$this` is expected to be one of FirNestedClassifierScope and FirClassUseSiteMemberScope to get ClassId")
+ }
+
+ private fun ClassId.idWithoutCompanion() = if (shortClassName == SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT) outerClassId else this
+
+ private fun FirScope.isScopeForClass() = this is FirNestedClassifierScope || this is FirClassUseSiteMemberScope
+
+ /**
+ * Assuming that both this [FirScope] and [another] are [FirNestedClassifierScope] or [FirClassUseSiteMemberScope] and both of them
+ * are surrounding [from], returns whether this [FirScope] is closer than [another] based on the distance from [from].
+ *
+ * If one of this [FirScope] and [another] is not [FirNestedClassifierScope] or [FirClassUseSiteMemberScope], it returns false.
+ *
+ * Example:
+ * class Outer { // scope1 ClassId = Other
+ * class Inner { // scope2 ClassId = Other.Inner
+ * fun foo() {
+ * // Distance to scopes for classes from <element> in the order from the closest:
+ * // scope2 -> scope3 -> scope1
+ * <element>
+ * }
+ * companion object { // scope3 ClassId = Other.Inner.Companion
+ * }
+ * }
+ * }
+ *
+ * This function determines the distance based on [ClassId].
+ */
+ private fun FirScope.isScopeForClassCloserThanAnotherScopeForClass(another: FirScope, from: KtClass): Boolean {
+ // Make sure both are scopes for classes
+ if (!isScopeForClass() || !another.isScopeForClass()) return false
+
+ if (this == another) return false
+
+ val classId = correspondingClassIdIfExists()
+ val classIdOfAnother = another.correspondingClassIdIfExists()
+ if (classId == classIdOfAnother) return false
+
+ // Find the first ClassId matching inner class. If the first matching one is this scope's ClassId, it means this scope is closer
+ // than `another`.
+ val candidates = setOfNotNull(classId, classIdOfAnother, classId.idWithoutCompanion(), classIdOfAnother.idWithoutCompanion())
+ val closestClassId = findMostInnerClassMatchingId(from, candidates)
+ return closestClassId == classId || (closestClassId != classIdOfAnother && closestClassId == classId.idWithoutCompanion())
+ }
+
+ /**
+ * Travels all containing classes of [innerClass] and finds the one matching ClassId with one of [candidates]. Returns the matching
+ * ClassId. If it does not have a matching ClassId, it returns null.
+ */
+ private fun findMostInnerClassMatchingId(innerClass: KtClass, candidates: Set<ClassId>): ClassId? {
+ var classInNestedClass: KtClass? = innerClass
+ while (classInNestedClass != null) {
+ val containingClassId = classInNestedClass.getClassId()
+ if (containingClassId in candidates) return containingClassId
+ classInNestedClass = classInNestedClass.containingClass()
+ }
+ return null
+ }
+
+
+ /**
+ * An enum class to specify the distance of scopes from an element as a partial order
+ *
+ * Example:
+ * import ... // scope1 FirExplicitSimpleImportingScope - enum entry: ExplicitSimpleImporting
+ * // scope2 FirPackageMemberScope - enum entry: PackageMember
+ * class Outer { // scope3 FirClassUseSiteMemberScope - enum entry: ClassUseSite
+ * class Inner { // scope4 FirClassUseSiteMemberScope or FirNestedClassifierScope - enum entry: ClassUseSite/NestedClassifier
+ * fun foo() { // scope5 FirLocalScope - enum entry: Local
+ *
+ * // Distance to scopes from <element> in the order from the closest:
+ * // scope5 -> scope4 -> scope6 -> scope3 -> scope1 -> scope2
+ * <element>
+ *
+ * }
+ * companion object {
+ * // scope6 FirClassUseSiteMemberScope or FirNestedClassifierScope - enum entry: ClassUseSite/NestedClassifier
+ * }
+ * }
+ * }
+ */
+ private enum class PartialOrderOfScope(
+ val scopeDistanceLevel: Int // Note: Don't use the built-in ordinal since there are some scopes that are at the same level.
+ ) {
+ Local(1),
+ ClassUseSite(2),
+ NestedClassifier(2),
+ ExplicitSimpleImporting(3),
+ PackageMember(4),
+ Unclassified(5),
+ ;
+
+ companion object {
+ fun FirScope.toPartialOrder(): PartialOrderOfScope {
+ return when (this) {
+ is FirLocalScope -> Local
+ is FirClassUseSiteMemberScope -> ClassUseSite
+ is FirNestedClassifierScope -> NestedClassifier
+ is FirExplicitSimpleImportingScope -> ExplicitSimpleImporting
+ is FirPackageMemberScope -> PackageMember
+ else -> Unclassified
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether this [FirScope] is a scope wider than [another] based on the above [PartialOrderOfScope] or not.
+ */
+ private fun FirScope.isWiderThan(another: FirScope): Boolean =
+ toPartialOrder().scopeDistanceLevel > another.toPartialOrder().scopeDistanceLevel
+
+ /**
+ * Assuming that all scopes in this List<FirScope> and [base] are surrounding [from], returns whether an element of
+ * this List<FirScope> is closer than [base] based on the distance from [from].
+ */
+ private fun List<FirScope>.hasScopeCloserThan(base: FirScope, from: KtElement) = any { scope ->
+ if (scope.isScopeForClass() && base.isScopeForClass()) {
+ val classContainingFrom = from.containingClass() ?: return@any false
+ return@any scope.isScopeForClassCloserThanAnotherScopeForClass(base, classContainingFrom)
+ }
+ base.isWiderThan(scope)
+ }
+
+ /**
+ * Returns true if this [PsiFile] has a [KtImportDirective] whose imported FqName is the same as [classId] but references a different
+ * symbol.
+ */
+ private fun PsiFile.hasImportDirectiveForDifferentSymbolWithSameName(classId: ClassId): Boolean {
+ val importDirectivesWithSameImportedFqName = collectDescendantsOfType { importedDirective: KtImportDirective ->
+ importedDirective.importedFqName?.shortName() == classId.shortClassName
+ }
+ return importDirectivesWithSameImportedFqName.isNotEmpty() &&
+ importDirectivesWithSameImportedFqName.all { it.importedFqName != classId.asSingleFqName() }
+ }
+
+ private fun shortenClassifierIfAlreadyImported(
+ classId: ClassId,
+ element: KtElement,
+ classSymbol: FirClassLikeSymbol<*>,
+ positionScopes: List<FirScope>,
+ ): Boolean {
+ // If its parent has a type parameter, we cannot shorten it because it will lose its type parameter.
+ if (classSymbol.hasTypeParameterFromParent()) return false
+
+ val name = classId.shortClassName
+ val availableClassifiers = shorteningContext.findClassifiersInScopesByName(positionScopes, name)
+ val matchingAvailableSymbol = availableClassifiers.firstOrNull { it.availableSymbol.symbol == classId }
+ val scopeForClass = matchingAvailableSymbol?.scope ?: return false
+
+ if (availableClassifiers.map { it.scope }.hasScopeCloserThan(scopeForClass, element)) return false
+
+ /**
+ * If we have a property with the same name, avoid dropping qualifiers makes it reference a property with the same name e.g.,
+ * package my.component
+ * class foo { .. } // A
+ * ..
+ * fun test() {
+ * val foo = .. // B
+ * my.component.foo::class.java // If we drop `my.component`, it will reference `B` instead of `A`
+ * }
+ */
+ if (shorteningContext.findPropertiesInScopes(positionScopes, name).isNotEmpty()) {
+ val firForElement = element.getOrBuildFir(firResolveSession) as? FirQualifiedAccess
+ val typeArguments = firForElement?.typeArguments ?: emptyList()
+ val qualifiedAccessCandidates = findCandidatesForPropertyAccess(classSymbol.annotations, typeArguments, name, element)
+ if (qualifiedAccessCandidates.mapNotNull { it.candidate.originScope }.hasScopeCloserThan(scopeForClass, element)) return false
+ }
+
+ return !element.containingFile.hasImportDirectiveForDifferentSymbolWithSameName(classId)
+ }
+
+ private inline fun <E : KtElement> findClassifierElementsToShorten(
positionScopes: List<FirScope>,
allClassIds: Sequence<ClassId>,
allQualifiedElements: Sequence<E>,
createElementToShorten: (E, nameToImport: FqName?, importAllInParent: Boolean) -> ElementToShorten,
findFakePackageToShortenFn: (E) -> ElementToShorten?,
): ElementToShorten? {
-
for ((classId, element) in allClassIds.zip(allQualifiedElements)) {
- val option = classShortenOption(shorteningContext.toClassSymbol(classId) ?: return null)
+ val classSymbol = shorteningContext.toClassSymbol(classId) ?: return null
+ val option = classShortenOption(classSymbol)
if (option == ShortenOption.DO_NOT_SHORTEN) continue
+ if (shortenClassifierIfAlreadyImported(classId, element, classSymbol, positionScopes)) {
+ return createElementToShorten(element, null, false)
+ }
+ if (option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) continue
+
// Find class with the same name that's already available in this file.
val availableClassifier = shorteningContext.findFirstClassifierInScopesByName(positionScopes, classId.shortClassName)
@@ -469,13 +684,193 @@
return findFakePackageToShortenFn(allQualifiedElements.last())
}
+ private fun resolveUnqualifiedAccess(
+ fullyQualifiedAccess: FirQualifiedAccess,
+ name: Name,
+ expressionInScope: KtExpression,
+ ): List<OverloadCandidate> {
+ val fakeCalleeReference = buildSimpleNamedReference { this.name = name }
+ val functionCall = fullyQualifiedAccess as? FirFunctionCall
+ val fakeFirQualifiedAccess: FirQualifiedAccess?
+ if (functionCall == null) {
+ fakeFirQualifiedAccess = buildPropertyAccessExpression {
+ annotations.addAll(fullyQualifiedAccess.annotations)
+ typeArguments.addAll(fullyQualifiedAccess.typeArguments)
+ calleeReference = fakeCalleeReference
+ }
+ } else {
+ val callExpression = expressionInScope as? KtCallExpression
+ fakeFirQualifiedAccess = buildFunctionCall {
+ annotations.addAll(functionCall.annotations)
+
+ /**
+ * It is important to avoid passing type arguments when they are implicit type arguments.
+ * For example,
+ * package a.b.c
+ * fun <T, E> foo(a: T, b: E) {} // A
+ * fun test() {
+ * fun foo(a: Int, b: String) {} // B
+ * a.b.c.foo(3, "test")
+ * }
+ *
+ * In the above code, we must prevent it from shortening `a.b.c.foo(3, "test")`. However, if we explicitly pass the type
+ * arguments to the resolver, the resolver considers it has some explicit type arguments. Therefore, it reports that the
+ * only function matching the signature is A, because B does not have type parameters. However, actually B also matches the
+ * signature, and we must avoid dropping a.b.c from the call expression.
+ */
+ if (callExpression?.typeArguments?.isNotEmpty() == true) typeArguments.addAll(functionCall.typeArguments)
+
+ argumentList = functionCall.argumentList
+ calleeReference = fakeCalleeReference
+ }
+ }
+ val candidates = AllCandidatesResolver(shorteningContext.analysisSession.useSiteSession).getAllCandidates(
+ firResolveSession, fakeFirQualifiedAccess, name, expressionInScope
+ )
+ return candidates.filter { overloadCandidate ->
+ overloadCandidate.candidate.currentApplicability == CandidateApplicability.RESOLVED
+ }
+ }
+
+ private fun findCandidatesForPropertyAccess(
+ annotations: List<FirAnnotation>,
+ typeArguments: List<FirTypeProjection>,
+ name: Name,
+ elementInScope: KtElement,
+ ): List<OverloadCandidate> {
+ val fakeCalleeReference = buildSimpleNamedReference { this.name = name }
+ val fakeFirQualifiedAccess = buildPropertyAccessExpression {
+ this.annotations.addAll(annotations)
+ this.typeArguments.addAll(typeArguments)
+ calleeReference = fakeCalleeReference
+ }
+ val candidates = AllCandidatesResolver(shorteningContext.analysisSession.useSiteSession).getAllCandidates(
+ firResolveSession, fakeFirQualifiedAccess, name, elementInScope
+ )
+ return candidates.filter { overloadCandidate ->
+ overloadCandidate.candidate.currentApplicability == CandidateApplicability.RESOLVED
+ }
+ }
+
+ private fun List<OverloadCandidate>.findScopeForSymbol(symbol: FirBasedSymbol<*>): FirScope? = firstOrNull {
+ it.candidate.symbol == symbol
+ }?.candidate?.originScope
+
+ /**
+ * Returns whether a member of companion is used to initialize the enum entry or not. For example,
+ * enum class C(val i: Int) {
+ * ONE(<expr>C.K</expr>) // C.ONE uses C.K for initialization
+ * ;
+ * companion object {
+ * const val K = 1
+ * }
+ * }
+ */
+ private fun KtExpression.isCompanionMemberUsedForEnumEntryInit(resolvedSymbol: FirCallableSymbol<*>): Boolean {
+ val enumEntry = getNonStrictParentOfType<KtEnumEntry>() ?: return false
+ val firEnumEntry = enumEntry.resolveToFirSymbol(firResolveSession) as? FirEnumEntrySymbol ?: return false
+ val classNameOfResolvedSymbol = resolvedSymbol.callableId.className ?: return false
+ return firEnumEntry.callableId.className == classNameOfResolvedSymbol.parent() &&
+ classNameOfResolvedSymbol.shortName() == SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
+ }
+
+ /**
+ * Returns whether it is fine to shorten [firQualifiedAccess] or not.
+ *
+ * @param firQualifiedAccess FIR for the shortening target expression
+ * @param calledSymbol The symbol referenced by the qualified access expression
+ * @param expressionInScope An expression under the same scope as the shortening target expression
+ *
+ * The decision has two steps:
+ * 1. Collect all candidates matching [firQualifiedAccess]
+ * - We use `AllCandidatesResolver(shorteningContext.analysisSession.useSiteSession).getAllCandidates( .. fake FIR .. )`. See
+ * [resolveUnqualifiedAccess] above.
+ * 2. Check whether the candidate with the highest priority based on the distance to the scope from [expressionInScope] is the same
+ * as [calledSymbol] ot not
+ * - We use [hasScopeCloserThan] to determine the distance to the scope
+ */
+ private fun shortenIfAlreadyImported(
+ firQualifiedAccess: FirQualifiedAccess,
+ calledSymbol: FirCallableSymbol<*>,
+ expressionInScope: KtExpression,
+ ): Boolean {
+ /**
+ * Avoid shortening reference to enum companion used in enum entry initialization there is no guarantee that the companion object
+ * was initialized in advance.
+ * For example, When we shorten the following code:
+ * enum class C(val i: Int) {
+ * ONE(<expr>C.K</expr>) // shorten C.K to K
+ * ;
+ * companion object {
+ * const val K = 1
+ * }
+ * }
+ *
+ * the compiler reports "Variable 'K' must be initialized". This happens because there is no guarantee that the companion object
+ * was initialized at the time when we use `C.K` for the enum entry `ONE`. To avoid this type of compiler errors, we don't shorten
+ * the reference if it is a part of the enum companion object, and it is used by the enum entry initialization.
+ */
+ if (expressionInScope.isCompanionMemberUsedForEnumEntryInit(calledSymbol)) return false
+
+ val candidates = resolveUnqualifiedAccess(firQualifiedAccess, calledSymbol.name, expressionInScope)
+
+ val scopeForQualifiedAccess = candidates.findScopeForSymbol(calledSymbol) ?: return false
+ if (candidates.mapNotNull { it.candidate.originScope }
+ .hasScopeCloserThan(scopeForQualifiedAccess, expressionInScope)) return false
+ val candidatesWithinSamePriorityScopes = candidates.filter { it.candidate.originScope == scopeForQualifiedAccess }
+ if (candidatesWithinSamePriorityScopes.isEmpty() || candidatesWithinSamePriorityScopes.size == 1) return true
+
+ /**
+ * This is a conservative decision to avoid false positives.
+ *
+ * TODO: Figure out the priorities among `candidatesWithinSamePriorityScopes` and determine if [firQualifiedAccess] matches the
+ * one with the highest priority. At this moment, we have some counter examples that [OverloadCandidate.isInBestCandidates] is true
+ * and its symbol matches [firQualifiedAccess], but we cannot shorten it.
+ *
+ * For example:
+ * package foo
+ * class Foo {
+ * fun test() {
+ * // It references FIRST. Removing `foo` lets it reference SECOND. However, the one has true for
+ * // [OverloadCandidate.isInBestCandidates] is FIRST. Therefore, making a decision based on `isInBestCandidates` can
+ * // cause false positives i.e., shortening changes the referenced symbol.
+ * <caret>foo.myRun {
+ * 42
+ * }
+ * }
+ * }
+ * inline fun <R> myRun(block: () -> R): R = block() // FIRST
+ * inline fun <T, R> T.myRun(block: T.() -> R): R = block() // SECOND
+ */
+ return false
+ }
+
private fun processPropertyReference(resolvedNamedReference: FirResolvedNamedReference) {
val referenceExpression = resolvedNamedReference.psi as? KtNameReferenceExpression ?: return
if (!referenceExpression.textRange.intersects(selection)) return
val qualifiedProperty = referenceExpression.getDotQualifiedExpressionForSelector() ?: return
val callableSymbol = resolvedNamedReference.resolvedSymbol as? FirCallableSymbol<*> ?: return
- processCallableQualifiedAccess(callableSymbol, qualifiedProperty, qualifiedProperty, shorteningContext::findPropertiesInScopes)
+
+ val option = callableShortenOption(callableSymbol)
+ if (option == ShortenOption.DO_NOT_SHORTEN) return
+
+ val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, namesToImport, towerContextProvider) ?: return
+ val availableCallables = shorteningContext.findPropertiesInScopes(scopes, callableSymbol.name)
+
+ val firPropertyAccess = qualifiedProperty.getOrBuildFir(firResolveSession) as? FirQualifiedAccess ?: return
+ if (availableCallables.isNotEmpty() && shortenIfAlreadyImported(firPropertyAccess, callableSymbol, referenceExpression)) {
+ addElementToShorten(ShortenQualifier(qualifiedProperty))
+ return
+ }
+ if (option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) return
+
+ processCallableQualifiedAccess(
+ callableSymbol,
+ option,
+ qualifiedProperty,
+ availableCallables,
+ )
}
private fun processFunctionCall(functionCall: FirFunctionCall) {
@@ -487,21 +882,34 @@
val calleeReference = functionCall.calleeReference
val calledSymbol = findUnambiguousReferencedCallableId(calleeReference) ?: return
- processCallableQualifiedAccess(calledSymbol, qualifiedCallExpression, callExpression, shorteningContext::findFunctionsInScopes)
+
+ val option = callableShortenOption(calledSymbol)
+ if (option == ShortenOption.DO_NOT_SHORTEN) return
+
+ val scopes = shorteningContext.findScopesAtPosition(callExpression, namesToImport, towerContextProvider) ?: return
+ val availableCallables = shorteningContext.findFunctionsInScopes(scopes, calledSymbol.name)
+ if (availableCallables.isNotEmpty() && shortenIfAlreadyImported(functionCall, calledSymbol, callExpression)) {
+ addElementToShorten(ShortenQualifier(qualifiedCallExpression))
+ return
+ }
+ if (option == ShortenOption.SHORTEN_IF_ALREADY_IMPORTED) return
+
+ processCallableQualifiedAccess(
+ calledSymbol,
+ option,
+ qualifiedCallExpression,
+ availableCallables,
+ )
}
private fun processCallableQualifiedAccess(
calledSymbol: FirCallableSymbol<*>,
+ option: ShortenOption,
qualifiedCallExpression: KtDotQualifiedExpression,
- expressionToGetScope: KtExpression,
- findCallableInScopes: (List<FirScope>, Name) -> List<AvailableSymbol<FirCallableSymbol<*>>>,
+ availableCallables: List<AvailableSymbol<FirCallableSymbol<*>>>,
) {
- val option = callableShortenOption(calledSymbol)
if (option == ShortenOption.DO_NOT_SHORTEN) return
- val scopes = shorteningContext.findScopesAtPosition(expressionToGetScope, namesToImport, towerContextProvider) ?: return
- val availableCallables = findCallableInScopes(scopes, calledSymbol.name)
-
val nameToImport = shorteningContext.convertToImportableName(calledSymbol)
val (matchedCallables, otherCallables) = availableCallables.partition { it.symbol.callableId == calledSymbol.callableId }
@@ -609,11 +1017,11 @@
}
private class ShortenCommandImpl(
- val targetFile: SmartPsiElementPointer<KtFile>,
- val importsToAdd: List<FqName>,
- val starImportsToAdd: List<FqName>,
- val typesToShorten: List<SmartPsiElementPointer<KtUserType>>,
- val qualifiersToShorten: List<SmartPsiElementPointer<KtDotQualifiedExpression>>,
+ private val targetFile: SmartPsiElementPointer<KtFile>,
+ private val importsToAdd: List<FqName>,
+ private val starImportsToAdd: List<FqName>,
+ private val typesToShorten: List<SmartPsiElementPointer<KtUserType>>,
+ private val qualifiersToShorten: List<SmartPsiElementPointer<KtDotQualifiedExpression>>,
) : ShortenCommand {
override fun invokeShortening() {
@@ -643,6 +1051,10 @@
}
override val isEmpty: Boolean get() = typesToShorten.isEmpty() && qualifiersToShorten.isEmpty()
+
+ override fun getTypesToShorten(): List<SmartPsiElementPointer<KtUserType>> = typesToShorten
+
+ override fun getQualifiersToShorten(): List<SmartPsiElementPointer<KtDotQualifiedExpression>> = qualifiersToShorten
}
private fun KtUserType.hasFakeRootPrefix(): Boolean =
@@ -657,4 +1069,4 @@
private fun KtDotQualifiedExpression.deleteQualifier(): KtExpression? {
val selectorExpression = selectorExpression ?: return null
return this.replace(selectorExpression) as KtExpression
-}
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..7705259
--- /dev/null
+++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.analysis.api.fir.test.cases.generated.cases.references;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.util.KtTestUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.analysis.api.fir.test.configurators.AnalysisApiFirTestConfiguratorFactory;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
+import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceShortenerTest;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@TestMetadata("analysis/analysis-api/testData/components/referenceShortener/referenceShortener")
+@TestDataPath("$PROJECT_ROOT")
+public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated extends AbstractReferenceShortenerTest {
+ @NotNull
+ @Override
+ public AnalysisApiTestConfigurator getConfigurator() {
+ return AnalysisApiFirTestConfiguratorFactory.INSTANCE.createConfigurator(
+ new AnalysisApiTestConfiguratorFactoryData(
+ FrontendKind.Fir,
+ TestModuleKind.Source,
+ AnalysisSessionMode.Normal,
+ AnalysisApiMode.Ide
+ )
+ );
+ }
+
+ @Test
+ public void testAllFilesPresentInReferenceShortener() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/referenceShortener/referenceShortener"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("classScopes.kt")
+ public void testClassScopes() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.kt");
+ }
+
+ @Test
+ @TestMetadata("classScopes2.kt")
+ public void testClassScopes2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.kt");
+ }
+
+ @Test
+ @TestMetadata("classScopes3.kt")
+ public void testClassScopes3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.kt");
+ }
+
+ @Test
+ @TestMetadata("classType.kt")
+ public void testClassType() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.kt");
+ }
+
+ @Test
+ @TestMetadata("classType2.kt")
+ public void testClassType2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName.kt")
+ public void testClassesWithSameName() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName2.kt")
+ public void testClassesWithSameName2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName3.kt")
+ public void testClassesWithSameName3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName4.kt")
+ public void testClassesWithSameName4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName5.kt")
+ public void testClassesWithSameName5() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName6.kt")
+ public void testClassesWithSameName6() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName7.kt")
+ public void testClassesWithSameName7() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName8.kt")
+ public void testClassesWithSameName8() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName9.kt")
+ public void testClassesWithSameName9() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.kt");
+ }
+
+ @Test
+ @TestMetadata("companionClassLiteral.kt")
+ public void testCompanionClassLiteral() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.kt");
+ }
+
+ @Test
+ @TestMetadata("companionClassLiteral2.kt")
+ public void testCompanionClassLiteral2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.kt");
+ }
+
+ @Test
+ @TestMetadata("companionClassLiteral3.kt")
+ public void testCompanionClassLiteral3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.kt");
+ }
+
+ @Test
+ @TestMetadata("companionQualifier.kt")
+ public void testCompanionQualifier() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.kt");
+ }
+
+ @Test
+ @TestMetadata("companionUsedOutOfClass.kt")
+ public void testCompanionUsedOutOfClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt");
+ }
+
+ @Test
+ @TestMetadata("enumClassCompanionAlreadyImported.kt")
+ public void testEnumClassCompanionAlreadyImported() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.kt");
+ }
+
+ @Test
+ @TestMetadata("enumEntryInitUsesCompanion.kt")
+ public void testEnumEntryInitUsesCompanion() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.kt");
+ }
+
+ @Test
+ @TestMetadata("enumEntryInitUsesCompanion2.kt")
+ public void testEnumEntryInitUsesCompanion2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClass.kt")
+ public void testNestedClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClass2.kt")
+ public void testNestedClass2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClass3.kt")
+ public void testNestedClass3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt");
+ }
+
+ @Test
+ @TestMetadata("parameterTypeTopLevelTypeLoses.kt")
+ public void testParameterTypeTopLevelTypeLoses() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver.kt")
+ public void testReceiver() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver2.kt")
+ public void testReceiver2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver3.kt")
+ public void testReceiver3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver4.kt")
+ public void testReceiver4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.kt");
+ }
+
+ @Test
+ @TestMetadata("referenceInNestedClass.kt")
+ public void testReferenceInNestedClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.kt");
+ }
+
+ @Test
+ @TestMetadata("sameNameDifferentParams.kt")
+ public void testSameNameDifferentParams() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.kt");
+ }
+
+ @Test
+ @TestMetadata("sameNameDifferentReceiver.kt")
+ public void testSameNameDifferentReceiver() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.kt");
+ }
+
+ @Test
+ @TestMetadata("sameTypeNamesWithinSameScopes.kt")
+ public void testSameTypeNamesWithinSameScopes() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedClass.kt")
+ public void testShortenAlreadyImportedClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedClass2.kt")
+ public void testShortenAlreadyImportedClass2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction.kt")
+ public void testShortenAlreadyImportedFunction() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction2.kt")
+ public void testShortenAlreadyImportedFunction2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction3.kt")
+ public void testShortenAlreadyImportedFunction3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction4.kt")
+ public void testShortenAlreadyImportedFunction4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.kt");
+ }
+
+ @Test
+ @TestMetadata("superClass.kt")
+ public void testSuperClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.kt");
+ }
+
+ @Test
+ @TestMetadata("typeParams.kt")
+ public void testTypeParams() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.kt");
+ }
+
+ @Test
+ @TestMetadata("typeParams2.kt")
+ public void testTypeParams2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.kt");
+ }
+
+ @Test
+ @TestMetadata("variable.kt")
+ public void testVariable() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.kt");
+ }
+
+ @Test
+ @TestMetadata("variable2.kt")
+ public void testVariable2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.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
new file mode 100644
index 0000000..03057b3
--- /dev/null
+++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceShortenerTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references
+
+import org.jetbrains.kotlin.analysis.api.components.ShortenOption
+import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiBasedSingleModuleTest
+import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider
+import org.jetbrains.kotlin.analysis.test.framework.utils.executeOnPooledThreadInReadAction
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.test.model.TestModule
+import org.jetbrains.kotlin.test.services.TestServices
+import org.jetbrains.kotlin.test.services.assertions
+
+/**
+ * A class for reference shortener test.
+ *
+ * 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.getSelectedElement(ktFiles.first())
+
+ val shortenings = executeOnPooledThreadInReadAction {
+ analyseForTest(element) {
+ ShortenOption.values().map { option ->
+ Pair(option.name, collectPossibleReferenceShorteningsInElement(element, { option }, { option }))
+ }
+ }
+ }
+
+ val actual = buildString {
+ appendLine("Before shortening: ${element.text}")
+ shortenings.forEach { (name, shortening) ->
+ appendLine("with ${name}:")
+ if (shortening.isEmpty) return@forEach
+ shortening.getTypesToShorten().forEach { userType ->
+ userType.element?.text?.let {
+ appendLine("[type] $it")
+ }
+ }
+ shortening.getQualifiersToShorten().forEach { qualifier ->
+ qualifier.element?.text?.let {
+ appendLine("[qualifier] $it")
+ }
+ }
+ }
+ }
+ testServices.assertions.assertEqualsToTestDataFileSibling(actual)
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..a74cdde
--- /dev/null
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.analysis.api.standalone.fir.test.cases.generated.cases.references;
+
+import com.intellij.testFramework.TestDataPath;
+import org.jetbrains.kotlin.test.util.KtTestUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.kotlin.analysis.api.standalone.fir.test.AnalysisApiFirStandaloneModeTestConfiguratorFactory;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfiguratorFactoryData;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.TestModuleKind;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisSessionMode;
+import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiMode;
+import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceShortenerTest;
+import org.jetbrains.kotlin.test.TestMetadata;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.analysis.api.GenerateAnalysisApiTestsKt}. DO NOT MODIFY MANUALLY */
+@SuppressWarnings("all")
+@TestMetadata("analysis/analysis-api/testData/components/referenceShortener/referenceShortener")
+@TestDataPath("$PROJECT_ROOT")
+public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated extends AbstractReferenceShortenerTest {
+ @NotNull
+ @Override
+ public AnalysisApiTestConfigurator getConfigurator() {
+ return AnalysisApiFirStandaloneModeTestConfiguratorFactory.INSTANCE.createConfigurator(
+ new AnalysisApiTestConfiguratorFactoryData(
+ FrontendKind.Fir,
+ TestModuleKind.Source,
+ AnalysisSessionMode.Normal,
+ AnalysisApiMode.Standalone
+ )
+ );
+ }
+
+ @Test
+ public void testAllFilesPresentInReferenceShortener() throws Exception {
+ KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/referenceShortener/referenceShortener"), Pattern.compile("^(.+)\\.kt$"), null, true);
+ }
+
+ @Test
+ @TestMetadata("classScopes.kt")
+ public void testClassScopes() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.kt");
+ }
+
+ @Test
+ @TestMetadata("classScopes2.kt")
+ public void testClassScopes2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.kt");
+ }
+
+ @Test
+ @TestMetadata("classScopes3.kt")
+ public void testClassScopes3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.kt");
+ }
+
+ @Test
+ @TestMetadata("classType.kt")
+ public void testClassType() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.kt");
+ }
+
+ @Test
+ @TestMetadata("classType2.kt")
+ public void testClassType2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName.kt")
+ public void testClassesWithSameName() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName2.kt")
+ public void testClassesWithSameName2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName3.kt")
+ public void testClassesWithSameName3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName4.kt")
+ public void testClassesWithSameName4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName5.kt")
+ public void testClassesWithSameName5() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName6.kt")
+ public void testClassesWithSameName6() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName7.kt")
+ public void testClassesWithSameName7() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName8.kt")
+ public void testClassesWithSameName8() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.kt");
+ }
+
+ @Test
+ @TestMetadata("classesWithSameName9.kt")
+ public void testClassesWithSameName9() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.kt");
+ }
+
+ @Test
+ @TestMetadata("companionClassLiteral.kt")
+ public void testCompanionClassLiteral() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.kt");
+ }
+
+ @Test
+ @TestMetadata("companionClassLiteral2.kt")
+ public void testCompanionClassLiteral2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.kt");
+ }
+
+ @Test
+ @TestMetadata("companionClassLiteral3.kt")
+ public void testCompanionClassLiteral3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.kt");
+ }
+
+ @Test
+ @TestMetadata("companionQualifier.kt")
+ public void testCompanionQualifier() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.kt");
+ }
+
+ @Test
+ @TestMetadata("companionUsedOutOfClass.kt")
+ public void testCompanionUsedOutOfClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt");
+ }
+
+ @Test
+ @TestMetadata("enumClassCompanionAlreadyImported.kt")
+ public void testEnumClassCompanionAlreadyImported() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.kt");
+ }
+
+ @Test
+ @TestMetadata("enumEntryInitUsesCompanion.kt")
+ public void testEnumEntryInitUsesCompanion() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.kt");
+ }
+
+ @Test
+ @TestMetadata("enumEntryInitUsesCompanion2.kt")
+ public void testEnumEntryInitUsesCompanion2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClass.kt")
+ public void testNestedClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClass2.kt")
+ public void testNestedClass2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.kt");
+ }
+
+ @Test
+ @TestMetadata("nestedClass3.kt")
+ public void testNestedClass3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt");
+ }
+
+ @Test
+ @TestMetadata("parameterTypeTopLevelTypeLoses.kt")
+ public void testParameterTypeTopLevelTypeLoses() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver.kt")
+ public void testReceiver() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver2.kt")
+ public void testReceiver2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver3.kt")
+ public void testReceiver3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt");
+ }
+
+ @Test
+ @TestMetadata("receiver4.kt")
+ public void testReceiver4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.kt");
+ }
+
+ @Test
+ @TestMetadata("referenceInNestedClass.kt")
+ public void testReferenceInNestedClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.kt");
+ }
+
+ @Test
+ @TestMetadata("sameNameDifferentParams.kt")
+ public void testSameNameDifferentParams() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.kt");
+ }
+
+ @Test
+ @TestMetadata("sameNameDifferentReceiver.kt")
+ public void testSameNameDifferentReceiver() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.kt");
+ }
+
+ @Test
+ @TestMetadata("sameTypeNamesWithinSameScopes.kt")
+ public void testSameTypeNamesWithinSameScopes() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedClass.kt")
+ public void testShortenAlreadyImportedClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedClass2.kt")
+ public void testShortenAlreadyImportedClass2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction.kt")
+ public void testShortenAlreadyImportedFunction() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction2.kt")
+ public void testShortenAlreadyImportedFunction2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction3.kt")
+ public void testShortenAlreadyImportedFunction3() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.kt");
+ }
+
+ @Test
+ @TestMetadata("shortenAlreadyImportedFunction4.kt")
+ public void testShortenAlreadyImportedFunction4() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.kt");
+ }
+
+ @Test
+ @TestMetadata("superClass.kt")
+ public void testSuperClass() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.kt");
+ }
+
+ @Test
+ @TestMetadata("typeParams.kt")
+ public void testTypeParams() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.kt");
+ }
+
+ @Test
+ @TestMetadata("typeParams2.kt")
+ public void testTypeParams2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.kt");
+ }
+
+ @Test
+ @TestMetadata("variable.kt")
+ public void testVariable() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.kt");
+ }
+
+ @Test
+ @TestMetadata("variable2.kt")
+ public void testVariable2() throws Exception {
+ runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.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 a8fd973..c0bd605 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
@@ -6,26 +6,55 @@
package org.jetbrains.kotlin.analysis.api.components
import com.intellij.openapi.util.TextRange
+import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.analysis.api.components.ShortenOption.Companion.defaultCallableShortenOption
import org.jetbrains.kotlin.analysis.api.components.ShortenOption.Companion.defaultClassShortenOption
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtUserType
public enum class ShortenOption {
/** Skip shortening references to this symbol. */
DO_NOT_SHORTEN,
- /** Only shorten references to this symbol if it's already imported in the file. Otherwise, leave it as it is. */
+ /**
+ * Only shorten references to this symbol if it's possible without adding a new import directive to the file. Otherwise, leave it as
+ * it is.
+ *
+ * Example:
+ * package a.b.c
+ * import foo.bar
+ * fun test() {}
+ * fun runFunctions() {
+ * foo.bar() // -> bar()
+ * a.b.c.test() // -> test()
+ * }
+ */
SHORTEN_IF_ALREADY_IMPORTED,
- /** Shorten references to this symbol and import it into the file. */
+ /**
+ * Shorten references to this symbol and import it into the file if importing it is needed for the shortening.
+ *
+ * Example:
+ * package a.b.c
+ * fun test() {}
+ * fun runFunctions() {
+ * foo.bar() // -> bar() and add a new import directive `import foo.bar`
+ * a.b.c.test() // -> test()
+ * }
+ */
SHORTEN_AND_IMPORT,
- /** Shorten references to this symbol and import this symbol and all its sibling symbols with star import on the parent. */
+ /**
+ * Shorten references to this symbol and import this symbol and all its sibling symbols with star import on the parent if importing them
+ * is needed for the shortening.
+ */
SHORTEN_AND_STAR_IMPORT;
public companion object {
@@ -92,4 +121,6 @@
public interface ShortenCommand {
public fun invokeShortening()
public val isEmpty: Boolean
+ public fun getTypesToShorten(): List<SmartPsiElementPointer<KtUserType>>
+ public fun getQualifiersToShorten(): List<SmartPsiElementPointer<KtDotQualifiedExpression>>
}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.kt
new file mode 100644
index 0000000..60e9a41
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.kt
@@ -0,0 +1,22 @@
+// FILE: main.kt
+package my.simple.name
+
+open class SuperClass {
+ companion object {
+ fun check() {}
+ }
+}
+
+class Child: SuperClass {
+ class Foo constructor() {
+ constructor(i: Int) : this()
+
+ fun foo() {
+ <expr>my.simple.name.SuperClass.check()</expr>
+ }
+
+ companion object {
+ fun check() {}
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.txt
new file mode 100644
index 0000000..3e515fa
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.txt
@@ -0,0 +1,8 @@
+Before shortening: my.simple.name.SuperClass.check()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] my.simple.name.SuperClass
+with SHORTEN_AND_IMPORT:
+[qualifier] my.simple.name.SuperClass
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] my.simple.name.SuperClass
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.kt
new file mode 100644
index 0000000..187e379
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.kt
@@ -0,0 +1,22 @@
+// FILE: main.kt
+package my.simple.name
+
+open class SuperClass {
+ companion object {
+ fun check() {}
+ }
+}
+
+class Child: SuperClass {
+ class Foo constructor() {
+ constructor(i: Int) : this()
+
+ fun foo() {
+ <expr>Child.Foo.check()</expr>
+ }
+
+ companion object {
+ fun check() {}
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.txt
new file mode 100644
index 0000000..ca2e835
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.txt
@@ -0,0 +1,11 @@
+Before shortening: Child.Foo.check()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Child.Foo
+[qualifier] Child.Foo.check()
+with SHORTEN_AND_IMPORT:
+[qualifier] Child.Foo
+[qualifier] Child.Foo.check()
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Child.Foo
+[qualifier] Child.Foo.check()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.kt
new file mode 100644
index 0000000..c2da4f1
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.kt
@@ -0,0 +1,28 @@
+// FILE: main.kt
+package my.simple.name
+
+class ClassFarAway {
+ companion object {
+ fun check() {}
+ }
+}
+
+open class SuperClass {
+ companion object {
+ fun check() {}
+ }
+}
+
+class Child: SuperClass {
+ class Foo constructor() {
+ constructor(i: Int) : this()
+
+ fun foo() {
+ <expr>my.simple.name.ClassFarAway.check()</expr>
+ }
+
+ companion object {
+ fun check() {}
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.txt
new file mode 100644
index 0000000..70aac6d
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.txt
@@ -0,0 +1,8 @@
+Before shortening: my.simple.name.ClassFarAway.check()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] my.simple.name.ClassFarAway
+with SHORTEN_AND_IMPORT:
+[qualifier] my.simple.name.ClassFarAway
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] my.simple.name.ClassFarAway
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.kt
new file mode 100644
index 0000000..8a9810a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package a.b.c
+
+class Outer {
+ class Inner {
+ companion object {
+ }
+ }
+}
+
+fun foo(): Class<*> {
+ return <expr>a.b.c.Outer.Inner::class.java</expr>
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.txt
new file mode 100644
index 0000000..5dde274
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.txt
@@ -0,0 +1,8 @@
+Before shortening: a.b.c.Outer.Inner::class.java
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.Outer
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.Outer.Inner
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.kt
new file mode 100644
index 0000000..8251fb3
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.kt
@@ -0,0 +1,12 @@
+// FILE: main.kt
+package a.b.c
+
+class Outer {
+ class Middle {
+ class Inner {
+ fun foo(): Class<*> {
+ return <expr>a.b.c.Outer.Middle.Inner::class.java</expr>
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.txt
new file mode 100644
index 0000000..552a4e3
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.txt
@@ -0,0 +1,8 @@
+Before shortening: a.b.c.Outer.Middle.Inner::class.java
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.Outer.Middle.Inner
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.Outer.Middle.Inner
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.Outer.Middle.Inner
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt
new file mode 100644
index 0000000..353e387
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt
@@ -0,0 +1,14 @@
+// FILE: main.kt
+package a.b.c
+
+class Outer {
+ class Inner {
+ companion object {
+ }
+ }
+}
+
+fun foo(): Class<*> {
+ class Outer
+ return <expr>a.b.c.Outer.Inner::class.java</expr>
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.txt
new file mode 100644
index 0000000..387f95e
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.txt
@@ -0,0 +1,7 @@
+Before shortening: a.b.c.Outer.Inner::class.java
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.Outer.Inner
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.kt
new file mode 100644
index 0000000..af2e860
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package a.b.c
+
+class Outer {
+ class Inner {
+ fun foo(): Class<*> {
+ class Outer
+ return <expr>a.b.c.Outer.Inner::class.java</expr>
+ }
+ companion object {
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.txt
new file mode 100644
index 0000000..2ef84e4
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.txt
@@ -0,0 +1,8 @@
+Before shortening: a.b.c.Outer.Inner::class.java
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.Outer.Inner
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.kt
new file mode 100644
index 0000000..f5c87c6
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package a.b.c
+
+class Outer {
+ class Outer
+ class Inner {
+ fun foo(): Class<*> {
+ return <expr>a.b.c.Outer.Inner::class.java</expr>
+ }
+ companion object {
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.txt
new file mode 100644
index 0000000..2ef84e4
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.txt
@@ -0,0 +1,8 @@
+Before shortening: a.b.c.Outer.Inner::class.java
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.Outer.Inner
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.kt
new file mode 100644
index 0000000..d56dd59
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.kt
@@ -0,0 +1,16 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ class Bwd {
+ fun dad() {
+ val Bwd = 42
+
+ class BBD
+
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.txt
new file mode 100644
index 0000000..70897b9
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.kt
new file mode 100644
index 0000000..a5b10eb
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.kt
@@ -0,0 +1,16 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ class Bwd {
+ fun dad() {
+ val Bwd = 42
+
+ val BBD = 3
+
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.txt
new file mode 100644
index 0000000..70897b9
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.kt
new file mode 100644
index 0000000..657b66b
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.kt
@@ -0,0 +1,15 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ class Bwd {
+ class BBD
+ fun dad() {
+ val Bwd = 42
+
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.txt
new file mode 100644
index 0000000..70897b9
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.kt
new file mode 100644
index 0000000..7f8981d
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.kt
@@ -0,0 +1,15 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ class BBD
+ class Bwd {
+ fun dad() {
+ val Bwd = 42
+
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.txt
new file mode 100644
index 0000000..70897b9
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.kt
new file mode 100644
index 0000000..0c363ed
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.kt
@@ -0,0 +1,17 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class BBD {
+ class Bwd
+}
+class Check {
+ class BBD {
+ class Bwd {
+ fun dad() {
+ val Bwd = 42
+
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.txt
new file mode 100644
index 0000000..a914b25
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check.BBD
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.kt
new file mode 100644
index 0000000..5dfc84c
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ class Bwd {
+ fun dad() {
+
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.txt
new file mode 100644
index 0000000..6790369
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.kt
new file mode 100644
index 0000000..cd0f556
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ companion object Bwd {
+ fun dad() {
+ val Bwd = 42
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.txt
new file mode 100644
index 0000000..a914b25
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check.BBD
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.kt
new file mode 100644
index 0000000..adfa4ff
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ object Bwd {
+ fun dad() {
+ val Bwd = 42
+ val a = <expr>foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.txt
new file mode 100644
index 0000000..a914b25
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check.BBD
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Bwd
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.kt
new file mode 100644
index 0000000..b3c4be0
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package foo.www.ddd
+
+class Check {
+ class BBD {
+ companion object {
+ fun dad() {
+ val Bwd = 42
+ val a = <expr>foo.www.ddd.Check.BBD.Companion::class.java.annotatedInterfaces.size</expr>
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.txt
new file mode 100644
index 0000000..4b4ed3f
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.txt
@@ -0,0 +1,8 @@
+Before shortening: foo.www.ddd.Check.BBD.Companion::class.java.annotatedInterfaces.size
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] foo.www.ddd.Check.BBD.Companion
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Companion
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.www.ddd.Check.BBD.Companion
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.kt
new file mode 100644
index 0000000..afe4d50
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.kt
@@ -0,0 +1,19 @@
+// FILE: main.kt
+package a.b.c
+
+class Outer {
+ fun <E> E.foo(x: E, y: E, z: E) = x.hashCode() + y.hashCode() + z.hashCode()
+
+ class Inner {
+ fun foo(a: Int, b: Boolean, c: String) = c + a + b
+
+ companion object {
+ fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+ }
+ }
+}
+
+fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c
+ return <expr>a.b.c.Outer.Inner.Companion.foo(1, false, "bar")</expr>
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.txt
new file mode 100644
index 0000000..1152500
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.txt
@@ -0,0 +1,8 @@
+Before shortening: a.b.c.Outer.Inner.Companion.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.Outer
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.Outer.Inner.Companion
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.Outer.Inner.Companion
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt
new file mode 100644
index 0000000..73bb9cd
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt
@@ -0,0 +1,14 @@
+// FILE: main.kt
+package a.b.c
+
+class MyClass(val id: Int) {
+ companion object {
+ fun foo() = ""
+ }
+}
+
+fun test() {
+ <expr>a.b.c.MyClass.Companion.foo()</expr>
+}
+
+fun foo() = ""
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.txt
new file mode 100644
index 0000000..44c68ec
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.txt
@@ -0,0 +1,8 @@
+Before shortening: a.b.c.MyClass.Companion.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.MyClass
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.MyClass.Companion
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.MyClass.Companion
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.kt
new file mode 100644
index 0000000..15cd012
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.kt
@@ -0,0 +1,18 @@
+package a.b.c
+
+import a.b.c.MyEnum.Companion.foo
+
+enum class MyEnum(val id: Int) {
+ A(1),
+ B(2);
+
+ companion object {
+ fun foo() = ""
+ }
+}
+
+fun test() {
+ <expr>a.b.c.MyEnum.Companion.foo()</expr>
+}
+
+fun foo() = ""
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.txt
new file mode 100644
index 0000000..7b0784b
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.txt
@@ -0,0 +1,11 @@
+Before shortening: a.b.c.MyEnum.Companion.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.MyEnum
+[qualifier] a.b.c.MyEnum.Companion.foo()
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.MyEnum.Companion
+[qualifier] a.b.c.MyEnum.Companion.foo()
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.MyEnum.Companion
+[qualifier] a.b.c.MyEnum.Companion.foo()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.kt
new file mode 100644
index 0000000..a2a6aad
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.kt
@@ -0,0 +1,8 @@
+enum class C(val i: Int) {
+ ONE(<expr>C.K</expr>)
+ ;
+
+ companion object {
+ const val K = 1
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.txt
new file mode 100644
index 0000000..29ebe04
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.txt
@@ -0,0 +1,7 @@
+Before shortening: C.K
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+[qualifier] C.K
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] C.K
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt
new file mode 100644
index 0000000..93b19d1
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt
@@ -0,0 +1,8 @@
+enum class C(val i: Int) {
+ ONE(<expr>C.foo()</expr>)
+ ;
+
+ companion object {
+ fun foo() = 1
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.txt
new file mode 100644
index 0000000..2e2daec
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.txt
@@ -0,0 +1,7 @@
+Before shortening: C.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+[qualifier] C.foo()
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] C.foo()
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt
new file mode 100644
index 0000000..59429de
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt
@@ -0,0 +1,23 @@
+// FILE: main.kt
+package a.b.c
+
+fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+class Outer {
+ fun <E> E.foo(x: E, y: E, z: E) = x.hashCode() + y.hashCode() + z.hashCode()
+
+ class Inner {
+ fun foo(a: Int, b: Boolean, c: String) = c + a + b
+
+ fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c
+ return <expr>Inner.foo(1, false, "bar")</expr>
+ }
+
+ companion object {
+ fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.txt
new file mode 100644
index 0000000..b1016e6
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.txt
@@ -0,0 +1,5 @@
+Before shortening: Inner.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.kt
new file mode 100644
index 0000000..8d42d5a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.kt
@@ -0,0 +1,23 @@
+// FILE: main.kt
+package a.b.c
+
+fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+class Outer {
+ fun <E> E.foo(x: E, y: E, z: E) = x.hashCode() + y.hashCode() + z.hashCode()
+
+ class Inner {
+ fun foo(a: Int, b: Boolean, c: String) = c + a + b
+
+ fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: String) = a.hashCode() + b.hashCode() + c.hashCode()
+ return <expr>a.b.c.foo(1, false, "bar")</expr>
+ }
+
+ companion object {
+ fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.txt
new file mode 100644
index 0000000..41b28e1
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.txt
@@ -0,0 +1,5 @@
+Before shortening: a.b.c.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt
new file mode 100644
index 0000000..cf27594
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt
@@ -0,0 +1,23 @@
+// FILE: main.kt
+package a.b.c
+
+fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+class Outer {
+ fun <E> E.foo(x: E, y: E, z: E) = x.hashCode() + y.hashCode() + z.hashCode()
+
+ class Inner {
+ fun foo(a: Int, b: Boolean, c: String) = c + a + b
+
+ fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c
+ return <expr>Inner.Companion.foo(1, false, "bar")</expr>
+ }
+
+ companion object {
+ fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+ }
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.txt
new file mode 100644
index 0000000..0e1bd58
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.txt
@@ -0,0 +1,8 @@
+Before shortening: Inner.Companion.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Inner.Companion
+with SHORTEN_AND_IMPORT:
+[qualifier] Inner.Companion
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Inner.Companion
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt
new file mode 100644
index 0000000..cb123fe
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt
@@ -0,0 +1,13 @@
+// FILE: main.kt
+package test
+
+import dependency.T
+
+class T
+
+fun foo(t: <expr>test.T</expr>) {}
+
+// FILE: dep.kt
+package dependency
+
+class T
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.txt
new file mode 100644
index 0000000..a95d82a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.txt
@@ -0,0 +1,5 @@
+Before shortening: test.T
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.kt
new file mode 100644
index 0000000..8f8080c
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.kt
@@ -0,0 +1,17 @@
+// FILE: main.kt
+package a.b.c
+
+fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+object Receiver {
+ fun <E> E.foo(x: E, y: E, z: E) = x.hashCode() + y.hashCode() + z.hashCode()
+
+ fun foo(a: Int, b: Boolean, c: String) = a.hashCode() + b.hashCode() + c.hashCode()
+
+ fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: String) = a + b.hashCode() + c.hashCode()
+ return <expr>Receiver.foo(1, false, "bar")</expr>
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.txt
new file mode 100644
index 0000000..6767bb8
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.txt
@@ -0,0 +1,5 @@
+Before shortening: Receiver.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt
new file mode 100644
index 0000000..b5ee62e
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt
@@ -0,0 +1,18 @@
+// IGNORE_FIR
+// FILE: main.kt
+package a.b.c
+
+fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+object Receiver {
+ fun <E> E.foo(x: E, y: E, z: E) = x.hashCode() + y.hashCode() + z.hashCode()
+
+ fun foo(a: Int, b: Boolean, c: String) = a.hashCode() + b.hashCode() + c.hashCode()
+
+ fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c
+ return <expr>Receiver.foo(1, false, "bar")</expr>
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.txt
new file mode 100644
index 0000000..c531f64
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.txt
@@ -0,0 +1,8 @@
+Before shortening: Receiver.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Receiver.foo(1, false, "bar")
+with SHORTEN_AND_IMPORT:
+[qualifier] Receiver.foo(1, false, "bar")
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Receiver.foo(1, false, "bar")
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt
new file mode 100644
index 0000000..da734ee
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt
@@ -0,0 +1,18 @@
+// IGNORE_FIR
+// FILE: main.kt
+package a.b.c
+
+fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+object Receiver {
+ fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+ fun foo(a: Int, b: Boolean, c: String) = a.hashCode() + b.hashCode() + c.hashCode()
+
+ fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c
+ return <expr>Receiver.foo(1, false, "bar")</expr>
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.txt
new file mode 100644
index 0000000..41e5898
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.txt
@@ -0,0 +1,8 @@
+Before shortening: Receiver.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Receiver.foo(1, false, "bar")
+with SHORTEN_AND_IMPORT:
+[qualifier] Receiver.foo(1, false, "bar")
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Receiver.foo(1, false, "bar")
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.kt
new file mode 100644
index 0000000..4523c99
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.kt
@@ -0,0 +1,17 @@
+// FILE: main.kt
+package a.b.c
+
+fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+object Receiver {
+ fun <T, E, D> foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode()
+
+ fun foo(a: Int, b: Boolean, c: String) = a.hashCode() + b.hashCode() + c.hashCode()
+
+ fun test(): Int {
+ fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c
+ return <expr>a.b.c.foo(1, false, "bar")</expr>
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.txt
new file mode 100644
index 0000000..41b28e1
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.txt
@@ -0,0 +1,5 @@
+Before shortening: a.b.c.foo(1, false, "bar")
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.kt
new file mode 100644
index 0000000..068c244
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.kt
@@ -0,0 +1,35 @@
+// MODULE: commonMain
+// FILE: main.kt
+
+package a.b.c
+
+fun foo() {}
+
+class Outer {
+ fun foo() {}
+
+ class Inner {
+ fun foo() {}
+
+ class InnerOfInner {
+ fun foo() {}
+
+ private fun check() {
+ fun foo() {}
+ <expr>a.b.c.Outer.Inner.Companion.foo()</expr>
+ }
+
+ companion object {
+ fun foo() {}
+ }
+ }
+
+ companion object {
+ fun foo() {}
+ }
+ }
+
+ companion object {
+ fun foo() {}
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.txt
new file mode 100644
index 0000000..e77c037
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.txt
@@ -0,0 +1,8 @@
+Before shortening: a.b.c.Outer.Inner.Companion.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_IMPORT:
+[qualifier] a.b.c.Outer.Inner
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] a.b.c.Outer.Inner
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.kt
new file mode 100644
index 0000000..f25da13
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.kt
@@ -0,0 +1,8 @@
+// FILE: main.kt
+
+fun foo() {}
+
+fun test() {
+ fun foo(a: Int) = a + 1
+ <expr>foo()</expr>
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.txt
new file mode 100644
index 0000000..2fe6aac
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.txt
@@ -0,0 +1,5 @@
+Before shortening: foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.kt
new file mode 100644
index 0000000..2c5a976
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.kt
@@ -0,0 +1,13 @@
+package foo
+
+class Foo {
+ fun test() {
+ <expr>foo.myRun {
+ 42
+ }</expr>
+ }
+}
+
+inline fun <R> myRun(block: () -> R): R = block()
+
+inline fun <T, R> T.myRun(block: T.() -> R): R = block()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.txt
new file mode 100644
index 0000000..73e1f24
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.txt
@@ -0,0 +1,13 @@
+Before shortening: foo.myRun {
+ 42
+ }
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+[qualifier] foo.myRun {
+ 42
+ }
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] foo.myRun {
+ 42
+ }
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.kt
new file mode 100644
index 0000000..74f712a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.kt
@@ -0,0 +1,4 @@
+// FILE: main.kt
+package test
+
+<expr>fun foo(p1: dependency1.T, p2: dependency2.T) {}</expr>
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.txt
new file mode 100644
index 0000000..ffeaa6a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.txt
@@ -0,0 +1,5 @@
+Before shortening: fun foo(p1: dependency1.T, p2: dependency2.T) {}
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.kt
new file mode 100644
index 0000000..91457ef
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.kt
@@ -0,0 +1,16 @@
+// FILE: main.kt
+package a.b.c
+
+import dependency.T
+
+class T
+
+fun test() {
+ class T(a: Int)
+ <expr>dependency.T<Int>(3)</expr>
+}
+
+// FILE: dep.kt
+package dependency
+
+class T<E>(value: Int)
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.txt
new file mode 100644
index 0000000..2c8872a
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.txt
@@ -0,0 +1,8 @@
+Before shortening: dependency.T<Int>(3)
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] dependency.T<Int>(3)
+with SHORTEN_AND_IMPORT:
+[qualifier] dependency.T<Int>(3)
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] dependency.T<Int>(3)
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.kt
new file mode 100644
index 0000000..ddccc5b
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.kt
@@ -0,0 +1,15 @@
+// FILE: main.kt
+package a.b.c
+
+import dependency.T
+
+class T(a: Int)
+
+fun test() {
+ <expr>dependency.T::class.java</expr>
+}
+
+// FILE: dep.kt
+package dependency
+
+class T<E>(value: Int)
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.txt
new file mode 100644
index 0000000..97102da
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.txt
@@ -0,0 +1,8 @@
+Before shortening: dependency.T::class.java
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] dependency.T
+with SHORTEN_AND_IMPORT:
+[qualifier] dependency.T
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] dependency.T
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.kt
new file mode 100644
index 0000000..0ab454f7
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.kt
@@ -0,0 +1,20 @@
+// FILE: main.kt
+package a.b.c
+
+import dependency.foo
+
+fun foo() {}
+
+class Outer {
+ fun foo() {}
+ class Inner {
+ fun test() {
+ <expr>a.b.c.foo()</expr>
+ }
+ }
+}
+
+// FILE: dep.kt
+package dependency
+
+fun foo() {}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.txt
new file mode 100644
index 0000000..5f09124
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.txt
@@ -0,0 +1,5 @@
+Before shortening: a.b.c.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.kt
new file mode 100644
index 0000000..c2cf811
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.kt
@@ -0,0 +1,22 @@
+// FILE: main.kt
+package a.b.c
+
+import dependency.foo
+
+fun foo() {}
+
+class Outer {
+ class Inner {
+ fun test() {
+ <expr>Outer.Inner.foo()</expr>
+ }
+ companion object {
+ fun foo() {}
+ }
+ }
+}
+
+// FILE: dep.kt
+package dependency
+
+fun foo() {}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.txt
new file mode 100644
index 0000000..cf9ca64
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.txt
@@ -0,0 +1,11 @@
+Before shortening: Outer.Inner.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Outer.Inner
+[qualifier] Outer.Inner.foo()
+with SHORTEN_AND_IMPORT:
+[qualifier] Outer.Inner
+[qualifier] Outer.Inner.foo()
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Outer.Inner
+[qualifier] Outer.Inner.foo()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.kt
new file mode 100644
index 0000000..d10ab1b
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.kt
@@ -0,0 +1,23 @@
+// FILE: main.kt
+package a.b.c
+
+import dependency.foo
+
+fun foo() {}
+
+class Outer {
+ class Inner {
+ fun foo() {}
+ fun test() {
+ <expr>Outer.Inner.foo()</expr>
+ }
+ companion object {
+ fun foo() {}
+ }
+ }
+}
+
+// FILE: dep.kt
+package dependency
+
+fun foo() {}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.txt
new file mode 100644
index 0000000..b98b858
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.txt
@@ -0,0 +1,8 @@
+Before shortening: Outer.Inner.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Outer.Inner
+with SHORTEN_AND_IMPORT:
+[qualifier] Outer.Inner
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Outer.Inner
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.kt
new file mode 100644
index 0000000..ac05ffe
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.kt
@@ -0,0 +1,23 @@
+// FILE: main.kt
+package a.b.c
+
+import dependency.foo
+
+fun foo() {}
+
+open class Base {
+ companion object {
+ fun foo() {}
+ }
+}
+
+class Child : Base() {
+ fun test() {
+ <expr>Base.foo()</expr>
+ }
+}
+
+// FILE: dep.kt
+package dependency
+
+fun foo() {}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.txt
new file mode 100644
index 0000000..d532c32
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.txt
@@ -0,0 +1,8 @@
+Before shortening: Base.foo()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Base.foo()
+with SHORTEN_AND_IMPORT:
+[qualifier] Base.foo()
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Base.foo()
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.kt
new file mode 100644
index 0000000..ceb1484
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.kt
@@ -0,0 +1,14 @@
+// FILE: main.kt
+package my.simple.name
+
+fun one() {}
+
+open class Parent {
+ fun one() {}
+}
+
+class Child: Parent() {
+ fun test() {
+ <expr>my.simple.name.one()</expr>
+ }
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.txt
new file mode 100644
index 0000000..ef78548
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.txt
@@ -0,0 +1,5 @@
+Before shortening: my.simple.name.one()
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.kt
new file mode 100644
index 0000000..7c8d92b
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.kt
@@ -0,0 +1,9 @@
+// FILE: main.kt
+package a.b.c
+
+fun <T> foo(a: T, b: T) = a.hashCode() + b.hashCode()
+
+fun test(): Int {
+ fun foo(a: Int, b: Int) = a + b
+ return <expr>a.b.c.foo(1, 2)</expr>
+}
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.txt
new file mode 100644
index 0000000..dc70276
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.txt
@@ -0,0 +1,5 @@
+Before shortening: a.b.c.foo(1, 2)
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.kt
new file mode 100644
index 0000000..9bc268d
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.kt
@@ -0,0 +1,10 @@
+fun <T> foo(a: T, b: T) = a.hashCode() + b.hashCode()
+
+fun <E> E.foo() = hashCode()
+
+fun <E> E.foo(x: E, y: E) = x.hashCode() + y.hashCode()
+
+fun test(): Int {
+ fun foo(a: Int, b: Int) = a + b
+ return <expr>foo<Int>(1, 2)</expr>
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.txt
new file mode 100644
index 0000000..01f5394
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.txt
@@ -0,0 +1,5 @@
+Before shortening: foo<Int>(1, 2)
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.kt
new file mode 100644
index 0000000..2dcf960
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.kt
@@ -0,0 +1,17 @@
+// FILE: main.kt
+package a.b.c
+
+val foo = 3
+
+val <E> E.foo: Int
+ get() = 4
+
+object Receiver {
+ val foo: Int
+ get() = 5
+
+ fun test(): Int {
+ val foo = 6
+ return <expr>Receiver.foo</expr>
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.txt
new file mode 100644
index 0000000..776d791
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.txt
@@ -0,0 +1,5 @@
+Before shortening: Receiver.foo
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+with SHORTEN_AND_IMPORT:
+with SHORTEN_AND_STAR_IMPORT:
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.kt
new file mode 100644
index 0000000..67313cb
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.kt
@@ -0,0 +1,16 @@
+// FILE: main.kt
+package a.b.c
+
+val foo = 3
+
+val <E> E.foo: Int
+ get() = 4
+
+object Receiver {
+ val foo: Int
+ get() = 5
+
+ fun test(): Int {
+ return <expr>Receiver.foo</expr>
+ }
+}
diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.txt
new file mode 100644
index 0000000..0053082
--- /dev/null
+++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.txt
@@ -0,0 +1,8 @@
+Before shortening: Receiver.foo
+with DO_NOT_SHORTEN:
+with SHORTEN_IF_ALREADY_IMPORTED:
+[qualifier] Receiver.foo
+with SHORTEN_AND_IMPORT:
+[qualifier] Receiver.foo
+with SHORTEN_AND_STAR_IMPORT:
+[qualifier] Receiver.foo
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolver/AllCandidatesResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolver/AllCandidatesResolver.kt
index cc60ae2..5e96867 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolver/AllCandidatesResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolver/AllCandidatesResolver.kt
@@ -13,7 +13,6 @@
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
-import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.calls.InapplicableCandidate
@@ -61,16 +60,16 @@
fun getAllCandidates(
firResolveSession: LLFirResolveSession,
- functionCall: FirFunctionCall,
+ qualifiedAccess: FirQualifiedAccess,
calleeName: Name,
- element: KtElement
+ element: KtElement,
): List<OverloadCandidate> {
initializeBodyResolveContext(firResolveSession, element)
val firFile = element.containingKtFile.getOrBuildFirFile(firResolveSession)
return bodyResolveComponents.context.withFile(firFile, bodyResolveComponents) {
bodyResolveComponents.callResolver
- .collectAllCandidates(functionCall, calleeName, bodyResolveComponents.context.containers, resolutionContext)
+ .collectAllCandidates(qualifiedAccess, calleeName, bodyResolveComponents.context.containers, resolutionContext)
.apply { postProcessCandidates() }
}
}
@@ -127,4 +126,4 @@
candidate.addDiagnostic(InapplicableCandidate)
}
-}
\ No newline at end of file
+}
diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt
index 2010b0f..2e22877 100644
--- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt
+++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt
@@ -231,6 +231,13 @@
contextReceiverGroup?.map { it.createSnapshot() },
isLocal,
)
+
+ /**
+ * Returns [scope] if it is not null. Otherwise, returns [implicitReceiver.implicitScope].
+ *
+ * Note that a scope for a companion object is an implicit scope.
+ */
+ fun getAvailableScope() = scope ?: implicitReceiver?.implicitScope
}
fun ImplicitReceiverValue<*>.asTowerDataElement(): FirTowerDataElement =
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 5d01f9b..d74c299 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
@@ -41,6 +41,7 @@
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeProvider.AbstractAnalysisApiGetSuperTypesTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeProvider.AbstractHasCommonSubtypeTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceResolveTest
+import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractReferenceShortenerTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.scopes.*
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.AbstractSingleSymbolByPsi
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.AbstractSymbolByFqNameTest
@@ -223,6 +224,12 @@
}
}
+ component("referenceShortener", filter = frontendIs(FrontendKind.Fir) and analysisSessionModeIs(AnalysisSessionMode.Normal)) {
+ test(AbstractReferenceShortenerTest::class) {
+ model("referenceShortener")
+ }
+ }
+
component("expressionTypeProvider") {
test(AbstractExpectedExpressionTypeTest::class) {
model("expectedExpressionType")