diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt index 88807da2947..f2213998efd 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaClassSymbol.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.analysis.project.structure.getKtModule import org.jetbrains.kotlin.analysis.utils.classIdIfNonLocal import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.fir.declarations.FirTypeParameter import org.jetbrains.kotlin.fir.java.classKind import org.jetbrains.kotlin.fir.java.modality import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol @@ -82,16 +83,21 @@ internal class KtFirPsiJavaClassSymbol( psi.containingClass?.let { KtFirPsiJavaClassSymbol(it, analysisSession) } } - override val typeParameterNames: List by cached { - // The parent Java class might contribute `FirOuterClassTypeParameterRef`s to the FIR class's type parameters (see - // `FirJavaFacade.createFirJavaClass`), but since they are filtered out by `createRegularKtTypeParameters`, we do not need to - // include them in the list of type parameter names. - javaClass.typeParameters.map { it.name } + override val typeParameters: List by cached { + // The parent Java class might contribute type parameters to the Java type parameter stack, but for this KtSymbol, parent type + // parameters aren't relevant. + psi.typeParameters.mapIndexed { index, psiTypeParameter -> + KtFirPsiJavaTypeParameterSymbol(psiTypeParameter, analysisSession) { + // `psi.typeParameters` should align with the list of regular `FirTypeParameter`s, making the use of `index` valid. + val firTypeParameter = firSymbol.fir.typeParameters.filterIsInstance().getOrNull(index) + require(firTypeParameter != null) { + "The FIR symbol's ${FirTypeParameter::class.simpleName}s should have an entry at $index." + } + firTypeParameter.symbol + } + } } - val hasTypeParameters: Boolean - get() = withValidityAssertion { psi.typeParameters.isNotEmpty() } - val annotationSimpleNames: List get() = withValidityAssertion { psi.annotations.map { it.nameReferenceElement?.referenceName } } @@ -122,11 +128,6 @@ internal class KtFirPsiJavaClassSymbol( firClassSymbol } - override val typeParameters: List by cached { - if (hasTypeParameters) firSymbol.createRegularKtTypeParameters(builder) - else emptyList() - } - override val annotationsList: KtAnnotationsList by cached { if (hasAnnotations) KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token) else KtEmptyAnnotationsList(token) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaTypeParameterSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaTypeParameterSymbol.kt new file mode 100644 index 00000000000..dee23d1dd22 --- /dev/null +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirPsiJavaTypeParameterSymbol.kt @@ -0,0 +1,44 @@ +/* + * 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 com.intellij.psi.PsiTypeParameter +import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession +import org.jetbrains.kotlin.analysis.api.fir.utils.cached +import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.name.SpecialNames +import org.jetbrains.kotlin.types.Variance + +/** + * [KtFirPsiJavaTypeParameterSymbol] is a PSI-based type parameter symbol with a lazy [firSymbol]. Some properties such as [name] are + * computed based on the PSI. This is used by [KtFirPsiJavaClassSymbol] to avoid building its own FIR symbol when a list of type parameters + * is requested. + */ +internal class KtFirPsiJavaTypeParameterSymbol( + override val psi: PsiTypeParameter, + override val analysisSession: KtFirAnalysisSession, + private val computeFirSymbol: () -> FirTypeParameterSymbol, +) : KtFirTypeParameterSymbolBase(), KtFirPsiSymbol { + override val name: Name = withValidityAssertion { + psi.name?.let { Name.identifier(it) } ?: SpecialNames.NO_NAME_PROVIDED + } + + override val origin: KtSymbolOrigin + get() = withValidityAssertion { KtSymbolOrigin.JAVA } + + override val variance: Variance + get() = withValidityAssertion { Variance.INVARIANT } + + override val isReified: Boolean + get() = withValidityAssertion { false } + + override val firSymbol: FirTypeParameterSymbol by cached { + computeFirSymbol() + } +} diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbol.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbol.kt index 333ea2ed5f6..e79cd20be63 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbol.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbol.kt @@ -6,65 +6,24 @@ package org.jetbrains.kotlin.analysis.api.fir.symbols import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.analysis.api.KtAnalysisSession -import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession -import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration import org.jetbrains.kotlin.analysis.api.fir.findPsi -import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirTypeParameterSymbolPointer -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.KtLifetimeToken import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion -import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol -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.analysis.checkers.typeParameterSymbols import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol -import org.jetbrains.kotlin.fir.types.isNullableAny import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance internal class KtFirTypeParameterSymbol( override val firSymbol: FirTypeParameterSymbol, override val analysisSession: KtFirAnalysisSession, -) : KtTypeParameterSymbol(), KtFirSymbol { +) : KtFirTypeParameterSymbolBase() { override val token: KtLifetimeToken get() = builder.token override val psi: PsiElement? by cached { firSymbol.findPsi() } - override val annotationsList: KtAnnotationsList - get() = withValidityAssertion { - KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token) - } - override val name: Name get() = withValidityAssertion { firSymbol.name } - override val upperBounds: List by cached { - firSymbol.resolvedBounds.mapNotNull { type -> - if (type.isNullableAny) return@mapNotNull null - builder.typeBuilder.buildKtType(type) - } - } - override val variance: Variance get() = withValidityAssertion { firSymbol.variance } override val isReified: Boolean get() = withValidityAssertion { firSymbol.isReified } - - context(KtAnalysisSession) - override fun createPointer(): KtSymbolPointer = withValidityAssertion { - KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it } - - val containingDeclarationSymbol = firSymbol.containingDeclarationSymbol - val typeParameters = containingDeclarationSymbol.typeParameterSymbols - requireNotNull(typeParameters) { "Containing declaration symbol: ${containingDeclarationSymbol::class.simpleName}" } - - KtFirTypeParameterSymbolPointer( - ownerPointer = requireOwnerPointer(), - name = name, - index = typeParameters.indexOf(firSymbol), - ) - } - - override fun equals(other: Any?): Boolean = symbolEquals(other) - override fun hashCode(): Int = symbolHashCode() } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbolBase.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbolBase.kt new file mode 100644 index 00000000000..900e7a01b2c --- /dev/null +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeParameterSymbolBase.kt @@ -0,0 +1,56 @@ +/* + * 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.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList +import org.jetbrains.kotlin.analysis.api.fir.annotations.KtFirAnnotationListForDeclaration +import org.jetbrains.kotlin.analysis.api.fir.symbols.pointers.KtFirTypeParameterSymbolPointer +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.KtTypeParameterSymbol +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.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.types.isNullableAny +import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols + +/** + * [KtFirTypeParameterSymbolBase] provides shared implementations for [KtFirTypeParameterSymbol] and [KtFirPsiJavaTypeParameterSymbol]. + */ +internal sealed class KtFirTypeParameterSymbolBase : KtTypeParameterSymbol(), KtFirSymbol { + override val annotationsList: KtAnnotationsList + get() = withValidityAssertion { + KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token) + } + + override val upperBounds: List by cached { + firSymbol.resolvedBounds.mapNotNull { type -> + if (type.isNullableAny) return@mapNotNull null + builder.typeBuilder.buildKtType(type) + } + } + + context(KtAnalysisSession) + override fun createPointer(): KtSymbolPointer = withValidityAssertion { + KtPsiBasedSymbolPointer.createForSymbolFromSource(this)?.let { return it } + + val containingDeclarationSymbol = firSymbol.containingDeclarationSymbol + val typeParameters = containingDeclarationSymbol.typeParameterSymbols + requireNotNull(typeParameters) { "Containing declaration symbol: ${containingDeclarationSymbol::class.simpleName}" } + + KtFirTypeParameterSymbolPointer( + ownerPointer = requireOwnerPointer(), + name = name, + index = typeParameters.indexOf(firSymbol), + ) + } + + override fun equals(other: Any?): Boolean = symbolEquals(other) + override fun hashCode(): Int = symbolHashCode() +} diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt index 321ef93f22e..ec443d067d8 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/markers.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.analysis.api.symbols.markers -import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol import org.jetbrains.kotlin.name.Name @@ -20,11 +19,4 @@ public interface KtNamedSymbol : KtPossiblyNamedSymbol { public interface KtSymbolWithTypeParameters : KtSymbol { public val typeParameters: List - - /** - * The names of [typeParameters]. Using this property should be preferred if only the names of type parameters are needed, because some - * symbol implementations may avoid building the full list of type parameters. - */ - public val typeParameterNames: List - get() = withValidityAssertion { typeParameters.map { it.name } } } \ No newline at end of file