From 80efa349266b8680db4ce1828ff928ce690cb4e9 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Thu, 24 Aug 2023 21:54:02 +0200 Subject: [PATCH] [AA] Add `KtEnumEntryInitializerSymbol` - An enum entry's body is an initializer with members only accessible within that body. Because users of the Analysis API might want to analyze the members of the enum entry initializer, we expose this initializer via `KtEnumEntrySymbol`. The initializer only exists if the enum entry has a body. - We already have some usages of the initializer inside symbol light classes, which generate a light class for each enum entry, which includes the enum entry's hidden members. - To hide the implementation detail that initializers are anonymous objects, `KtEnumEntryInitializerSymbol` is simply a `KtSymbolWithMembers`. - The advantage of making it a `KtSymbolWithMembers`, instead of providing a custom way to get a member scope, is that we can pass around the initializer easily, e.g. in `KtEnumEntrySymbolRenderer`. - We implement `KtEnumEntryInitializerSymbol` directly as a `KtFirAnonymousObjectSymbol` without a wrapper. This has a few advantages: 1. We can directly benefit from the anonymous object symbol being a `KtSymbolWithMembers`, so we don't have to handle enum entry initializers specially in e.g. `KtFirScopeProvider`. 2. We don't have to implement a new symbol restoration mechanism for the initializer. 3. This implementation matches the actual FIR tree structure (with a simplification that the connecting anonymous object expression between the enum entry and the initializing anonymous object is omitted). ^KT-61425 fixed --- .../KtFe10DescEnumEntrySymbol.kt | 8 +++++- .../psiBased/KtFe10PsiEnumEntrySymbol.kt | 6 ++++- .../fir/symbols/KtFirAnonymousObjectSymbol.kt | 3 ++- .../api/fir/symbols/KtFirEnumEntrySymbol.kt | 18 +++++++++++++ .../callables/KtEnumEntrySymbolRenderer.kt | 2 +- .../api/symbols/KtVariableLikeSymbol.kt | 27 +++++++++++++++++++ .../scopeContextForPosition/enumEntry.txt | 1 + .../symbolByFqName/enumEntry.descriptors.txt | 1 + .../symbols/symbolByFqName/enumEntry.txt | 1 + .../testData/symbols/symbolByPsi/enum.txt | 2 ++ .../enumEntryFunctions.descriptors.txt | 3 +++ .../symbolByPsi/enumEntryFunctions.txt | 3 +++ .../enumEntryOverride.descriptors.txt | 3 +++ .../symbols/symbolByPsi/enumEntryOverride.txt | 3 +++ .../enumEntryProperties.descriptors.txt | 3 +++ .../symbolByPsi/enumEntryProperties.txt | 3 +++ .../enumValueMember.descriptors.txt | 1 + .../symbols/symbolByPsi/enumValueMember.txt | 1 + .../classes/SymbolLightClassForEnumEntry.kt | 22 +++++++++++---- .../symbol/classes/symbolLightClassUtils.kt | 3 ++- .../light/classes/symbol/symbolLightUtils.kt | 3 ++- 21 files changed, 106 insertions(+), 11 deletions(-) diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescEnumEntrySymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescEnumEntrySymbol.kt index e6b8baa2f95..c311c3b23f4 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescEnumEntrySymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/KtFe10DescEnumEntrySymbol.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.isEqualTo import org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers.KtFe10DescEnumEntrySymbolPointer import org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers.KtFe10NeverRestoringSymbolPointer import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntryInitializerSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer @@ -27,7 +28,7 @@ import org.jetbrains.kotlin.name.Name internal class KtFe10DescEnumEntrySymbol( override val descriptor: ClassDescriptor, override val analysisContext: Fe10AnalysisContext -) : KtEnumEntrySymbol(), KtFe10DescMemberSymbol { +) : KtEnumEntrySymbol(), KtEnumEntryInitializerSymbol, KtFe10DescMemberSymbol { private val enumDescriptor: ClassDescriptor get() = descriptor.containingDeclaration as ClassDescriptor @@ -50,6 +51,11 @@ internal class KtFe10DescEnumEntrySymbol( override val name: Name get() = withValidityAssertion { descriptor.name } + // There doesn't seem to be a way to determine if `descriptor` has a body or not, so we return an initializer even for enum entries + // without a body. + override val enumEntryInitializer: KtEnumEntryInitializerSymbol? + get() = this + context(KtAnalysisSession) override fun createPointer(): KtSymbolPointer = withValidityAssertion { KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiEnumEntrySymbol.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiEnumEntrySymbol.kt index 1b4746aebbb..a75bb55e13f 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiEnumEntrySymbol.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/psiBased/KtFe10PsiEnumEntrySymbol.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.calla import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.createErrorType import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntryInitializerSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer @@ -33,7 +34,7 @@ import org.jetbrains.kotlin.resolve.BindingContext internal class KtFe10PsiEnumEntrySymbol( override val psi: KtEnumEntry, override val analysisContext: Fe10AnalysisContext -) : KtEnumEntrySymbol(), KtFe10PsiSymbol { +) : KtEnumEntrySymbol(), KtEnumEntryInitializerSymbol, KtFe10PsiSymbol { override val descriptor: ClassDescriptor? by cached { val bindingContext = analysisContext.analyze(psi, AnalysisMode.PARTIAL) bindingContext[BindingContext.CLASS, psi] @@ -61,6 +62,9 @@ internal class KtFe10PsiEnumEntrySymbol( override val name: Name get() = withValidityAssertion { psi.nameAsSafeName } + override val enumEntryInitializer: KtEnumEntryInitializerSymbol? + get() = this.takeIf { psi.body != null } + context(KtAnalysisSession) override fun createPointer(): KtSymbolPointer = withValidityAssertion { KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFe10NeverRestoringSymbolPointer() diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousObjectSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousObjectSymbol.kt index b4261cc57ec..2a0b77161a8 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousObjectSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirAnonymousObjectSymbol.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.requireOwnerPointe import org.jetbrains.kotlin.analysis.api.fir.utils.cached import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousObjectSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntryInitializerSymbol import org.jetbrains.kotlin.analysis.api.symbols.pointers.CanNotCreateSymbolPointerForLocalLibraryDeclarationException import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer @@ -25,7 +26,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol internal class KtFirAnonymousObjectSymbol( override val firSymbol: FirAnonymousObjectSymbol, override val analysisSession: KtFirAnalysisSession, -) : KtAnonymousObjectSymbol(), KtFirSymbol { +) : KtAnonymousObjectSymbol(), KtEnumEntryInitializerSymbol, KtFirSymbol { override val psi: PsiElement? = withValidityAssertion { firSymbol.fir.getAllowedPsi() } override val annotationsList by cached { diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirEnumEntrySymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirEnumEntrySymbol.kt index 981bd996e71..998b3a5f6a3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirEnumEntrySymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirEnumEntrySymbol.kt @@ -15,11 +15,15 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirEnumEntrySymb import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.requireOwnerPointer import org.jetbrains.kotlin.analysis.api.fir.utils.cached import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntryInitializerSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name @@ -41,6 +45,20 @@ internal class KtFirEnumEntrySymbol( override val callableIdIfNonLocal: CallableId? get() = withValidityAssertion { firSymbol.getCallableIdIfNonLocal() } + override val enumEntryInitializer: KtEnumEntryInitializerSymbol? by cached { + if (firSymbol.fir.initializer == null) { + return@cached null + } + + firSymbol.fir.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) + + val initializerExpression = firSymbol.fir.initializer + check(initializerExpression is FirAnonymousObjectExpression) { + "Unexpected enum entry initializer: ${initializerExpression?.javaClass}" + } + KtFirAnonymousObjectSymbol(initializerExpression.anonymousObject.symbol, analysisSession) + } + context(KtAnalysisSession) override fun createPointer(): KtSymbolPointer = withValidityAssertion { KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFirEnumEntrySymbolPointer(requireOwnerPointer(), firSymbol.name) diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/declarations/renderers/callables/KtEnumEntrySymbolRenderer.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/declarations/renderers/callables/KtEnumEntrySymbolRenderer.kt index 3beb20702f4..649607de43b 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/declarations/renderers/callables/KtEnumEntrySymbolRenderer.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/renderer/declarations/renderers/callables/KtEnumEntrySymbolRenderer.kt @@ -21,7 +21,7 @@ public interface KtEnumEntrySymbolRenderer { " ".separated( { renderAnnotationsModifiersAndContextReceivers(symbol, printer) }, { nameRenderer.renderName(symbol, printer) }, - { classifierBodyRenderer.renderBody(symbol, printer) }, + { symbol.enumEntryInitializer?.let { classifierBodyRenderer.renderBody(it, printer) } }, ) } } 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 f4104deb697..e0773c2268f 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 @@ -91,10 +91,37 @@ public abstract class KtEnumEntrySymbol : KtVariableLikeSymbol(), KtSymbolWithKi //todo reduntant, remove public abstract val containingEnumClassIdIfNonLocal: ClassId? + /** + * Returns the enum entry's initializer, or `null` if the enum entry doesn't have a body. + */ + public abstract val enumEntryInitializer: KtEnumEntryInitializerSymbol? + context(KtAnalysisSession) abstract override fun createPointer(): KtSymbolPointer } +/** + * An initializer for enum entries with a body. The initializer may contain its own declarations (especially overrides of members declared + * by the enum class), and is [similar to an object declaration](https://kotlinlang.org/spec/declarations.html#enum-class-declaration). + * + * #### Example + * + * ```kotlin + * enum class E { + * // `A` is declared with an initializer. + * A { + * val x: Int = 5 + * }, + * + * // `B` has no initializer. + * B + * } + * ``` + * + * The initializer of `A` declares a member `x: Int`, which is inaccessible outside the initializer. Still, the corresponding + * [KtEnumEntryInitializerSymbol] can be used to get a declared member scope that contains `x`. + */ +public interface KtEnumEntryInitializerSymbol : KtSymbolWithMembers public sealed class KtVariableSymbol : KtVariableLikeSymbol() { public abstract val isVal: Boolean diff --git a/analysis/analysis-api/testData/components/scopeProvider/scopeContextForPosition/enumEntry.txt b/analysis/analysis-api/testData/components/scopeProvider/scopeContextForPosition/enumEntry.txt index cca06181abd..91066dcd5dd 100644 --- a/analysis/analysis-api/testData/components/scopeProvider/scopeContextForPosition/enumEntry.txt +++ b/analysis/analysis-api/testData/components/scopeProvider/scopeContextForPosition/enumEntry.txt @@ -519,6 +519,7 @@ scopes: callableIdIfNonLocal: /E.A containingEnumClassIdIfNonLocal: E contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: A origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.descriptors.txt b/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.descriptors.txt index b72a14f0041..fcc810112ec 100644 --- a/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.descriptors.txt +++ b/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.descriptors.txt @@ -3,6 +3,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: kotlin/LazyThreadSafetyMode.SYNCHRONIZED containingEnumClassIdIfNonLocal: kotlin/LazyThreadSafetyMode contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(kotlin/LazyThreadSafetyMode.SYNCHRONIZED) isExtension: false name: SYNCHRONIZED origin: LIBRARY diff --git a/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.txt b/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.txt index 46469abe022..24e88c85142 100644 --- a/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.txt +++ b/analysis/analysis-api/testData/symbols/symbolByFqName/enumEntry.txt @@ -3,6 +3,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: kotlin/LazyThreadSafetyMode.SYNCHRONIZED containingEnumClassIdIfNonLocal: kotlin/LazyThreadSafetyMode contextReceivers: [] + enumEntryInitializer: null isExtension: false name: SYNCHRONIZED origin: LIBRARY diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enum.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enum.txt index 11df371b001..d5f52ca72b5 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enum.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enum.txt @@ -3,6 +3,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /X.Y containingEnumClassIdIfNonLocal: X contextReceivers: [] + enumEntryInitializer: null isExtension: false name: Y origin: SOURCE @@ -21,6 +22,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /X.Z containingEnumClassIdIfNonLocal: X contextReceivers: [] + enumEntryInitializer: null isExtension: false name: Z origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.descriptors.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.descriptors.txt index 9e130895956..d293a58e8df 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.descriptors.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.descriptors.txt @@ -39,6 +39,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.FirstEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.FirstEntry) isExtension: false name: FirstEntry origin: SOURCE @@ -57,6 +58,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.SecondEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: null isExtension: false name: SecondEntry origin: SOURCE @@ -170,6 +172,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.ThirdEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.ThirdEntry) isExtension: false name: ThirdEntry origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.txt index 58a407080ef..1c2c04298e2 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryFunctions.txt @@ -39,6 +39,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.FirstEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: FirstEntry origin: SOURCE @@ -57,6 +58,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.SecondEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: null isExtension: false name: SecondEntry origin: SOURCE @@ -170,6 +172,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.ThirdEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: ThirdEntry origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.descriptors.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.descriptors.txt index 6e1063e1cd0..71c38cfc0eb 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.descriptors.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.descriptors.txt @@ -75,6 +75,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.FirstEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.FirstEntry) isExtension: false name: FirstEntry origin: SOURCE @@ -214,6 +215,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.SecondEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.SecondEntry) isExtension: false name: SecondEntry origin: SOURCE @@ -327,6 +329,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.ThirdEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.ThirdEntry) isExtension: false name: ThirdEntry origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.txt index 9b1fcd7d0f0..3bea5a4bef5 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryOverride.txt @@ -75,6 +75,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.FirstEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: FirstEntry origin: SOURCE @@ -210,6 +211,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.SecondEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: SecondEntry origin: SOURCE @@ -323,6 +325,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.ThirdEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: ThirdEntry origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.descriptors.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.descriptors.txt index f48eaacae52..8b8d6916eb4 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.descriptors.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.descriptors.txt @@ -88,6 +88,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.FirstEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.FirstEntry) isExtension: false name: FirstEntry origin: SOURCE @@ -106,6 +107,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.SecondEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: null isExtension: false name: SecondEntry origin: SOURCE @@ -312,6 +314,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.ThirdEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.ThirdEntry) isExtension: false name: ThirdEntry origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.txt index f2638820fd9..5fc9f6dff39 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumEntryProperties.txt @@ -88,6 +88,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.FirstEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: FirstEntry origin: SOURCE @@ -106,6 +107,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.SecondEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: null isExtension: false name: SecondEntry origin: SOURCE @@ -308,6 +310,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /MyEnumClass.ThirdEntry containingEnumClassIdIfNonLocal: MyEnumClass contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: ThirdEntry origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.descriptors.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.descriptors.txt index 236b7676051..5b229b494d6 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.descriptors.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.descriptors.txt @@ -217,6 +217,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /Style.SHEET containingEnumClassIdIfNonLocal: Style contextReceivers: [] + enumEntryInitializer: KtEnumEntrySymbol(/Style.SHEET) isExtension: false name: SHEET origin: SOURCE diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.txt b/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.txt index 833c7959195..a37ad949cc2 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.txt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/enumValueMember.txt @@ -213,6 +213,7 @@ KtEnumEntrySymbol: callableIdIfNonLocal: /Style.SHEET containingEnumClassIdIfNonLocal: Style contextReceivers: [] + enumEntryInitializer: KtAnonymousObjectSymbol(/) isExtension: false name: SHEET origin: SOURCE diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt index 6511f6f08c5..bf119445632 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/SymbolLightClassForEnumEntry.kt @@ -107,7 +107,17 @@ internal class SymbolLightClassForEnumEntry( val result = mutableListOf() // Then, add instance fields: properties from parameters, and then member properties - addPropertyBackingFields(result, enumEntrySymbol) + enumEntrySymbol.enumEntryInitializer?.let { initializer -> + addPropertyBackingFields( + result, + initializer, + + // `addPropertyBackingFields` detects that property fields should be static when the given symbol with members is an + // object. Unfortunately, the enum entry's initializer is an anonymous object, yet we want the enum entry's light class + // to have non-static properties. + forceIsStaticTo = false, + ) + } result } @@ -117,11 +127,13 @@ internal class SymbolLightClassForEnumEntry( enumConstant.withEnumEntrySymbol { enumEntrySymbol -> val result = mutableListOf() - val declaredMemberScope = enumEntrySymbol.getDeclaredMemberScope() - val visibleDeclarations = declaredMemberScope.getCallableSymbols() + enumEntrySymbol.enumEntryInitializer?.let { initializer -> + val declaredMemberScope = initializer.getDeclaredMemberScope() + val visibleDeclarations = declaredMemberScope.getCallableSymbols() - createMethods(visibleDeclarations, result) - createConstructors(declaredMemberScope.getConstructors(), result) + createMethods(visibleDeclarations, result) + createConstructors(declaredMemberScope.getConstructors(), result) + } result } diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/symbolLightClassUtils.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/symbolLightClassUtils.kt index 1c334965cff..e094419e2c1 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/symbolLightClassUtils.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/symbolLightClassUtils.kt @@ -619,6 +619,7 @@ context(KtAnalysisSession) internal fun SymbolLightClassBase.addPropertyBackingFields( result: MutableList, symbolWithMembers: KtSymbolWithMembers, + forceIsStaticTo: Boolean? = null, ) { val propertySymbols = symbolWithMembers.getDeclaredMemberScope().getCallableSymbols() .filterIsInstance() @@ -633,7 +634,7 @@ internal fun SymbolLightClassBase.addPropertyBackingFields( val nameGenerator = SymbolLightField.FieldNameGenerator() - val isStatic = symbolWithMembers is KtClassOrObjectSymbol && symbolWithMembers.classKind.isObject + val isStatic = forceIsStaticTo ?: (symbolWithMembers is KtClassOrObjectSymbol && symbolWithMembers.classKind.isObject) fun addPropertyBackingField(propertySymbol: KtPropertySymbol) { createField( declaration = propertySymbol, diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt index 5ac31c248bd..741810fbde3 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/symbolLightUtils.kt @@ -96,7 +96,8 @@ internal fun KtClassOrObjectSymbol.enumClassModality(): String? { context(KtAnalysisSession) private fun KtEnumEntrySymbol.requiresSubClass(): Boolean { - return getDeclaredMemberScope().getAllSymbols().any { it !is KtConstructorSymbol } + val initializer = enumEntryInitializer ?: return false + return initializer.getDeclaredMemberScope().getAllSymbols().any { it !is KtConstructorSymbol } } internal fun KtSymbolWithVisibility.toPsiVisibilityForMember(): String = visibility.toPsiVisibilityForMember()