From a09d0aa1cf13544cd0c50c88100eff5d6b10fec9 Mon Sep 17 00:00:00 2001 From: Jaebaek Seo Date: Wed, 25 Jan 2023 02:17:38 +0100 Subject: [PATCH] Handle SHORTEN_IF_ALEADY_IMPORTED case of KtFirReferenceShortener For the following example, when we run the reference shortener, it drops `a.b.c` qualifier, because it matches "FOURTH". ``` package a.b.c fun foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() // FIRST fun E.foo() = hashCode() // SECOND object Receiver { fun foo(a: T, b: E, c: D) = a.hashCode() + b.hashCode() + c.hashCode() // THIRD fun foo(a: Int, b: Boolean, c: String) = a.hashCode() + b.hashCode() + c.hashCode() // FOURTH fun test(): Int { fun foo(a: Int, b: Boolean, c: Int) = a + b.hashCode() + c // FIFTH return a.b.c.foo(1, false, "bar") } } ``` As shown in the above example, when SHORTEN_IF_ALEADY_IMPORTED option is given from a user, the reference shortener has to check whether it can drop the qualifier without changing the referenced symbol and if it is possible to do that without adding a new import directive, it deletes the qualifier. It needs two steps: 1. Collect all candidate symbols matching the signature e.g., function arguments / type arguments 2. Determine whether the referenced symbol has the highest reference priority when we drops the qualifier depending on scopes This commit uses `AllCandidatesResolver(shorteningContext.analysisSession.useSiteSession). getAllCandidates( .. fake FIR call/property-access ..)` for step1. For step2, we use a heuristic based on scopes of candidates. If a candidate symbol is under the same scope with the target expression, it has a `FirLocalScope` which has the high priority. So when we have a candidate under a `FirLocalScope` and the actual referenced symbol is different from the candidate, we must avoid dropping its qualifier because the shortening will change its semantics i.e., reference. The order of scopes depending on their scope types is: 1. FirLocalScope 2. FirClassUseSiteMemberScope / FirNestedClassifierScope 3. FirExplicitSimpleImportingScope 4. FirPackageMemberScope 5. others Note that for "others" the above rule can be wrong. Please update it if you find other scopes that have a priority higher than the specified scopes. One of non-trivial parts is the priority among multiple FirClassUseSiteMemberScope and FirNestedClassifierScope. They are basically scopes for class declarations. We decide their priorities based on the distance of class declaration from the target expression. Note that we take a strict approach to reject all false positive. For example, when we are not sure, we don't shorten it to avoid changing its semantics. TODO: One corner case is handling receivers. We have to update ``` private fun shortenIfAlreadyImported( firQualifiedAccess: FirQualifiedAccess, calledSymbol: FirCallableSymbol<*>, expressionInScope: KtExpression, ): Boolean ``` The current implementation cannot handle the following example: ``` package foo class Foo { fun test() { // It references FIRST. Removing `foo` lets it reference SECOND. foo.myRun { 42 } } } inline fun myRun(block: () -> R): R = block() // FIRST inline fun T.myRun(block: T.() -> R): R = block() // SECOND ``` Tests related to TODO: - analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt - analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt --- .../components/KtFe10ReferenceShortener.kt | 9 +- .../fir/components/KtFirReferenceShortener.kt | 484 ++++++++++++++++-- ...ModuleReferenceShortenerTestGenerated.java | 318 ++++++++++++ .../AbstractReferenceShortenerTest.kt | 53 ++ ...ModuleReferenceShortenerTestGenerated.java | 318 ++++++++++++ .../api/components/KtReferenceShortener.kt | 37 +- .../referenceShortener/classScopes.kt | 22 + .../referenceShortener/classScopes.txt | 8 + .../referenceShortener/classScopes2.kt | 22 + .../referenceShortener/classScopes2.txt | 11 + .../referenceShortener/classScopes3.kt | 28 + .../referenceShortener/classScopes3.txt | 8 + .../referenceShortener/classType.kt | 13 + .../referenceShortener/classType.txt | 8 + .../referenceShortener/classType2.kt | 12 + .../referenceShortener/classType2.txt | 8 + .../referenceShortener/classesWithSameName.kt | 14 + .../classesWithSameName.txt | 7 + .../classesWithSameName2.kt | 13 + .../classesWithSameName2.txt | 8 + .../classesWithSameName3.kt | 13 + .../classesWithSameName3.txt | 8 + .../classesWithSameName4.kt | 16 + .../classesWithSameName4.txt | 8 + .../classesWithSameName5.kt | 16 + .../classesWithSameName5.txt | 8 + .../classesWithSameName6.kt | 15 + .../classesWithSameName6.txt | 8 + .../classesWithSameName7.kt | 15 + .../classesWithSameName7.txt | 8 + .../classesWithSameName8.kt | 17 + .../classesWithSameName8.txt | 8 + .../classesWithSameName9.kt | 13 + .../classesWithSameName9.txt | 8 + .../companionClassLiteral.kt | 13 + .../companionClassLiteral.txt | 8 + .../companionClassLiteral2.kt | 13 + .../companionClassLiteral2.txt | 8 + .../companionClassLiteral3.kt | 13 + .../companionClassLiteral3.txt | 8 + .../referenceShortener/companionQualifier.kt | 19 + .../referenceShortener/companionQualifier.txt | 8 + .../companionUsedOutOfClass.kt | 14 + .../companionUsedOutOfClass.txt | 8 + .../enumClassCompanionAlreadyImported.kt | 18 + .../enumClassCompanionAlreadyImported.txt | 11 + .../enumEntryInitUsesCompanion.kt | 8 + .../enumEntryInitUsesCompanion.txt | 7 + .../enumEntryInitUsesCompanion2.kt | 8 + .../enumEntryInitUsesCompanion2.txt | 7 + .../referenceShortener/nestedClass.kt | 23 + .../referenceShortener/nestedClass.txt | 5 + .../referenceShortener/nestedClass2.kt | 23 + .../referenceShortener/nestedClass2.txt | 5 + .../referenceShortener/nestedClass3.kt | 23 + .../referenceShortener/nestedClass3.txt | 8 + .../parameterTypeTopLevelTypeLoses.kt | 13 + .../parameterTypeTopLevelTypeLoses.txt | 5 + .../referenceShortener/receiver.kt | 17 + .../referenceShortener/receiver.txt | 5 + .../referenceShortener/receiver2.kt | 18 + .../referenceShortener/receiver2.txt | 8 + .../referenceShortener/receiver3.kt | 18 + .../referenceShortener/receiver3.txt | 8 + .../referenceShortener/receiver4.kt | 17 + .../referenceShortener/receiver4.txt | 5 + .../referenceInNestedClass.kt | 35 ++ .../referenceInNestedClass.txt | 8 + .../sameNameDifferentParams.kt | 8 + .../sameNameDifferentParams.txt | 5 + .../sameNameDifferentReceiver.kt | 13 + .../sameNameDifferentReceiver.txt | 13 + .../sameTypeNamesWithinSameScopes.kt | 4 + .../sameTypeNamesWithinSameScopes.txt | 5 + .../shortenAlreadyImportedClass.kt | 16 + .../shortenAlreadyImportedClass.txt | 8 + .../shortenAlreadyImportedClass2.kt | 15 + .../shortenAlreadyImportedClass2.txt | 8 + .../shortenAlreadyImportedFunction.kt | 20 + .../shortenAlreadyImportedFunction.txt | 5 + .../shortenAlreadyImportedFunction2.kt | 22 + .../shortenAlreadyImportedFunction2.txt | 11 + .../shortenAlreadyImportedFunction3.kt | 23 + .../shortenAlreadyImportedFunction3.txt | 8 + .../shortenAlreadyImportedFunction4.kt | 23 + .../shortenAlreadyImportedFunction4.txt | 8 + .../referenceShortener/superClass.kt | 14 + .../referenceShortener/superClass.txt | 5 + .../referenceShortener/typeParams.kt | 9 + .../referenceShortener/typeParams.txt | 5 + .../referenceShortener/typeParams2.kt | 10 + .../referenceShortener/typeParams2.txt | 5 + .../referenceShortener/variable.kt | 17 + .../referenceShortener/variable.txt | 5 + .../referenceShortener/variable2.kt | 16 + .../referenceShortener/variable2.txt | 8 + .../api/fir/resolver/AllCandidatesResolver.kt | 10 +- .../fir/declarations/ImplicitReceiverUtils.kt | 7 + .../tests/analysis/api/analysisApi.kt | 7 + 99 files changed, 2265 insertions(+), 45 deletions(-) create mode 100644 analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java create mode 100644 analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/references/AbstractReferenceShortenerTest.kt create mode 100644 analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classScopes3.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classType2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName3.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName4.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName5.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName6.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName7.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName8.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/classesWithSameName9.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionClassLiteral3.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionQualifier.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumClassCompanionAlreadyImported.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/enumEntryInitUsesCompanion2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClass3.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/parameterTypeTopLevelTypeLoses.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver3.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/receiver4.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/referenceInNestedClass.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentParams.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameNameDifferentReceiver.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/sameTypeNamesWithinSameScopes.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedClass2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction3.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/shortenAlreadyImportedFunction4.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/superClass.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/typeParams2.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/variable2.txt 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")