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