[AA] Add specific implementation for KtFirEnumEntryInitializerSymbol

- Previously, `KtFirAnonymousObjectSymbol` was a
  `KtEnumEntryInitializerSymbol`, which carried the risk that an
  anonymous object unrelated to enum entries might be used as an enum
  entry initializer. This commit introduces a specific symbol for FIR
  enum entry initializers.
- As a nice side effect, anonymous object symbol creation is simplified
  and `KtFirEnumEntryInitializerSymbolPointer` can restore the symbol
  via `KtFirEnumEntrySymbol.enumEntryInitializer`.

^KT-61425
This commit is contained in:
Marco Pennekamp
2023-09-06 19:05:43 +02:00
committed by Space Team
parent 536e172d0e
commit 3fa2ca7ddd
7 changed files with 71 additions and 33 deletions
@@ -10,6 +10,8 @@ import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
import org.jetbrains.kotlin.analysis.api.KtTypeProjection
import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirFunctionLikeSubstitutorBasedSignature
import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirVariableLikeSubstitutorBasedSignature
import org.jetbrains.kotlin.analysis.api.fir.symbols.*
import org.jetbrains.kotlin.analysis.api.fir.types.*
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
@@ -21,16 +23,13 @@ import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
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.util.errorWithFirSpecificEntries
import org.jetbrains.kotlin.fir.utils.exceptions.withConeTypeEntry
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.fir.utils.exceptions.withFirSymbolEntry
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirFieldImpl
import org.jetbrains.kotlin.fir.declarations.FirOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.declarations.impl.FirFieldImpl
import org.jetbrains.kotlin.fir.diagnostics.ConeCannotInferTypeParameterType
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
@@ -48,6 +47,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectOrStaticData
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
@@ -56,15 +56,16 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.utils.exceptions.withConeTypeEntry
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.fir.utils.exceptions.withFirSymbolEntry
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirFunctionLikeSubstitutorBasedSignature
import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirVariableLikeSubstitutorBasedSignature
import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectOrStaticData
/**
* Maps FirElement to KtSymbol & ConeType to KtType, thread safe
@@ -160,7 +161,12 @@ internal class KtSymbolByFirBuilder constructor(
}
fun buildAnonymousObjectSymbol(symbol: FirAnonymousObjectSymbol): KtAnonymousObjectSymbol {
return symbolsCache.cache(symbol) { KtFirAnonymousObjectSymbol(symbol, analysisSession) }
return symbolsCache.cache(symbol) {
when (symbol.classKind) {
ClassKind.ENUM_ENTRY -> KtFirEnumEntryInitializerSymbol(symbol, analysisSession)
else -> KtFirAnonymousObjectSymbol(symbol, analysisSession)
}
}
}
fun buildTypeAliasSymbol(symbol: FirTypeAliasSymbol): KtFirTypeAliasSymbol {
@@ -6,27 +6,23 @@
package org.jetbrains.kotlin.analysis.api.fir.symbols
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration
import org.jetbrains.kotlin.analysis.api.fir.getAllowedPsi
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirEnumEntryInitializerSymbolPointer
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.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
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol
internal class KtFirAnonymousObjectSymbol(
internal open class KtFirAnonymousObjectSymbol(
override val firSymbol: FirAnonymousObjectSymbol,
override val analysisSession: KtFirAnalysisSession,
) : KtAnonymousObjectSymbol(), KtEnumEntryInitializerSymbol, KtFirSymbol<FirAnonymousObjectSymbol> {
) : KtAnonymousObjectSymbol(), KtFirSymbol<FirAnonymousObjectSymbol> {
override val psi: PsiElement? = withValidityAssertion { firSymbol.fir.getAllowedPsi() }
override val annotationsList by cached {
@@ -38,9 +34,6 @@ internal class KtFirAnonymousObjectSymbol(
context(KtAnalysisSession)
override fun createPointer(): KtSymbolPointer<KtAnonymousObjectSymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtAnonymousObjectSymbol>(this)?.let { return it }
if (firSymbol.source?.kind == KtFakeSourceElementKind.EnumInitializer) {
return KtFirEnumEntryInitializerSymbolPointer(requireOwnerPointer())
}
throw CanNotCreateSymbolPointerForLocalLibraryDeclarationException(this::class)
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.fir.symbols
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirEnumEntryInitializerSymbolPointer
import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.requireOwnerPointer
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntryInitializerSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtPsiBasedSymbolPointer
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol
internal class KtFirEnumEntryInitializerSymbol(
firSymbol: FirAnonymousObjectSymbol,
analysisSession: KtFirAnalysisSession,
) : KtFirAnonymousObjectSymbol(firSymbol, analysisSession), KtEnumEntryInitializerSymbol {
init {
check(firSymbol.source?.kind == KtFakeSourceElementKind.EnumInitializer) {
"Expected the `firSymbol` of ${KtFirEnumEntryInitializerSymbol::class.simpleName} to have an enum initializer fake source kind."
}
}
/**
* [KtFirEnumEntryInitializerSymbol] is the required return type instead of [KtEnumEntryInitializerSymbol] to fulfill return type
* subtyping requirements, as [KtEnumEntryInitializerSymbol] is not a subtype of
* [org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousObjectSymbol]. (It cannot be a subtype in the general Analysis API because enum
* entry initializers are classes in FE10.)
*/
context(KtAnalysisSession)
override fun createPointer(): KtSymbolPointer<KtFirEnumEntryInitializerSymbol> = withValidityAssertion {
KtPsiBasedSymbolPointer.createForSymbolFromSource<KtFirEnumEntryInitializerSymbol>(this)?.let { return it }
KtFirEnumEntryInitializerSymbolPointer(requireOwnerPointer())
}
}
@@ -15,7 +15,6 @@ 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
@@ -45,7 +44,7 @@ internal class KtFirEnumEntrySymbol(
override val callableIdIfNonLocal: CallableId? get() = withValidityAssertion { firSymbol.getCallableIdIfNonLocal() }
override val enumEntryInitializer: KtEnumEntryInitializerSymbol? by cached {
override val enumEntryInitializer: KtFirEnumEntryInitializerSymbol? by cached {
if (firSymbol.fir.initializer == null) {
return@cached null
}
@@ -56,7 +55,10 @@ internal class KtFirEnumEntrySymbol(
check(initializerExpression is FirAnonymousObjectExpression) {
"Unexpected enum entry initializer: ${initializerExpression?.javaClass}"
}
KtFirAnonymousObjectSymbol(initializerExpression.anonymousObject.symbol, analysisSession)
val classifierBuilder = analysisSession.firSymbolBuilder.classifierBuilder
classifierBuilder.buildAnonymousObjectSymbol(initializerExpression.anonymousObject.symbol) as? KtFirEnumEntryInitializerSymbol
?: error("The anonymous object symbol for an enum entry initializer should be a ${KtFirEnumEntryInitializerSymbol::class.simpleName}")
}
context(KtAnalysisSession)
@@ -7,25 +7,21 @@ package org.jetbrains.kotlin.analysis.api.fir.symbols.pointers
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.utils.firSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtAnonymousObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirEnumEntryInitializerSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirEnumEntrySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
internal class KtFirEnumEntryInitializerSymbolPointer(
private val ownerPointer: KtSymbolPointer<KtEnumEntrySymbol>,
) : KtSymbolPointer<KtAnonymousObjectSymbol>() {
private val ownerPointer: KtSymbolPointer<KtFirEnumEntrySymbol>,
) : KtSymbolPointer<KtFirEnumEntryInitializerSymbol>() {
@Deprecated("Consider using org.jetbrains.kotlin.analysis.api.KtAnalysisSession.restoreSymbol")
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtAnonymousObjectSymbol? {
override fun restoreSymbol(analysisSession: KtAnalysisSession): KtFirEnumEntryInitializerSymbol? {
require(analysisSession is KtFirAnalysisSession)
val owner = with(analysisSession) {
ownerPointer.restoreSymbol()
}
val initializer = owner?.firSymbol?.fir?.initializer as? FirAnonymousObjectExpression ?: return null
return analysisSession.firSymbolBuilder.classifierBuilder.buildAnonymousObjectSymbol(initializer.anonymousObject.symbol)
return owner?.enumEntryInitializer
}
override fun pointsToTheSameSymbolAs(other: KtSymbolPointer<KtSymbol>): Boolean = this === other ||
@@ -1,7 +1,7 @@
element: e
implicit receivers:
type: `<anonymous>`
owner symbol: KtFirAnonymousObjectSymbol
owner symbol: KtFirEnumEntryInitializerSymbol
type: kotlin.Enum.Companion
owner symbol: KtFirNamedClassOrObjectSymbol
@@ -4,7 +4,7 @@ implicit receivers:
annotationsList: []
ownTypeArguments: []
type: <anonymous>
owner symbol: KtFirAnonymousObjectSymbol
owner symbol: KtFirEnumEntryInitializerSymbol
type: KtUsualClassType:
annotationsList: []