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 2dba2e80077..8711f842437 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 @@ internal class KtFe10ReferenceShortener( override val isEmpty: Boolean get() = true + override fun getTypesToShorten(): List> = emptyList() + + override fun getQualifiersToShorten(): List> = 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 94262b6fd9e..d8266e72870 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,23 +5,25 @@ 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.* @@ -29,14 +31,16 @@ import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol 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.expressions.FirQualifiedAccessExpression 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.getProperties 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 @@ internal class KtFirReferenceShortener( val declarationToVisit = file.findSmallestDeclarationContainingSelection(selection) ?: file.withDeclarationsResolvedToBodyResolve() - val firDeclaration = declarationToVisit.getOrBuildFirOfType(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 class FirShorteningContext(val analysisSession: KtFirAnalysisSession) { private val firSession: FirSession get() = firResolveSession.useSiteFirSession + class ClassifierCandidate(val scope: FirScope, val availableSymbol: AvailableSymbol) + fun findFirstClassifierInScopesByName(positionScopes: List, targetClassName: Name): AvailableSymbol? { for (scope in positionScopes) { val classifierSymbol = scope.findFirstClassifierByName(targetClassName) ?: continue @@ -180,11 +185,26 @@ private class FirShorteningContext(val analysisSession: KtFirAnalysisSession) { return null } - fun findFunctionsInScopes(scopes: List, name: Name): List> { + fun findClassifiersInScopesByName(scopes: List, targetClassName: Name): List = + 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, name: Name): List>> { 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() + }?.forEach { add(AvailableSymbol(it, importKind)) } + + // Collect functions + addAll(scope.getFunctions(name).map { AvailableSymbol(it, importKind) }) } } } @@ -217,7 +237,10 @@ private class FirShorteningContext(val analysisSession: KtFirAnalysisSession) { ): List? { 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 class ElementsToShortenCollector( ) } - private inline fun findClassifierElementsToShorten( + /** + * Returns true if the class symbol has a type parameter that is supposed to be provided for its parent class. + * + * Example: + * class Outer { + * 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 in the order from the closest: + * // scope2 -> scope3 -> scope1 + * + * } + * 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? { + 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 in the order from the closest: + * // scope5 -> scope4 -> scope6 -> scope3 -> scope1 -> scope2 + * + * + * } + * 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 and [base] are surrounding [from], returns whether an element of + * this List is closer than [base] based on the distance from [from]. + */ + private fun List.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, + ): 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? FirQualifiedAccessExpression + 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 findClassifierElementsToShorten( positionScopes: List, allClassIds: Sequence, allQualifiedElements: Sequence, 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 @@ private class ElementsToShortenCollector( return findFakePackageToShortenFn(allQualifiedElements.last()) } + private fun resolveUnqualifiedAccess( + fullyQualifiedAccess: FirQualifiedAccessExpression, + name: Name, + expressionInScope: KtExpression, + ): List { + val fakeCalleeReference = buildSimpleNamedReference { this.name = name } + val functionCall = fullyQualifiedAccess as? FirFunctionCall + val fakeFirQualifiedAccess: FirQualifiedAccessExpression? + 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 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, + typeArguments: List, + name: Name, + elementInScope: KtElement, + ): List { + 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.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(C.K) // C.ONE uses C.K for initialization + * ; + * companion object { + * const val K = 1 + * } + * } + */ + private fun KtExpression.isCompanionMemberUsedForEnumEntryInit(resolvedSymbol: FirCallableSymbol<*>): Boolean { + val enumEntry = getNonStrictParentOfType() ?: 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: FirQualifiedAccessExpression, + 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(C.K) // 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. + * foo.myRun { + * 42 + * } + * } + * } + * inline fun myRun(block: () -> R): R = block() // FIRST + * inline fun 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? FirQualifiedAccessExpression ?: 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 @@ private class ElementsToShortenCollector( 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, Name) -> List>>, + availableCallables: List>>, ) { - 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 ElementsToShortenCollector( } private class ShortenCommandImpl( - val targetFile: SmartPsiElementPointer, - val importsToAdd: List, - val starImportsToAdd: List, - val typesToShorten: List>, - val qualifiersToShorten: List>, + private val targetFile: SmartPsiElementPointer, + private val importsToAdd: List, + private val starImportsToAdd: List, + private val typesToShorten: List>, + private val qualifiersToShorten: List>, ) : ShortenCommand { override fun invokeShortening() { @@ -643,6 +1051,10 @@ private class ShortenCommandImpl( } override val isEmpty: Boolean get() = typesToShorten.isEmpty() && qualifiersToShorten.isEmpty() + + override fun getTypesToShorten(): List> = typesToShorten + + override fun getQualifiersToShorten(): List> = qualifiersToShorten } private fun KtUserType.hasFakeRootPrefix(): Boolean = @@ -657,4 +1069,4 @@ internal fun KtElement.getDotQualifiedExpressionForSelector(): KtDotQualifiedExp 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 00000000000..770525932d9 --- /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 00000000000..03057b34194 --- /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 and in the first file. + */ +abstract class AbstractReferenceShortenerTest : AbstractAnalysisApiBasedSingleModuleTest() { + override fun doTestByFileStructure(ktFiles: List, 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 00000000000..a74cddec90e --- /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 a8fd973c4a2..c0bd6053adf 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 KtReferenceShortenerMixIn : KtAnalysisSessionMixIn { public interface ShortenCommand { public fun invokeShortening() public val isEmpty: Boolean + public fun getTypesToShorten(): List> + public fun getQualifiersToShorten(): List> } \ 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 00000000000..60e9a410909 --- /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() { + my.simple.name.SuperClass.check() + } + + 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 00000000000..3e515fa295d --- /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 00000000000..187e379cb0f --- /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() { + Child.Foo.check() + } + + 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 00000000000..ca2e835b02d --- /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 00000000000..c2da4f128da --- /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() { + my.simple.name.ClassFarAway.check() + } + + 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 00000000000..70aac6dedd5 --- /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 00000000000..8a9810a5aa0 --- /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 a.b.c.Outer.Inner::class.java +} \ 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 00000000000..5dde274cc36 --- /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 00000000000..8251fb393ce --- /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 a.b.c.Outer.Middle.Inner::class.java + } + } + } +} \ 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 00000000000..552a4e3c3e4 --- /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 00000000000..353e38789e4 --- /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 a.b.c.Outer.Inner::class.java +} \ 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 00000000000..387f95e1592 --- /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 00000000000..af2e8609349 --- /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 a.b.c.Outer.Inner::class.java + } + 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 00000000000..2ef84e4a6e4 --- /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 00000000000..f5c87c636dc --- /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 a.b.c.Outer.Inner::class.java + } + 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 00000000000..2ef84e4a6e4 --- /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 00000000000..d56dd597c1f --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} 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 00000000000..70897b9f27c --- /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 00000000000..a5b10ebafd4 --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} 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 00000000000..70897b9f27c --- /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 00000000000..657b66b0fdf --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} 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 00000000000..70897b9f27c --- /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 00000000000..7f8981d7ead --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} 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 00000000000..70897b9f27c --- /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 00000000000..0c363ed728a --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} 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 00000000000..a914b258f86 --- /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 00000000000..5dfc84c493e --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} 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 00000000000..6790369e93d --- /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 00000000000..cd0f5567500 --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} \ 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 00000000000..a914b258f86 --- /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 00000000000..adfa4ff6483 --- /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 = foo.www.ddd.Check.BBD.Bwd::class.java.annotatedInterfaces.size + } + } + } +} \ 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 00000000000..a914b258f86 --- /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 00000000000..b3c4be0cc78 --- /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 = foo.www.ddd.Check.BBD.Companion::class.java.annotatedInterfaces.size + } + } + } +} \ 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 00000000000..4b4ed3fcd82 --- /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 00000000000..afe4d50eaf9 --- /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.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 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 a.b.c.Outer.Inner.Companion.foo(1, false, "bar") +} \ 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 00000000000..11525009fe0 --- /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 00000000000..73bb9cd0b67 --- /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() { + a.b.c.MyClass.Companion.foo() +} + +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 00000000000..44c68ec071e --- /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 00000000000..15cd0122c5d --- /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() { + a.b.c.MyEnum.Companion.foo() +} + +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 00000000000..7b0784b6498 --- /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 00000000000..a2a6aad5361 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.kt @@ -0,0 +1,8 @@ +enum class C(val i: Int) { + ONE(C.K) + ; + + 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 00000000000..29ebe0469e7 --- /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 00000000000..93b19d1f601 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt @@ -0,0 +1,8 @@ +enum class C(val i: Int) { + ONE(C.foo()) + ; + + 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 00000000000..2e2daec09f5 --- /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 00000000000..59429dec3ab --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt @@ -0,0 +1,23 @@ +// FILE: main.kt +package a.b.c + +fun foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() + +fun E.foo() = hashCode() + +class Outer { + fun 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 Inner.foo(1, false, "bar") + } + + companion object { + fun 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 00000000000..b1016e6a490 --- /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 00000000000..8d42d5aa43b --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.kt @@ -0,0 +1,23 @@ +// FILE: main.kt +package a.b.c + +fun foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() + +fun E.foo() = hashCode() + +class Outer { + fun 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 a.b.c.foo(1, false, "bar") + } + + companion object { + fun 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 00000000000..41b28e14349 --- /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 00000000000..cf275948eb3 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt @@ -0,0 +1,23 @@ +// FILE: main.kt +package a.b.c + +fun foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() + +fun E.foo() = hashCode() + +class Outer { + fun 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 Inner.Companion.foo(1, false, "bar") + } + + companion object { + fun 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 00000000000..0e1bd58dfa3 --- /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 00000000000..cb123fec241 --- /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: test.T) {} + +// 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 00000000000..a95d82afdd6 --- /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 00000000000..8f8080c1f09 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.kt @@ -0,0 +1,17 @@ +// FILE: main.kt +package a.b.c + +fun foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() + +fun E.foo() = hashCode() + +object Receiver { + fun 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 Receiver.foo(1, false, "bar") + } +} 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 00000000000..6767bb8384f --- /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 00000000000..b5ee62ea734 --- /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 foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() + +fun E.foo() = hashCode() + +object Receiver { + fun 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 Receiver.foo(1, false, "bar") + } +} \ 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 00000000000..c531f641692 --- /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 00000000000..da734ee83aa --- /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 foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() + +fun E.foo() = hashCode() + +object Receiver { + fun 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 Receiver.foo(1, false, "bar") + } +} \ 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 00000000000..41e58988241 --- /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 00000000000..4523c990254 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.kt @@ -0,0 +1,17 @@ +// FILE: main.kt +package a.b.c + +fun foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() + +fun E.foo() = hashCode() + +object Receiver { + fun 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 a.b.c.foo(1, false, "bar") + } +} 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 00000000000..41b28e14349 --- /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 00000000000..068c244cb3d --- /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() {} + a.b.c.Outer.Inner.Companion.foo() + } + + 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 00000000000..e77c0373736 --- /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 00000000000..f25da13ffd3 --- /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 + foo() +} \ 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 00000000000..2fe6aacbe68 --- /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 00000000000..2c5a976787d --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.kt @@ -0,0 +1,13 @@ +package foo + +class Foo { + fun test() { + foo.myRun { + 42 + } + } +} + +inline fun myRun(block: () -> R): R = block() + +inline fun 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 00000000000..73e1f24ec19 --- /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 00000000000..74f712afc82 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.kt @@ -0,0 +1,4 @@ +// FILE: main.kt +package test + +fun foo(p1: dependency1.T, p2: dependency2.T) {} \ 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 00000000000..ffeaa6a4149 --- /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 00000000000..91457ef9632 --- /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) + dependency.T(3) +} + +// FILE: dep.kt +package dependency + +class T(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 00000000000..2c8872a894e --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.txt @@ -0,0 +1,8 @@ +Before shortening: dependency.T(3) +with DO_NOT_SHORTEN: +with SHORTEN_IF_ALREADY_IMPORTED: +[qualifier] dependency.T(3) +with SHORTEN_AND_IMPORT: +[qualifier] dependency.T(3) +with SHORTEN_AND_STAR_IMPORT: +[qualifier] dependency.T(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 00000000000..ddccc5b58e7 --- /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() { + dependency.T::class.java +} + +// FILE: dep.kt +package dependency + +class T(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 00000000000..97102dad68f --- /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 00000000000..0ab454f7594 --- /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() { + a.b.c.foo() + } + } +} + +// 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 00000000000..5f09124147a --- /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 00000000000..c2cf811d2ed --- /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() { + Outer.Inner.foo() + } + 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 00000000000..cf9ca641e97 --- /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 00000000000..d10ab1b8e55 --- /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() { + Outer.Inner.foo() + } + 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 00000000000..b98b8584a31 --- /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 00000000000..ac05ffe5f17 --- /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() { + Base.foo() + } +} + +// 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 00000000000..d532c32cccb --- /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 00000000000..ceb1484d683 --- /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() { + my.simple.name.one() + } +} \ 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 00000000000..ef78548eab9 --- /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 00000000000..7c8d92b2a16 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.kt @@ -0,0 +1,9 @@ +// FILE: main.kt +package a.b.c + +fun foo(a: T, b: T) = a.hashCode() + b.hashCode() + +fun test(): Int { + fun foo(a: Int, b: Int) = a + b + return a.b.c.foo(1, 2) +} \ 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 00000000000..dc7027644ab --- /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 00000000000..9bc268dab1e --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.kt @@ -0,0 +1,10 @@ +fun foo(a: T, b: T) = a.hashCode() + b.hashCode() + +fun E.foo() = hashCode() + +fun E.foo(x: E, y: E) = x.hashCode() + y.hashCode() + +fun test(): Int { + fun foo(a: Int, b: Int) = a + b + return foo(1, 2) +} 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 00000000000..01f5394897e --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.txt @@ -0,0 +1,5 @@ +Before shortening: foo(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 00000000000..2dcf9606b2c --- /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.foo: Int + get() = 4 + +object Receiver { + val foo: Int + get() = 5 + + fun test(): Int { + val foo = 6 + return Receiver.foo + } +} 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 00000000000..776d7912112 --- /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 00000000000..67313cb7afb --- /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.foo: Int + get() = 4 + +object Receiver { + val foo: Int + get() = 5 + + fun test(): Int { + return Receiver.foo + } +} 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 00000000000..0053082cbb1 --- /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 3681a8f1723..92bfbc34607 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,7 @@ import org.jetbrains.kotlin.fir.* 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.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.calleeReference import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.calls.InapplicableCandidate @@ -61,16 +61,16 @@ class AllCandidatesResolver(private val firSession: FirSession) { fun getAllCandidates( firResolveSession: LLFirResolveSession, - functionCall: FirFunctionCall, + qualifiedAccess: FirQualifiedAccessExpression, calleeName: Name, - element: KtElement + element: KtElement, ): List { 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 +127,4 @@ class AllCandidatesResolver(private val firSession: FirSession) { 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 fcee6805914..6be2f2af465 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 @@ -234,6 +234,13 @@ class FirTowerDataElement( isLocal, staticScopeOwnerSymbol ) + + /** + * 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 28f94e5bc96..6683a7eaf9f 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 @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.components.typeInf 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 @@ -237,6 +238,12 @@ private fun AnalysisApiTestGroup.generateAnalysisApiComponentsTests() { } } + component("referenceShortener", filter = frontendIs(FrontendKind.Fir) and analysisSessionModeIs(AnalysisSessionMode.Normal)) { + test(AbstractReferenceShortenerTest::class) { + model("referenceShortener") + } + } + component("expressionTypeProvider") { test(AbstractExpectedExpressionTypeTest::class) { model("expectedExpressionType")