[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
This commit is contained in:
Marco Pennekamp
2023-08-24 21:54:02 +02:00
committed by Space Team
parent e72a38dc82
commit 80efa34926
21 changed files with 106 additions and 11 deletions
@@ -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.KtFe10DescEnumEntrySymbolPointer
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers.KtFe10NeverRestoringSymbolPointer import org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers.KtFe10NeverRestoringSymbolPointer
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion 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.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
@@ -27,7 +28,7 @@ import org.jetbrains.kotlin.name.Name
internal class KtFe10DescEnumEntrySymbol( internal class KtFe10DescEnumEntrySymbol(
override val descriptor: ClassDescriptor, override val descriptor: ClassDescriptor,
override val analysisContext: Fe10AnalysisContext override val analysisContext: Fe10AnalysisContext
) : KtEnumEntrySymbol(), KtFe10DescMemberSymbol<ClassDescriptor> { ) : KtEnumEntrySymbol(), KtEnumEntryInitializerSymbol, KtFe10DescMemberSymbol<ClassDescriptor> {
private val enumDescriptor: ClassDescriptor private val enumDescriptor: ClassDescriptor
get() = descriptor.containingDeclaration as ClassDescriptor get() = descriptor.containingDeclaration as ClassDescriptor
@@ -50,6 +51,11 @@ internal class KtFe10DescEnumEntrySymbol(
override val name: Name override val name: Name
get() = withValidityAssertion { descriptor.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) context(KtAnalysisSession)
override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> = withValidityAssertion { override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtEnumEntrySymbol>(this)?.let { KtPsiBasedSymbolPointer.createForSymbolFromSource<KtEnumEntrySymbol>(this)?.let {
@@ -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.symbols.psiBased.base.createErrorType
import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached import org.jetbrains.kotlin.analysis.api.descriptors.utils.cached
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion 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.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
@@ -33,7 +34,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
internal class KtFe10PsiEnumEntrySymbol( internal class KtFe10PsiEnumEntrySymbol(
override val psi: KtEnumEntry, override val psi: KtEnumEntry,
override val analysisContext: Fe10AnalysisContext override val analysisContext: Fe10AnalysisContext
) : KtEnumEntrySymbol(), KtFe10PsiSymbol<KtEnumEntry, ClassDescriptor> { ) : KtEnumEntrySymbol(), KtEnumEntryInitializerSymbol, KtFe10PsiSymbol<KtEnumEntry, ClassDescriptor> {
override val descriptor: ClassDescriptor? by cached { override val descriptor: ClassDescriptor? by cached {
val bindingContext = analysisContext.analyze(psi, AnalysisMode.PARTIAL) val bindingContext = analysisContext.analyze(psi, AnalysisMode.PARTIAL)
bindingContext[BindingContext.CLASS, psi] bindingContext[BindingContext.CLASS, psi]
@@ -61,6 +62,9 @@ internal class KtFe10PsiEnumEntrySymbol(
override val name: Name override val name: Name
get() = withValidityAssertion { psi.nameAsSafeName } get() = withValidityAssertion { psi.nameAsSafeName }
override val enumEntryInitializer: KtEnumEntryInitializerSymbol?
get() = this.takeIf { psi.body != null }
context(KtAnalysisSession) context(KtAnalysisSession)
override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> = withValidityAssertion { override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFe10NeverRestoringSymbolPointer() KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFe10NeverRestoringSymbolPointer()
@@ -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.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousObjectSymbol 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.CanNotCreateSymbolPointerForLocalLibraryDeclarationException
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
@@ -25,7 +26,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol
internal class KtFirAnonymousObjectSymbol( internal class KtFirAnonymousObjectSymbol(
override val firSymbol: FirAnonymousObjectSymbol, override val firSymbol: FirAnonymousObjectSymbol,
override val analysisSession: KtFirAnalysisSession, override val analysisSession: KtFirAnalysisSession,
) : KtAnonymousObjectSymbol(), KtFirSymbol<FirAnonymousObjectSymbol> { ) : KtAnonymousObjectSymbol(), KtEnumEntryInitializerSymbol, KtFirSymbol<FirAnonymousObjectSymbol> {
override val psi: PsiElement? = withValidityAssertion { firSymbol.fir.getAllowedPsi() } override val psi: PsiElement? = withValidityAssertion { firSymbol.fir.getAllowedPsi() }
override val annotationsList by cached { override val annotationsList by cached {
@@ -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.symbols.pointers.requireOwnerPointer
import org.jetbrains.kotlin.analysis.api.fir.utils.cached import org.jetbrains.kotlin.analysis.api.fir.utils.cached
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion 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.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.api.types.KtType 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.impl.FirEnumEntrySymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -41,6 +45,20 @@ internal class KtFirEnumEntrySymbol(
override val callableIdIfNonLocal: CallableId? get() = withValidityAssertion { firSymbol.getCallableIdIfNonLocal() } 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) context(KtAnalysisSession)
override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> = withValidityAssertion { override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFirEnumEntrySymbolPointer(requireOwnerPointer(), firSymbol.name) KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFirEnumEntrySymbolPointer(requireOwnerPointer(), firSymbol.name)
@@ -21,7 +21,7 @@ public interface KtEnumEntrySymbolRenderer {
" ".separated( " ".separated(
{ renderAnnotationsModifiersAndContextReceivers(symbol, printer) }, { renderAnnotationsModifiersAndContextReceivers(symbol, printer) },
{ nameRenderer.renderName(symbol, printer) }, { nameRenderer.renderName(symbol, printer) },
{ classifierBodyRenderer.renderBody(symbol, printer) }, { symbol.enumEntryInitializer?.let { classifierBodyRenderer.renderBody(it, printer) } },
) )
} }
} }
@@ -91,10 +91,37 @@ public abstract class KtEnumEntrySymbol : KtVariableLikeSymbol(), KtSymbolWithKi
//todo reduntant, remove //todo reduntant, remove
public abstract val containingEnumClassIdIfNonLocal: ClassId? 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) context(KtAnalysisSession)
abstract override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol> abstract override fun createPointer(): KtSymbolPointer<KtEnumEntrySymbol>
} }
/**
* 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 sealed class KtVariableSymbol : KtVariableLikeSymbol() {
public abstract val isVal: Boolean public abstract val isVal: Boolean
@@ -519,6 +519,7 @@ scopes:
callableIdIfNonLocal: /E.A callableIdIfNonLocal: /E.A
containingEnumClassIdIfNonLocal: E containingEnumClassIdIfNonLocal: E
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: A name: A
origin: SOURCE origin: SOURCE
@@ -3,6 +3,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: kotlin/LazyThreadSafetyMode.SYNCHRONIZED callableIdIfNonLocal: kotlin/LazyThreadSafetyMode.SYNCHRONIZED
containingEnumClassIdIfNonLocal: kotlin/LazyThreadSafetyMode containingEnumClassIdIfNonLocal: kotlin/LazyThreadSafetyMode
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(kotlin/LazyThreadSafetyMode.SYNCHRONIZED)
isExtension: false isExtension: false
name: SYNCHRONIZED name: SYNCHRONIZED
origin: LIBRARY origin: LIBRARY
@@ -3,6 +3,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: kotlin/LazyThreadSafetyMode.SYNCHRONIZED callableIdIfNonLocal: kotlin/LazyThreadSafetyMode.SYNCHRONIZED
containingEnumClassIdIfNonLocal: kotlin/LazyThreadSafetyMode containingEnumClassIdIfNonLocal: kotlin/LazyThreadSafetyMode
contextReceivers: [] contextReceivers: []
enumEntryInitializer: null
isExtension: false isExtension: false
name: SYNCHRONIZED name: SYNCHRONIZED
origin: LIBRARY origin: LIBRARY
@@ -3,6 +3,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /X.Y callableIdIfNonLocal: /X.Y
containingEnumClassIdIfNonLocal: X containingEnumClassIdIfNonLocal: X
contextReceivers: [] contextReceivers: []
enumEntryInitializer: null
isExtension: false isExtension: false
name: Y name: Y
origin: SOURCE origin: SOURCE
@@ -21,6 +22,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /X.Z callableIdIfNonLocal: /X.Z
containingEnumClassIdIfNonLocal: X containingEnumClassIdIfNonLocal: X
contextReceivers: [] contextReceivers: []
enumEntryInitializer: null
isExtension: false isExtension: false
name: Z name: Z
origin: SOURCE origin: SOURCE
@@ -39,6 +39,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.FirstEntry callableIdIfNonLocal: /MyEnumClass.FirstEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.FirstEntry)
isExtension: false isExtension: false
name: FirstEntry name: FirstEntry
origin: SOURCE origin: SOURCE
@@ -57,6 +58,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.SecondEntry callableIdIfNonLocal: /MyEnumClass.SecondEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: null
isExtension: false isExtension: false
name: SecondEntry name: SecondEntry
origin: SOURCE origin: SOURCE
@@ -170,6 +172,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.ThirdEntry callableIdIfNonLocal: /MyEnumClass.ThirdEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.ThirdEntry)
isExtension: false isExtension: false
name: ThirdEntry name: ThirdEntry
origin: SOURCE origin: SOURCE
@@ -39,6 +39,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.FirstEntry callableIdIfNonLocal: /MyEnumClass.FirstEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: FirstEntry name: FirstEntry
origin: SOURCE origin: SOURCE
@@ -57,6 +58,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.SecondEntry callableIdIfNonLocal: /MyEnumClass.SecondEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: null
isExtension: false isExtension: false
name: SecondEntry name: SecondEntry
origin: SOURCE origin: SOURCE
@@ -170,6 +172,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.ThirdEntry callableIdIfNonLocal: /MyEnumClass.ThirdEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: ThirdEntry name: ThirdEntry
origin: SOURCE origin: SOURCE
@@ -75,6 +75,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.FirstEntry callableIdIfNonLocal: /MyEnumClass.FirstEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.FirstEntry)
isExtension: false isExtension: false
name: FirstEntry name: FirstEntry
origin: SOURCE origin: SOURCE
@@ -214,6 +215,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.SecondEntry callableIdIfNonLocal: /MyEnumClass.SecondEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.SecondEntry)
isExtension: false isExtension: false
name: SecondEntry name: SecondEntry
origin: SOURCE origin: SOURCE
@@ -327,6 +329,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.ThirdEntry callableIdIfNonLocal: /MyEnumClass.ThirdEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.ThirdEntry)
isExtension: false isExtension: false
name: ThirdEntry name: ThirdEntry
origin: SOURCE origin: SOURCE
@@ -75,6 +75,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.FirstEntry callableIdIfNonLocal: /MyEnumClass.FirstEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: FirstEntry name: FirstEntry
origin: SOURCE origin: SOURCE
@@ -210,6 +211,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.SecondEntry callableIdIfNonLocal: /MyEnumClass.SecondEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: SecondEntry name: SecondEntry
origin: SOURCE origin: SOURCE
@@ -323,6 +325,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.ThirdEntry callableIdIfNonLocal: /MyEnumClass.ThirdEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: ThirdEntry name: ThirdEntry
origin: SOURCE origin: SOURCE
@@ -88,6 +88,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.FirstEntry callableIdIfNonLocal: /MyEnumClass.FirstEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.FirstEntry)
isExtension: false isExtension: false
name: FirstEntry name: FirstEntry
origin: SOURCE origin: SOURCE
@@ -106,6 +107,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.SecondEntry callableIdIfNonLocal: /MyEnumClass.SecondEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: null
isExtension: false isExtension: false
name: SecondEntry name: SecondEntry
origin: SOURCE origin: SOURCE
@@ -312,6 +314,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.ThirdEntry callableIdIfNonLocal: /MyEnumClass.ThirdEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/MyEnumClass.ThirdEntry)
isExtension: false isExtension: false
name: ThirdEntry name: ThirdEntry
origin: SOURCE origin: SOURCE
@@ -88,6 +88,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.FirstEntry callableIdIfNonLocal: /MyEnumClass.FirstEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: FirstEntry name: FirstEntry
origin: SOURCE origin: SOURCE
@@ -106,6 +107,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.SecondEntry callableIdIfNonLocal: /MyEnumClass.SecondEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: null
isExtension: false isExtension: false
name: SecondEntry name: SecondEntry
origin: SOURCE origin: SOURCE
@@ -308,6 +310,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /MyEnumClass.ThirdEntry callableIdIfNonLocal: /MyEnumClass.ThirdEntry
containingEnumClassIdIfNonLocal: MyEnumClass containingEnumClassIdIfNonLocal: MyEnumClass
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: ThirdEntry name: ThirdEntry
origin: SOURCE origin: SOURCE
@@ -217,6 +217,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /Style.SHEET callableIdIfNonLocal: /Style.SHEET
containingEnumClassIdIfNonLocal: Style containingEnumClassIdIfNonLocal: Style
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtEnumEntrySymbol(/Style.SHEET)
isExtension: false isExtension: false
name: SHEET name: SHEET
origin: SOURCE origin: SOURCE
@@ -213,6 +213,7 @@ KtEnumEntrySymbol:
callableIdIfNonLocal: /Style.SHEET callableIdIfNonLocal: /Style.SHEET
containingEnumClassIdIfNonLocal: Style containingEnumClassIdIfNonLocal: Style
contextReceivers: [] contextReceivers: []
enumEntryInitializer: KtAnonymousObjectSymbol(<local>/<no name provided>)
isExtension: false isExtension: false
name: SHEET name: SHEET
origin: SOURCE origin: SOURCE
@@ -107,7 +107,17 @@ internal class SymbolLightClassForEnumEntry(
val result = mutableListOf<KtLightField>() val result = mutableListOf<KtLightField>()
// Then, add instance fields: properties from parameters, and then member properties // 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 result
} }
@@ -117,11 +127,13 @@ internal class SymbolLightClassForEnumEntry(
enumConstant.withEnumEntrySymbol { enumEntrySymbol -> enumConstant.withEnumEntrySymbol { enumEntrySymbol ->
val result = mutableListOf<KtLightMethod>() val result = mutableListOf<KtLightMethod>()
val declaredMemberScope = enumEntrySymbol.getDeclaredMemberScope() enumEntrySymbol.enumEntryInitializer?.let { initializer ->
val visibleDeclarations = declaredMemberScope.getCallableSymbols() val declaredMemberScope = initializer.getDeclaredMemberScope()
val visibleDeclarations = declaredMemberScope.getCallableSymbols()
createMethods(visibleDeclarations, result) createMethods(visibleDeclarations, result)
createConstructors(declaredMemberScope.getConstructors(), result) createConstructors(declaredMemberScope.getConstructors(), result)
}
result result
} }
@@ -619,6 +619,7 @@ context(KtAnalysisSession)
internal fun SymbolLightClassBase.addPropertyBackingFields( internal fun SymbolLightClassBase.addPropertyBackingFields(
result: MutableList<KtLightField>, result: MutableList<KtLightField>,
symbolWithMembers: KtSymbolWithMembers, symbolWithMembers: KtSymbolWithMembers,
forceIsStaticTo: Boolean? = null,
) { ) {
val propertySymbols = symbolWithMembers.getDeclaredMemberScope().getCallableSymbols() val propertySymbols = symbolWithMembers.getDeclaredMemberScope().getCallableSymbols()
.filterIsInstance<KtPropertySymbol>() .filterIsInstance<KtPropertySymbol>()
@@ -633,7 +634,7 @@ internal fun SymbolLightClassBase.addPropertyBackingFields(
val nameGenerator = SymbolLightField.FieldNameGenerator() 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) { fun addPropertyBackingField(propertySymbol: KtPropertySymbol) {
createField( createField(
declaration = propertySymbol, declaration = propertySymbol,
@@ -96,7 +96,8 @@ internal fun KtClassOrObjectSymbol.enumClassModality(): String? {
context(KtAnalysisSession) context(KtAnalysisSession)
private fun KtEnumEntrySymbol.requiresSubClass(): Boolean { 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() internal fun KtSymbolWithVisibility.toPsiVisibilityForMember(): String = visibility.toPsiVisibilityForMember()