From 44d48510b449e02a2dd552f842033d2b95a6788d Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Mon, 23 Oct 2023 22:42:29 +0200 Subject: [PATCH] KTIJ-26057 [AA] Ignore implicit receivers scope when dealing with types in reference shortener Implicit receivers generally do not affect the resolution of types. However, they generate scopes which might contain undesirable classifiers, which can confuse reference shortener. Dropping all the implicit receivers when dealing with type references allows completely avoid such undesirable scopes instead of filtering them by `instanceof` checks. Also, temporary move `hasTypeParameterFromParent` check higher to the `findClassifierElementsToShorten`, because ATM we don't know how to properly decide whether to shorten the fully-qualified inner types with implicit parameters or not (see KTIJ-26072). ^KTIJ-26057 Fixed --- .../fir/components/KtFirReferenceShortener.kt | 47 +++++++++---------- ...ModuleReferenceShortenerTestGenerated.java | 12 +++++ ...ModuleReferenceShortenerTestGenerated.java | 12 +++++ ...nericsAsExtensionReceiverType_innerType.kt | 7 +++ ...ericsAsExtensionReceiverType_innerType.txt | 5 ++ ...ericsAsExtensionReceiverType_nestedType.kt | 7 +++ ...ricsAsExtensionReceiverType_nestedType.txt | 7 +++ 7 files changed, 71 insertions(+), 26 deletions(-) create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.txt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.txt 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 da1d15003e0..b905bb64a7b 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 @@ -39,7 +39,6 @@ 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.java.scopes.JavaClassMembersEnhancementScope import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference @@ -320,15 +319,21 @@ private class FirShorteningContext(val analysisSession: KtFirAnalysisSession) { fun findScopesAtPosition( position: KtElement, newImports: Sequence, - towerContextProvider: FirTowerContextProvider + towerContextProvider: FirTowerContextProvider, + withImplicitReceivers: Boolean = true, ): List? { val towerDataContext = towerContextProvider.getClosestAvailableParentContext(position) ?: return null - val result = buildList { - addAll(towerDataContext.nonLocalTowerDataElements.flatMap { + val nonLocalScopes = towerDataContext.nonLocalTowerDataElements + .asSequence() + .filter { withImplicitReceivers || it.implicitReceiver == null } + .flatMap { // We must use `it.getAvailableScopes()` instead of `it.scope` to check scopes of companion objects // and context receivers as well. it.getAvailableScopes() - }) + } + + val result = buildList { + addAll(nonLocalScopes) addIfNotNull(createFakeImportingScope(newImports)) addAll(towerDataContext.localScopes) } @@ -552,8 +557,13 @@ private class ElementsToShortenCollector( wholeClassQualifier: ClassId, wholeQualifierElement: KtElement, ): ElementToShorten? { - val positionScopes: List = - shorteningContext.findScopesAtPosition(wholeQualifierElement, getNamesToImport(), towerContextProvider) ?: return null + val positionScopes = shorteningContext.findScopesAtPosition( + wholeQualifierElement, + getNamesToImport(), + towerContextProvider, + withImplicitReceivers = false, + ) ?: return null + val allClassIds = wholeClassQualifier.outerClassesWithSelf val allQualifiers = wholeQualifierElement.qualifiedElementsWithSelf return findClassifierElementsToShorten( @@ -731,26 +741,8 @@ private class ElementsToShortenCollector( classId: ClassId, element: KtElement, classSymbol: FirClassLikeSymbol<*>, - positionScopes: List, + scopes: 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 - - /** - * Class use-site member scopes may contain classifiers which are not actually available without explicit import. - * And if the class is declared in Java, it can be represented with JavaClassMembersEnhancementScope. - */ - val scopes = positionScopes.filter { - when (it) { - // KTIJ-24684, KTIJ-24662 - is FirClassUseSiteMemberScope -> false - // KTIJ-26785 - is JavaClassMembersEnhancementScope -> false - - else -> true - } - } - val name = classId.shortClassName val availableClassifiers = shorteningContext.findClassifiersInScopesByName(scopes, name) val matchingAvailableSymbol = availableClassifiers.firstOrNull { it.availableSymbol.symbol.classIdIfExists == classId } @@ -788,6 +780,9 @@ private class ElementsToShortenCollector( val option = classShortenOption(classSymbol) if (option == ShortenOption.DO_NOT_SHORTEN) continue + // If its parent has a type parameter, we do not shorten it ATM because it will lose its type parameter. See KTIJ-26072 + if (classSymbol.hasTypeParameterFromParent()) continue + if (shortenClassifierIfAlreadyImported(classId, element, classSymbol, positionScopes)) { return createElementToShorten(element, null, false) } diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java index ea778944908..cd51f691621 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/references/FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java @@ -643,6 +643,18 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/nestedClassFromSupertypes6_java.kt"); } + @Test + @TestMetadata("TypeWithGenericsAsExtensionReceiverType_innerType.kt") + public void testTypeWithGenericsAsExtensionReceiverType_innerType() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.kt"); + } + + @Test + @TestMetadata("TypeWithGenericsAsExtensionReceiverType_nestedType.kt") + public void testTypeWithGenericsAsExtensionReceiverType_nestedType() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.kt"); + } + @Nested @TestMetadata("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classHeaderPositions") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java index ab996f39ded..142e614a7c2 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/references/FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenerated.java @@ -643,6 +643,18 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/nestedClassFromSupertypes6_java.kt"); } + @Test + @TestMetadata("TypeWithGenericsAsExtensionReceiverType_innerType.kt") + public void testTypeWithGenericsAsExtensionReceiverType_innerType() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.kt"); + } + + @Test + @TestMetadata("TypeWithGenericsAsExtensionReceiverType_nestedType.kt") + public void testTypeWithGenericsAsExtensionReceiverType_nestedType() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.kt"); + } + @Nested @TestMetadata("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/classHeaderPositions") @TestDataPath("$PROJECT_ROOT") diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.kt new file mode 100644 index 00000000000..68658f7116e --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.kt @@ -0,0 +1,7 @@ +package test + +class Outer { + inner class Inner +} + +fun Outer.test(p: Outer.Inner) {} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.txt new file mode 100644 index 00000000000..9a71427afd8 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_innerType.txt @@ -0,0 +1,5 @@ +Before shortening: Outer.Inner +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/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.kt new file mode 100644 index 00000000000..91d979faf2b --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.kt @@ -0,0 +1,7 @@ +package test + +class Outer { + class Nested +} + +fun Outer.test(p: Outer.Nested) {} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.txt new file mode 100644 index 00000000000..cea78ad2998 --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/nestedClasses/TypeWithGenericsAsExtensionReceiverType_nestedType.txt @@ -0,0 +1,7 @@ +Before shortening: Outer.Nested +with DO_NOT_SHORTEN: +with SHORTEN_IF_ALREADY_IMPORTED: +with SHORTEN_AND_IMPORT: +[type] Outer.Nested +with SHORTEN_AND_STAR_IMPORT: +[type] Outer.Nested