From e72a38dc824b2d395157bc39b317102fbdb32265 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Thu, 24 Aug 2023 21:36:36 +0200 Subject: [PATCH] [AA] Remove `KtSymbolWithMembers` from `KtEnumEntrySymbol` - An enum entry is a variable which doesn't declare any additional members. It must not be confused with its implementing anonymous object initializer, which may declare additional members, but is an implementation detail hidden outside the enum entry's initializer. Hence, the enum entry variable should not have a (declared) member scope. - A following commit will add the ability to get the enum entry's initializer, so that a member scope for this initializer can be obtained (which might be relevant for local analysis). ^KT-61405 fixed --- .../api/fir/components/KtFirScopeProvider.kt | 128 +++++------------- ...oduleMemberScopeByFqNameTestGenerated.java | 6 - ...oduleMemberScopeByFqNameTestGenerated.java | 6 - .../api/symbols/KtVariableLikeSymbol.kt | 29 +++- .../emumEntryWithoutMembers.kt | 7 - .../emumEntryWithoutMembers.pretty.txt | 1 - .../emumEntryWithoutMembers.txt | 1 - 7 files changed, 61 insertions(+), 117 deletions(-) delete mode 100644 analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.kt delete mode 100644 analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.pretty.txt delete mode 100644 analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.txt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt index d33ad353866..a18c26cdbac 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtCompositeScope import org.jetbrains.kotlin.analysis.api.impl.base.scopes.KtEmptyScope import org.jetbrains.kotlin.analysis.api.scopes.KtScope import org.jetbrains.kotlin.analysis.api.scopes.KtTypeScope -import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtPackageSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithDeclarations @@ -25,32 +24,26 @@ import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError -import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.declarations.utils.delegateFields -import org.jetbrains.kotlin.fir.declarations.utils.isCompanion -import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression import org.jetbrains.kotlin.fir.java.JavaScopeProvider import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertiesScope import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.scopeSessionKey -import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseWithCallableMembers import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.utils.addToStdlib.applyIf import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment import org.jetbrains.kotlin.utils.exceptions.withPsiEntry @@ -64,45 +57,29 @@ internal class KtFirScopeProvider( return analysisSession.getScopeSessionFor(analysisSession.useSiteSession) } - private inline fun KtSymbolWithMembers.withFirForScope(crossinline body: (FirClass) -> T): T? { - return when (this) { - is KtFirNamedClassOrObjectSymbol -> body(firSymbol.fir) - is KtFirPsiJavaClassSymbol -> body(firSymbol.fir) - is KtFirAnonymousObjectSymbol -> body(firSymbol.fir) - is KtFirEnumEntrySymbol -> { - firSymbol.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) - val initializer = firSymbol.fir.initializer ?: return null - check(initializer is FirAnonymousObjectExpression) { "Unexpected enum entry initializer: ${initializer.javaClass}" } - body(initializer.anonymousObject) - } - - else -> error("Unknown ${KtSymbolWithDeclarations::class.simpleName} implementation ${this::class.qualifiedName}") - } + private fun KtSymbolWithMembers.getFirForScope(): FirClass = when (this) { + is KtFirNamedClassOrObjectSymbol -> firSymbol.fir + is KtFirPsiJavaClassSymbol -> firSymbol.fir + is KtFirAnonymousObjectSymbol -> firSymbol.fir + else -> error( + "`${this::class.qualifiedName}` needs to be specially handled by the scope provider or is an unknown" + + " ${KtSymbolWithDeclarations::class.simpleName} implementation." + ) } override fun getMemberScope(classSymbol: KtSymbolWithMembers): KtScope { - val firScope = classSymbol.withFirForScope { fir -> - val firSession = analysisSession.useSiteSession - fir.unsubstitutedScope( - firSession, - getScopeSession(), - withForcedTypeCalculator = false, - memberRequiredPhase = FirResolvePhase.STATUS, - ) - }?.applyIf(classSymbol is KtEnumEntrySymbol, ::EnumEntryContainingNamesAwareScope) ?: return getEmptyScope() - + val firScope = classSymbol.getFirForScope().unsubstitutedScope( + analysisSession.useSiteSession, + getScopeSession(), + withForcedTypeCalculator = false, + memberRequiredPhase = FirResolvePhase.STATUS, + ) return KtFirDelegatingNamesAwareScope(firScope, builder) } override fun getStaticMemberScope(symbol: KtSymbolWithMembers): KtScope { - val firScope = symbol.withFirForScope { fir -> - val firSession = analysisSession.useSiteSession - fir.scopeProvider.getStaticScope( - fir, - firSession, - getScopeSession(), - ) - } ?: return getEmptyScope() + val fir = symbol.getFirForScope() + val firScope = fir.scopeProvider.getStaticScope(fir, analysisSession.useSiteSession, getScopeSession()) ?: return getEmptyScope() return KtFirDelegatingNamesAwareScope(firScope, builder) } @@ -115,33 +92,33 @@ internal class KtFirScopeProvider( ) } - val firScope = classSymbol.withFirForScope { - when (val regularClass = classSymbol.firSymbol.fir) { - is FirJavaClass -> buildJavaEnhancementDeclaredMemberScope(useSiteSession, regularClass.symbol, getScopeSession()) - else -> useSiteSession.declaredMemberScope(it, memberRequiredPhase = null) - } - } ?: return getEmptyScope() - + val fir = classSymbol.getFirForScope() + val firScope = when (val regularClass = classSymbol.firSymbol.fir) { + is FirJavaClass -> buildJavaEnhancementDeclaredMemberScope(useSiteSession, regularClass.symbol, getScopeSession()) + else -> useSiteSession.declaredMemberScope(fir, memberRequiredPhase = null) + } return KtFirDelegatingNamesAwareScope(firScope, builder) } override fun getDelegatedMemberScope(classSymbol: KtSymbolWithMembers): KtScope { val declaredScope = (getDeclaredMemberScope(classSymbol) as? KtFirDelegatingNamesAwareScope)?.firScope ?: return getEmptyScope() - val firScope = classSymbol.withFirForScope { fir -> - val delegateFields = fir.delegateFields - if (delegateFields.isNotEmpty()) { - fir.lazyResolveToPhaseWithCallableMembers(FirResolvePhase.STATUS) - val firSession = analysisSession.useSiteSession - FirDelegatedMemberScope( - firSession, - getScopeSession(), - fir, - declaredScope, - delegateFields - ) - } else null - } ?: return getEmptyScope() + val fir = classSymbol.getFirForScope() + val delegateFields = fir.delegateFields + + if (delegateFields.isEmpty()) { + return getEmptyScope() + } + + fir.lazyResolveToPhaseWithCallableMembers(FirResolvePhase.STATUS) + + val firScope = FirDelegatedMemberScope( + analysisSession.useSiteSession, + getScopeSession(), + fir, + declaredScope, + delegateFields + ) return KtFirDelegatedMemberScope(firScope, builder) } @@ -158,7 +135,6 @@ internal class KtFirScopeProvider( return createPackageScope(packageSymbol.fqName) } - override fun getCompositeScope(subScopes: List): KtScope { return KtCompositeScope.create(subScopes, token) } @@ -339,34 +315,4 @@ private class FirTypeScopeWithSyntheticProperties( } } -private class EnumEntryContainingNamesAwareScope(private val originalScope: FirContainingNamesAwareScope) : FirContainingNamesAwareScope() { - override fun getCallableNames(): Set = originalScope.getCallableNames() - override fun getClassifierNames(): Set = originalScope.getClassifierNames() - override fun mayContainName(name: Name): Boolean = originalScope.mayContainName(name) - override val scopeOwnerLookupNames: List get() = super.scopeOwnerLookupNames - - override fun processClassifiersByNameWithSubstitution( - name: Name, - processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit - ) { - originalScope.processClassifiersByNameWithSubstitution(name) { classifier, substitutor -> - if ((classifier as? FirRegularClassSymbol)?.isCompanion != true) { - processor(classifier, substitutor) - } - } - } - - override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) { - originalScope.processFunctionsByName(name, processor) - } - - override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { - originalScope.processPropertiesByName(name, processor) - } - - override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) { - // enum entries does not have constructors - } -} - private val JAVA_ENHANCEMENT_FOR_DECLARED_MEMBER = scopeSessionKey() diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/scopeProvider/FirIdeNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/scopeProvider/FirIdeNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java index ebc26c2a500..f6a1dbe1797 100644 --- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/scopeProvider/FirIdeNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java +++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/scopeProvider/FirIdeNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java @@ -52,12 +52,6 @@ public class FirIdeNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated ex runTest("analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/dataClass.kt"); } - @Test - @TestMetadata("emumEntryWithoutMembers.kt") - public void testEmumEntryWithoutMembers() throws Exception { - runTest("analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.kt"); - } - @Test @TestMetadata("enumEntry.kt") public void testEnumEntry() throws Exception { diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/scopeProvider/FirStandaloneNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/scopeProvider/FirStandaloneNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java index b2eac7c86b4..90eba8bc9e2 100644 --- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/scopeProvider/FirStandaloneNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java +++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/scopeProvider/FirStandaloneNormalAnalysisSourceModuleMemberScopeByFqNameTestGenerated.java @@ -52,12 +52,6 @@ public class FirStandaloneNormalAnalysisSourceModuleMemberScopeByFqNameTestGener runTest("analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/dataClass.kt"); } - @Test - @TestMetadata("emumEntryWithoutMembers.kt") - public void testEmumEntryWithoutMembers() throws Exception { - runTest("analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.kt"); - } - @Test @TestMetadata("enumEntry.kt") public void testEnumEntry() throws Exception { diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt index 1a5a4237ca3..f4104deb697 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/KtVariableLikeSymbol.kt @@ -7,9 +7,7 @@ package org.jetbrains.kotlin.analysis.api.symbols import com.intellij.psi.PsiElement import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.KtConstantInitializerValue import org.jetbrains.kotlin.analysis.api.KtInitializerValue -import org.jetbrains.kotlin.analysis.api.KtNonConstantInitializerValue import org.jetbrains.kotlin.analysis.api.base.KtContextReceiver import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.markers.* @@ -18,7 +16,6 @@ import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtExpression public sealed class KtVariableLikeSymbol : KtCallableSymbol(), KtNamedSymbol, KtSymbolWithKind, KtPossibleMemberSymbol { context(KtAnalysisSession) @@ -59,8 +56,30 @@ public abstract class KtBackingFieldSymbol : KtVariableLikeSymbol() { } } - -public abstract class KtEnumEntrySymbol : KtVariableLikeSymbol(), KtSymbolWithMembers, KtSymbolWithKind { +/** + * An entry of an enum class. + * + * The type of the enum entry is the enum class itself. The members declared in an enum entry's body are local to the body and cannot be + * accessed from the outside. Hence, while it might look like enum entries can declare their own members (see the example below), they do + * not have a (declared) member scope. + * + * Members declared by the enum class and overridden in the enum entry's body will be accessible, of course, but only the base version + * declared in the enum class. For example, a narrowed return type of an overridden member in an enum entry's body will not be visible + * outside the body. + * + * #### Example + * + * ```kotlin + * enum class E { + * A { + * val x: Int = 5 + * } + * } + * ``` + * + * `A` is an enum entry of enum class `E`. `x` is a property of `A`'s initializer and thus not accessible outside the initializer. + */ +public abstract class KtEnumEntrySymbol : KtVariableLikeSymbol(), KtSymbolWithKind { final override val symbolKind: KtSymbolKind get() = withValidityAssertion { KtSymbolKind.CLASS_MEMBER } final override val isExtension: Boolean get() = withValidityAssertion { false } final override val receiverParameter: KtReceiverParameterSymbol? get() = withValidityAssertion { null } diff --git a/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.kt b/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.kt deleted file mode 100644 index a0babb8af55..00000000000 --- a/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.kt +++ /dev/null @@ -1,7 +0,0 @@ -package test - -enum class E { - A -} - -// callable: test/E.A diff --git a/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.pretty.txt b/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.pretty.txt deleted file mode 100644 index e71fee3bda8..00000000000 --- a/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.pretty.txt +++ /dev/null @@ -1 +0,0 @@ -NO_SYMBOLS diff --git a/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.txt b/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.txt deleted file mode 100644 index 63e2cb6e5c3..00000000000 --- a/analysis/analysis-api/testData/components/scopeProvider/memberScopeByFqName/emumEntryWithoutMembers.txt +++ /dev/null @@ -1 +0,0 @@ -NO_SYMBOLS \ No newline at end of file