FIR IDE: more comprehensive abstractions of annotation values
This commit is contained in:
committed by
Ilya Kirillov
parent
fe41c4513f
commit
6ef2dad895
+1
-5
@@ -84,7 +84,6 @@ internal class KtSymbolByFirBuilder private constructor(
|
||||
filesCache = BuilderCache(),
|
||||
)
|
||||
|
||||
|
||||
fun createReadOnlyCopy(newResolveState: FirModuleResolveState): KtSymbolByFirBuilder {
|
||||
check(!withReadOnlyCaching) { "Cannot create readOnly KtSymbolByFirBuilder from a readonly one" }
|
||||
return KtSymbolByFirBuilder(
|
||||
@@ -99,7 +98,6 @@ internal class KtSymbolByFirBuilder private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun buildSymbol(fir: FirDeclaration): KtSymbol {
|
||||
return when (fir) {
|
||||
is FirClassLikeDeclaration -> classifierBuilder.buildClassLikeSymbol(fir)
|
||||
@@ -109,11 +107,9 @@ internal class KtSymbolByFirBuilder private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun buildEnumEntrySymbol(fir: FirEnumEntry) = symbolsCache.cache(fir) { KtFirEnumEntrySymbol(fir, resolveState, token, this) }
|
||||
|
||||
|
||||
fun buildFileSymbol(fir: FirFile) = filesCache.cache(fir) { KtFirFileSymbol(fir, resolveState, token) }
|
||||
fun buildFileSymbol(fir: FirFile) = filesCache.cache(fir) { KtFirFileSymbol(fir, resolveState, token, this) }
|
||||
|
||||
private val packageProvider = project.createPackageProvider(GlobalSearchScope.allScope(project))//todo scope
|
||||
|
||||
|
||||
+6
-3
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirEle
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtCompileTimeConstantProvider
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.utils.convertConstantExpression
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSimpleConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
|
||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -22,9 +22,12 @@ internal class KtFirCompileTimeConstantProvider(
|
||||
override val token: ValidityToken,
|
||||
) : KtCompileTimeConstantProvider(), KtFirAnalysisSessionComponent {
|
||||
|
||||
override fun evaluate(expression: KtExpression): KtSimpleConstantValue<*>? = withValidityAssertion {
|
||||
override fun evaluate(expression: KtExpression): KtConstantValue? = withValidityAssertion {
|
||||
when (val fir = expression.getOrBuildFir(firResolveState)) {
|
||||
is FirExpression -> FirCompileTimeConstantEvaluator().evaluate(fir)?.convertConstantExpression()
|
||||
is FirExpression -> {
|
||||
FirCompileTimeConstantEvaluator().evaluate(fir)?.convertConstantExpression()
|
||||
?: fir.convertConstantExpression(firResolveState.rootModuleSession, firSymbolBuilder)
|
||||
}
|
||||
else -> throwUnexpectedFirElementError(fir, expression)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ internal class FirCompileTimeConstantEvaluator {
|
||||
// This is no longer used during FIR2IR where an inner expression is recursively rewritten to ConstExpression if possible.
|
||||
// Maybe rewrite this to a recursive version with caching either here or in provider.
|
||||
private fun evaluate(functionCall: FirFunctionCall): FirConstExpression<*>? {
|
||||
val function = functionCall.getOriginalFunction()!! as FirSimpleFunction
|
||||
val function = functionCall.getOriginalFunction()!! as? FirSimpleFunction ?: return null
|
||||
|
||||
val opr1 = functionCall.explicitReceiver as? FirConstExpression<*> ?: return null
|
||||
opr1.evaluate(function)?.let {
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ internal class KtFirAnonymousObjectSymbol(
|
||||
override val firRef = firRef(fir, resolveState)
|
||||
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ internal class KtFirConstructorSymbol(
|
||||
|
||||
override val visibility: Visibility get() = getVisibility()
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+3
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.analysis.api.fir.symbols
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.analysis.api.fir.findPsi
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
|
||||
@@ -26,6 +27,7 @@ internal class KtFirFileSymbol(
|
||||
fir: FirFile,
|
||||
resolveState: FirModuleResolveState,
|
||||
override val token: ValidityToken,
|
||||
_builder: KtSymbolByFirBuilder,
|
||||
) : KtFileSymbol(), KtSymbolWithDeclarations, KtFirSymbol<FirFile> {
|
||||
override val firRef = firRef(fir, resolveState)
|
||||
override val psi: PsiElement? by firRef.withFirAndCache { fir -> fir.findPsi(fir.moduleData.session) }
|
||||
@@ -35,7 +37,7 @@ internal class KtFirFileSymbol(
|
||||
TODO("Creating pointers for files from library is not supported yet")
|
||||
}
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ internal class KtFirFunctionSymbol(
|
||||
|
||||
override val hasStableParameterNames: Boolean = firRef.withFir { it.getHasStableParameterNames(it.moduleData.session) }
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+4
-2
@@ -71,7 +71,9 @@ internal class KtFirKotlinPropertySymbol(
|
||||
}
|
||||
|
||||
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
|
||||
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir -> fir.initializer?.convertConstantExpression() }
|
||||
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir ->
|
||||
fir.initializer?.convertConstantExpression(resolveState.rootModuleSession, _builder)
|
||||
}
|
||||
override val symbolKind: KtSymbolKind
|
||||
get() = firRef.withFir { fir ->
|
||||
when (fir.containingClass()?.classId) {
|
||||
@@ -83,7 +85,7 @@ internal class KtFirKotlinPropertySymbol(
|
||||
|
||||
override val visibility: Visibility get() = getVisibility()
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ internal class KtFirNamedClassOrObjectSymbol(
|
||||
else -> possiblyRawVisibility
|
||||
}
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ internal class KtFirPropertyGetterSymbol(
|
||||
}
|
||||
override val modality: Modality get() = getModality()
|
||||
override val visibility: Visibility get() = getVisibility()
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ internal class KtFirPropertySetterSymbol(
|
||||
override val modality: Modality get() = getModality()
|
||||
override val visibility: Visibility get() = getVisibility()
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+4
-2
@@ -59,12 +59,14 @@ internal class KtFirSyntheticJavaPropertySymbol(
|
||||
firRef.receiverTypeAndAnnotations(builder)
|
||||
}
|
||||
override val isExtension: Boolean get() = firRef.withFir { it.receiverTypeRef != null }
|
||||
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir -> fir.initializer?.convertConstantExpression() }
|
||||
override val initializer: KtConstantValue? by firRef.withFirAndCache(FirResolvePhase.BODY_RESOLVE) { fir ->
|
||||
fir.initializer?.convertConstantExpression(resolveState.rootModuleSession, _builder)
|
||||
}
|
||||
|
||||
override val modality: Modality get() = getModality()
|
||||
override val visibility: Visibility get() = getVisibility()
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ internal class KtFirTypeAndAnnotations<T : FirDeclaration>(
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by containingDeclaration.withFirAndCache { fir ->
|
||||
typeRef(fir).annotations.map {
|
||||
KtFirAnnotationCall(containingDeclaration, it)
|
||||
KtFirAnnotationCall(containingDeclaration, it, _builder)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ private fun List<FirTypeRef>.mapToTypeAndAnnotations(
|
||||
builder: KtSymbolByFirBuilder,
|
||||
) = map { typeRef ->
|
||||
val annotations = typeRef.annotations.map { annotation ->
|
||||
KtFirAnnotationCall(containingDeclaration, annotation)
|
||||
KtFirAnnotationCall(containingDeclaration, annotation, builder)
|
||||
}
|
||||
KtSimpleFirTypeAndAnnotations(typeRef.coneType, annotations, builder, containingDeclaration.token)
|
||||
}
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ internal class KtFirValueParameterSymbol(
|
||||
override val annotatedType: KtTypeAndAnnotations by firRef.withFirAndCache(FirResolvePhase.TYPES) { fir ->
|
||||
if (fir.isVararg) {
|
||||
val annotations = fir.returnTypeRef.annotations.map { annotation ->
|
||||
KtFirAnnotationCall(firRef, annotation)
|
||||
KtFirAnnotationCall(firRef, annotation, _builder)
|
||||
}
|
||||
// There SHOULD always be an array element type (even if it is an error type, e.g., unresolved).
|
||||
val arrayElementType = fir.returnTypeRef.coneType.arrayElementType()
|
||||
@@ -58,7 +58,7 @@ internal class KtFirValueParameterSymbol(
|
||||
|
||||
override val hasDefaultValue: Boolean get() = firRef.withFir { it.defaultValue != null }
|
||||
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList() }
|
||||
override val annotations: List<KtAnnotationCall> by cached { firRef.toAnnotationsList(_builder) }
|
||||
override fun containsAnnotation(classId: ClassId): Boolean = firRef.containsAnnotation(classId)
|
||||
override val annotationClassIds: Collection<ClassId> by cached { firRef.getAnnotationClassIds() }
|
||||
|
||||
|
||||
+4
-4
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.fir.symbols.annotations
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
@@ -19,7 +20,8 @@ import org.jetbrains.kotlin.psi.KtCallElement
|
||||
|
||||
internal class KtFirAnnotationCall(
|
||||
private val containingDeclaration: FirRefWithValidityCheck<FirDeclaration>,
|
||||
annotation: FirAnnotation
|
||||
annotation: FirAnnotation,
|
||||
_builder: KtSymbolByFirBuilder,
|
||||
) : KtAnnotationCall() {
|
||||
|
||||
private val annotationCallRef by weakRef(annotation)
|
||||
@@ -39,9 +41,7 @@ internal class KtFirAnnotationCall(
|
||||
override val useSiteTarget: AnnotationUseSiteTarget? get() = annotationCallRef.useSiteTarget
|
||||
|
||||
override val arguments: List<KtNamedConstantValue> by containingDeclaration.withFirAndCache(ResolveType.AnnotationsArguments) { fir ->
|
||||
mapAnnotationParameters(annotationCallRef, fir.moduleData.session).map { (name, expression) ->
|
||||
KtNamedConstantValue(name, expression.convertConstantExpression())
|
||||
}
|
||||
mapAnnotationParameters(annotationCallRef, fir.moduleData.session).toNamedConstantValue(fir.moduleData.session, _builder)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
||||
+5
-3
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.fir.symbols.annotations
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
@@ -15,12 +16,13 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType
|
||||
import org.jetbrains.kotlin.analysis.api.fir.utils.FirRefWithValidityCheck
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
|
||||
internal fun FirAnnotation.getClassId(session: FirSession): ClassId? =
|
||||
coneClassLikeType?.fullyExpandedType(session)?.classId
|
||||
|
||||
internal fun FirRefWithValidityCheck<FirAnnotatedDeclaration>.toAnnotationsList() = withFir { fir ->
|
||||
fir.annotations.map { KtFirAnnotationCall(this, it) }
|
||||
internal fun FirRefWithValidityCheck<FirAnnotatedDeclaration>.toAnnotationsList(
|
||||
builder: KtSymbolByFirBuilder
|
||||
) = withFir { fir ->
|
||||
fir.annotations.map { KtFirAnnotationCall(this, it, builder) }
|
||||
}
|
||||
|
||||
internal fun FirRefWithValidityCheck<FirAnnotatedDeclaration>.containsAnnotation(classId: ClassId): Boolean =
|
||||
|
||||
+80
-9
@@ -5,14 +5,12 @@
|
||||
package org.jetbrains.kotlin.analysis.api.fir.utils
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
|
||||
import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.resolved
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.primaryConstructor
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
@@ -24,15 +22,18 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.withFirDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSimpleConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtUnsupportedConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.ArrayFqNames
|
||||
|
||||
internal fun PsiElement.unwrap(): PsiElement {
|
||||
return when (this) {
|
||||
@@ -96,13 +97,83 @@ internal fun mapAnnotationParameters(annotation: FirAnnotation, session: FirSess
|
||||
return resultSet
|
||||
}
|
||||
|
||||
internal fun Map<String, FirExpression>.toNamedConstantValue(
|
||||
session: FirSession,
|
||||
firSymbolBuilder: KtSymbolByFirBuilder
|
||||
): List<KtNamedConstantValue> =
|
||||
map { (name, expression) ->
|
||||
KtNamedConstantValue(
|
||||
name,
|
||||
expression.convertConstantExpression(session, firSymbolBuilder) ?: KtUnsupportedConstantValue
|
||||
)
|
||||
}
|
||||
|
||||
internal fun <T> FirConstExpression<T>.convertConstantExpression(): KtSimpleConstantValue<T> = KtSimpleConstantValue(kind, value)
|
||||
|
||||
internal fun FirExpression.convertConstantExpression(): KtConstantValue =
|
||||
when (this) {
|
||||
private fun Collection<FirExpression>.convertConstantExpression(
|
||||
session: FirSession,
|
||||
firSymbolBuilder: KtSymbolByFirBuilder
|
||||
): Collection<KtConstantValue> =
|
||||
mapNotNull { it.convertConstantExpression(session, firSymbolBuilder) }
|
||||
|
||||
private fun Collection<KtConstantValue>.toArrayConstantValueIfNecessary(): KtConstantValue {
|
||||
return if (size == 1)
|
||||
single()
|
||||
else
|
||||
KtArrayConstantValue(this)
|
||||
}
|
||||
|
||||
internal fun FirExpression.convertConstantExpression(
|
||||
session: FirSession,
|
||||
firSymbolBuilder: KtSymbolByFirBuilder
|
||||
): KtConstantValue? {
|
||||
return when (this) {
|
||||
is FirConstExpression<*> -> convertConstantExpression()
|
||||
is FirNamedArgumentExpression -> {
|
||||
expression.convertConstantExpression(session, firSymbolBuilder)
|
||||
}
|
||||
is FirVarargArgumentsExpression -> {
|
||||
arguments.convertConstantExpression(session, firSymbolBuilder).toArrayConstantValueIfNecessary()
|
||||
}
|
||||
is FirArrayOfCall -> {
|
||||
argumentList.arguments.convertConstantExpression(session, firSymbolBuilder).toArrayConstantValueIfNecessary()
|
||||
}
|
||||
is FirFunctionCall -> {
|
||||
val reference = calleeReference as? FirResolvedNamedReference ?: return null
|
||||
when (val resolvedSymbol = reference.resolvedSymbol) {
|
||||
is FirConstructorSymbol -> {
|
||||
val classSymbol = resolvedSymbol.getContainingClassSymbol(session) ?: return null
|
||||
if ((classSymbol.fir as? FirClass)?.classKind == ClassKind.ANNOTATION_CLASS) {
|
||||
val resultMap = mutableMapOf<String, FirExpression>()
|
||||
argumentMapping?.entries?.forEach { (arg, param) ->
|
||||
resultMap[param.name.asString()] = arg
|
||||
}
|
||||
KtAnnotationConstantValue(
|
||||
resolvedSymbol.callableId.className?.asString(),
|
||||
resultMap.toNamedConstantValue(session, firSymbolBuilder)
|
||||
)
|
||||
} else null
|
||||
}
|
||||
is FirNamedFunctionSymbol -> {
|
||||
if (resolvedSymbol.callableId.asSingleFqName() in ArrayFqNames.ARRAY_CALL_FQ_NAMES)
|
||||
argumentList.arguments.convertConstantExpression(session, firSymbolBuilder).toArrayConstantValueIfNecessary()
|
||||
else null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
is FirPropertyAccessExpression -> {
|
||||
val reference = calleeReference as? FirResolvedNamedReference ?: return null
|
||||
when (val resolvedSymbol = reference.resolvedSymbol) {
|
||||
is FirEnumEntrySymbol -> {
|
||||
KtEnumEntryValue(resolvedSymbol.fir.buildSymbol(firSymbolBuilder) as KtEnumEntrySymbol)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> KtUnsupportedConstantValue
|
||||
}
|
||||
}
|
||||
|
||||
internal fun KtTypeNullability.toConeNullability() = when (this) {
|
||||
KtTypeNullability.NULLABLE -> ConeNullability.NULLABLE
|
||||
|
||||
+42
-3
@@ -9,23 +9,62 @@ import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
|
||||
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
|
||||
import org.jetbrains.kotlin.analysis.api.analyse
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.assertions
|
||||
|
||||
abstract class AbstractCompileTimeConstantEvaluatorTest : AbstractHLApiSingleFileTest() {
|
||||
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
|
||||
val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile) as KtExpression
|
||||
val element = testServices.expressionMarkerProvider.getSelectedElement(ktFile)
|
||||
val expression = when (element) {
|
||||
is KtExpression -> element
|
||||
is KtValueArgument -> element.getArgumentExpression()
|
||||
else -> null
|
||||
} ?: testServices.assertions.fail { "Unsupported expression: $element" }
|
||||
val constantValue = executeOnPooledThreadInReadAction {
|
||||
analyse(expression) { expression.evaluate() }
|
||||
}
|
||||
val actual = buildString {
|
||||
appendLine("expression: ${expression.text}")
|
||||
appendLine("constant_value: $constantValue")
|
||||
appendLine("constant: ${constantValue?.toConst()}")
|
||||
appendLine("constant_value: ${analyse(ktFile) { constantValue?.stringRepresentation() }}")
|
||||
appendLine("constant: ${(constantValue as? KtSimpleConstantValue<*>)?.toConst()}")
|
||||
}
|
||||
testServices.assertions.assertEqualsToFile(testDataFileSibling(".txt"), actual)
|
||||
}
|
||||
|
||||
private fun KtConstantValue.stringRepresentation(): String {
|
||||
return when (this) {
|
||||
is KtArrayConstantValue -> buildString {
|
||||
appendLine("KtArrayConstantValue [")
|
||||
appendLine(INDENT, values.joinToString(separator = "\n") { it.stringRepresentation() })
|
||||
append("]")
|
||||
}
|
||||
is KtAnnotationConstantValue -> buildString {
|
||||
append("KtAnnotationConstantValue(")
|
||||
append(fqName)
|
||||
append(", ")
|
||||
arguments.joinTo(this, separator = ", ", prefix = "(", postfix = ")") {
|
||||
"${it.name} = ${it.expression.stringRepresentation()}"
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
is KtEnumEntryValue -> buildString {
|
||||
append("KtEnumEntryValue(")
|
||||
append(enumEntrySymbol.callableIdIfNonLocal ?: enumEntrySymbol.name)
|
||||
append(")")
|
||||
}
|
||||
is KtSimpleConstantValue<*> -> toString()
|
||||
is KtUnsupportedConstantValue -> "KtUnsupportedConstantValue"
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendLine(indent: Int, value: String) {
|
||||
appendLine(value.prependIndent(" ".repeat(indent)))
|
||||
}
|
||||
}
|
||||
|
||||
private const val INDENT = 2
|
||||
|
||||
+36
@@ -24,6 +24,36 @@ public class CompileTimeConstantEvaluatorTestGenerated extends AbstractCompileTi
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/compileTimeConstantEvaluator"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_arrayOf.kt")
|
||||
public void testAnnotationInAnnotation_arrayOf() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_arrayOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_collectionLiteral.kt")
|
||||
public void testAnnotationInAnnotation_collectionLiteral() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_collectionLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_multipleAnnotations_arrayOf.kt")
|
||||
public void testAnnotationInAnnotation_multipleAnnotations_arrayOf() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_multipleAnnotations_arrayOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_multipleAnnotations_collectionLiteral.kt")
|
||||
public void testAnnotationInAnnotation_multipleAnnotations_collectionLiteral() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/annotationInAnnotation_multipleAnnotations_collectionLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumAsAnnotationValue.kt")
|
||||
public void testEnumAsAnnotationValue() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/enumAsAnnotationValue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyInit_Byte.kt")
|
||||
public void testPropertyInit_Byte() throws Exception {
|
||||
@@ -59,4 +89,10 @@ public class CompileTimeConstantEvaluatorTestGenerated extends AbstractCompileTi
|
||||
public void testPropertyInit_UInt() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_UInt.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("stringLiteral.kt")
|
||||
public void testStringLiteral() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/stringLiteral.kt");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -5,14 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.components
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSimpleConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtConstantValue
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
public abstract class KtCompileTimeConstantProvider : KtAnalysisSessionComponent() {
|
||||
public abstract fun evaluate(expression: KtExpression): KtSimpleConstantValue<*>?
|
||||
public abstract fun evaluate(expression: KtExpression): KtConstantValue?
|
||||
}
|
||||
|
||||
public interface KtCompileTimeConstantProviderMixIn : KtAnalysisSessionMixIn {
|
||||
public fun KtExpression.evaluate(): KtSimpleConstantValue<*>? =
|
||||
public fun KtExpression.evaluate(): KtConstantValue? =
|
||||
analysisSession.compileTimeConstantProvider.evaluate(this)
|
||||
}
|
||||
|
||||
+2
@@ -87,6 +87,7 @@ public object DebugSymbolRenderer {
|
||||
is KtFunctionSymbol -> renderValue(value.callableIdIfNonLocal ?: "<local>/${value.name}")
|
||||
is KtSamConstructorSymbol -> renderValue(value.callableIdIfNonLocal ?: "<local>/${value.name}")
|
||||
is KtConstructorSymbol -> "<constructor>"
|
||||
is KtEnumEntrySymbol -> renderValue(value.callableIdIfNonLocal ?: "<local>/${value.name}")
|
||||
is KtNamedSymbol -> renderValue(value.name)
|
||||
is KtPropertyGetterSymbol -> "<getter>"
|
||||
is KtPropertySetterSymbol -> "<setter>"
|
||||
@@ -95,6 +96,7 @@ public object DebugSymbolRenderer {
|
||||
"${value::class.simpleName!!}($symbolTag)"
|
||||
}
|
||||
is KtSimpleConstantValue<*> -> renderValue(value.value)
|
||||
is KtEnumEntryValue -> "KtEnumEntryValue(${renderValue(value.enumEntrySymbol)})"
|
||||
is KtNamedConstantValue -> "${renderValue(value.name)} = ${renderValue(value.expression)}"
|
||||
is KtAnnotationCall -> buildString {
|
||||
append(renderValue(value.classId))
|
||||
|
||||
+29
@@ -5,11 +5,40 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.symbols.markers
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtEnumEntrySymbol
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
/**
|
||||
* Annotation values are expected to be compile-time constants. According to the
|
||||
* [spec](https://kotlinlang.org/spec/annotations.html#annotation-values),
|
||||
* allowed kinds are:
|
||||
* * integer types,
|
||||
* * string type,
|
||||
* * enum types,
|
||||
* * other annotation types, and
|
||||
* * array of aforementioned types
|
||||
*
|
||||
* [KtSimpleConstantValue] covers first two kinds;
|
||||
* [KtEnumEntryValue] corresponds to enum types;
|
||||
* [KtAnnotationConstantValue] represents annotation types (with annotation fq name and arguments); and
|
||||
* [KtArrayConstantValue] abstracts an array of [KtConstantValue]s.
|
||||
*/
|
||||
public sealed class KtConstantValue
|
||||
public object KtUnsupportedConstantValue : KtConstantValue()
|
||||
|
||||
public class KtArrayConstantValue(
|
||||
public val values: Collection<KtConstantValue>
|
||||
) : KtConstantValue()
|
||||
|
||||
public class KtAnnotationConstantValue(
|
||||
public val fqName: String?,
|
||||
public val arguments: List<KtNamedConstantValue>
|
||||
) : KtConstantValue()
|
||||
|
||||
public class KtEnumEntryValue(
|
||||
public val enumEntrySymbol: KtEnumEntrySymbol
|
||||
) : KtConstantValue()
|
||||
|
||||
public data class KtSimpleConstantValue<T>(val constantValueKind: ConstantValueKind<T>, val value: T) : KtConstantValue() {
|
||||
public fun toConst(): Any? {
|
||||
return (value as? Long)?.let {
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation(strings = arrayOf("v1", "v2"))</expr>)
|
||||
class C
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
expression: Annotation(strings = arrayOf("v1", "v2"))
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v1)
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation(["v1", "v2"])</expr>)
|
||||
class C
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
expression: Annotation(["v1", "v2"])
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v1)
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationArray(vararg val annos: Annotation)
|
||||
|
||||
@AnnotationArray(<expr>annos = arrayOf(Annotation("v1", "v2"), Annotation(strings = arrayOf("v3", "v4")))</expr>)
|
||||
class C
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
expression: arrayOf(Annotation("v1", "v2"), Annotation(strings = arrayOf("v3", "v4")))
|
||||
constant_value: KtArrayConstantValue [
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v1)
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v3)
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v4)
|
||||
]))
|
||||
]
|
||||
constant: null
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationArray(vararg val annos: Annotation)
|
||||
|
||||
@AnnotationArray(<expr>[Annotation("v1", "v2"), Annotation(["v3", "v4"])]</expr>)
|
||||
class C
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
expression: [Annotation("v1", "v2"), Annotation(["v3", "v4"])]
|
||||
constant_value: KtArrayConstantValue [
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v1)
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v3)
|
||||
KtSimpleConstantValue(constantValueKind=String, value=v4)
|
||||
]))
|
||||
]
|
||||
constant: null
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
enum class Color {
|
||||
R,
|
||||
G,
|
||||
B
|
||||
}
|
||||
|
||||
annotation class Annotation(val color : Color)
|
||||
|
||||
@Annotation(<expr>Color.R</expr>)
|
||||
class C
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
expression: Color.R
|
||||
constant_value: KtEnumEntryValue(/Color.R)
|
||||
constant: null
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
annotation class Annotation(vararg val values: String)
|
||||
|
||||
@Annotation(<expr>"42"</expr>)
|
||||
class C
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
expression: "42"
|
||||
constant_value: KtSimpleConstantValue(constantValueKind=String, value=42)
|
||||
constant: 42
|
||||
@@ -296,7 +296,7 @@ KtFirKotlinPropertySymbol:
|
||||
kotlin/Deprecated
|
||||
]
|
||||
annotations: [
|
||||
kotlin/Deprecated(level = KtUnsupportedConstantValue, message = don't use j)
|
||||
kotlin/Deprecated(level = KtEnumEntryValue(KtFirEnumEntrySymbol(kotlin/DeprecationLevel.ERROR)), message = don't use j)
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
callableIdIfNonLocal: /j
|
||||
@@ -332,7 +332,7 @@ KtFirKotlinPropertySymbol:
|
||||
kotlin/Deprecated
|
||||
]
|
||||
annotations: [
|
||||
kotlin/Deprecated(level = KtUnsupportedConstantValue, message = don't use j2)
|
||||
kotlin/Deprecated(level = KtEnumEntryValue(KtFirEnumEntrySymbol(kotlin/DeprecationLevel.HIDDEN)), message = don't use j2)
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
callableIdIfNonLocal: /j2
|
||||
|
||||
@@ -3,7 +3,7 @@ KtFirNamedClassOrObjectSymbol:
|
||||
kotlin/annotation/Target
|
||||
]
|
||||
annotations: [
|
||||
kotlin/annotation/Target(allowedTargets = KtUnsupportedConstantValue)
|
||||
kotlin/annotation/Target(allowedTargets = KtEnumEntryValue(KtFirEnumEntrySymbol(kotlin/annotation/AnnotationTarget.TYPE)))
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
classIdIfNonLocal: Anno1
|
||||
@@ -30,7 +30,7 @@ KtFirNamedClassOrObjectSymbol:
|
||||
kotlin/annotation/Target
|
||||
]
|
||||
annotations: [
|
||||
kotlin/annotation/Target(allowedTargets = KtUnsupportedConstantValue)
|
||||
kotlin/annotation/Target(allowedTargets = KtEnumEntryValue(KtFirEnumEntrySymbol(kotlin/annotation/AnnotationTarget.TYPE)))
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
classIdIfNonLocal: Anno2
|
||||
@@ -57,7 +57,7 @@ KtFirNamedClassOrObjectSymbol:
|
||||
kotlin/annotation/Target
|
||||
]
|
||||
annotations: [
|
||||
kotlin/annotation/Target(allowedTargets = KtUnsupportedConstantValue)
|
||||
kotlin/annotation/Target(allowedTargets = KtEnumEntryValue(KtFirEnumEntrySymbol(kotlin/annotation/AnnotationTarget.TYPE)))
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
classIdIfNonLocal: Anno3
|
||||
@@ -84,7 +84,7 @@ KtFirNamedClassOrObjectSymbol:
|
||||
kotlin/annotation/Target
|
||||
]
|
||||
annotations: [
|
||||
kotlin/annotation/Target(allowedTargets = KtUnsupportedConstantValue)
|
||||
kotlin/annotation/Target(allowedTargets = KtEnumEntryValue(KtFirEnumEntrySymbol(kotlin/annotation/AnnotationTarget.TYPE)))
|
||||
psi: KtAnnotationEntry
|
||||
]
|
||||
classIdIfNonLocal: Anno4
|
||||
|
||||
Reference in New Issue
Block a user