From d89d774411de2faef5b3f77da49abf8c064fa291 Mon Sep 17 00:00:00 2001 From: aleksandrina-streltsova Date: Sun, 26 Feb 2023 21:48:39 +0200 Subject: [PATCH] [AA] Consider context receivers in FirTowerDataElement.getAvailableScope --- .../fir/components/KtFirReferenceShortener.kt | 7 ++++--- ...ModuleReferenceShortenerTestGenerated.java | 6 ++++++ ...ModuleReferenceShortenerTestGenerated.java | 6 ++++++ .../referenceShortener/contextReceiver.kt | 12 +++++++++++ .../referenceShortener/contextReceiver.txt | 5 +++++ .../kotlin/fir/resolve/calls/FirReceivers.kt | 4 ++++ .../fir/declarations/ImplicitReceiverUtils.kt | 21 +++++++++++++++++-- 7 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.kt create mode 100644 analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.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 ef3931c8933..e6b6e499468 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 @@ -236,9 +236,10 @@ private class FirShorteningContext(val analysisSession: KtFirAnalysisSession) { ): List? { val towerDataContext = towerContextProvider.getClosestAvailableParentContext(position) ?: return null val result = buildList { - addAll(towerDataContext.nonLocalTowerDataElements.mapNotNull { - // We must use `it.getAvailableScope()` instead of `it.scope` to check scopes of companion objects as well. - it.getAvailableScope() + addAll(towerDataContext.nonLocalTowerDataElements.flatMap { + // We must use `it.getAvailableScopes()` instead of `it.scope` to check scopes of companion objects + // and context receivers as well. + it.getAvailableScopes() }) addIfNotNull(createFakeImportingScope(newImports)) addAll(towerDataContext.localScopes) 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 780b1df440c..8c41aea6cba 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 @@ -160,6 +160,12 @@ public class FirIdeNormalAnalysisSourceModuleReferenceShortenerTestGenerated ext runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt"); } + @Test + @TestMetadata("contextReceiver.kt") + public void testContextReceiver() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.kt"); + } + @Test @TestMetadata("enumClassCompanionAlreadyImported.kt") public void testEnumClassCompanionAlreadyImported() throws Exception { 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 21c5f6d45e0..8cf383a6aae 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 @@ -160,6 +160,12 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceShortenerTestGenera runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/companionUsedOutOfClass.kt"); } + @Test + @TestMetadata("contextReceiver.kt") + public void testContextReceiver() throws Exception { + runTest("analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.kt"); + } + @Test @TestMetadata("enumClassCompanionAlreadyImported.kt") public void testEnumClassCompanionAlreadyImported() throws Exception { diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.kt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.kt new file mode 100644 index 00000000000..98e3adf8a9d --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.kt @@ -0,0 +1,12 @@ +// FILE: main.kt +package a.b.c + +class A { + fun foo() {} +} +fun foo() = 1 + +context(A) +fun test() { + a.b.c.foo() +} diff --git a/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.txt b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.txt new file mode 100644 index 00000000000..5f09124147a --- /dev/null +++ b/analysis/analysis-api/testData/components/referenceShortener/referenceShortener/contextReceiver.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/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt index 11b395dcfab..e471e0099c9 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/FirReceivers.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.builder.buildThisReceiverExpression import org.jetbrains.kotlin.fir.references.builder.buildImplicitThisReference import org.jetbrains.kotlin.fir.renderWithType import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.smartcastScope import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator @@ -29,6 +30,7 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.SmartcastStability +import org.jetbrains.kotlin.utils.addToStdlib.applyIf interface Receiver @@ -88,6 +90,8 @@ sealed class ImplicitReceiverValue>( val originalType: ConeKotlinType = type + val expandedType: ConeKotlinType = type.applyIf(type is ConeClassLikeType) { fullyExpandedType(useSiteSession) } + var implicitScope: FirTypeScope? = type.scope(useSiteSession, scopeSession, FakeOverrideTypeCalculator.DoNothing, requiredPhase = FirResolvePhase.STATUS) private set 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 6be2f2af465..352b68d2405 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 @@ -14,10 +14,13 @@ import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.FirTypeScope import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.fir.types.ConeErrorType import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.ConeStubType import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addIfNotNull @@ -219,6 +222,7 @@ class FirTowerDataContext private constructor( } } +// Each FirTowerDataElement has exactly one non-null value among values of properties: scope, implicitReceiver and contextReceiverGroup. class FirTowerDataElement( val scope: FirScope?, val implicitReceiver: ImplicitReceiverValue<*>?, @@ -236,11 +240,24 @@ class FirTowerDataElement( ) /** - * Returns [scope] if it is not null. Otherwise, returns [implicitReceiver.implicitScope]. + * Returns [scope] if it is not null. Otherwise, returns scopes of implicit receivers (including context receivers). * * Note that a scope for a companion object is an implicit scope. */ - fun getAvailableScope() = scope ?: implicitReceiver?.implicitScope + fun getAvailableScopes(): List = when { + scope != null -> listOf(scope) + implicitReceiver != null -> listOf(implicitReceiver.getImplicitScope()) + contextReceiverGroup != null -> contextReceiverGroup.map { it.getImplicitScope() } + else -> error("Tower data element is expected to have either scope or implicit receivers.") + } + + private fun ImplicitReceiverValue<*>.getImplicitScope(): FirScope { + return when (expandedType) { + is ConeErrorType, + is ConeStubType -> FirTypeScope.Empty + else -> implicitScope ?: error("Scope for type ${type::class.simpleName} is null.") + } + } } fun ImplicitReceiverValue<*>.asTowerDataElement(): FirTowerDataElement =