[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.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<ClassDescriptor> {
) : KtEnumEntrySymbol(), KtEnumEntryInitializerSymbol, KtFe10DescMemberSymbol<ClassDescriptor> {
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<KtEnumEntrySymbol> = withValidityAssertion {
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.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<KtEnumEntry, ClassDescriptor> {
) : KtEnumEntrySymbol(), KtEnumEntryInitializerSymbol, KtFe10PsiSymbol<KtEnumEntry, ClassDescriptor> {
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<KtEnumEntrySymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource(this) ?: KtFe10NeverRestoringSymbolPointer()