Analysis API: separate constant values from annotation values
This commit is contained in:
@@ -8,8 +8,7 @@ package org.jetbrains.kotlin.analysis.api.fir
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplication
|
||||
import org.jetbrains.kotlin.analysis.api.fir.annotations.fullyExpandedClassId
|
||||
import org.jetbrains.kotlin.analysis.api.fir.annotations.mapAnnotationParameters
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.KtFirConstantValueConverter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.utils.cached
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
@@ -26,7 +25,6 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirImplicitInvokeCall
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtCallElement
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
/**
|
||||
@@ -80,7 +78,7 @@ internal fun FirAnnotation.toKtAnnotationApplication(useSiteSession: FirSession)
|
||||
fullyExpandedClassId(useSiteSession),
|
||||
psi as? KtAnnotationEntry,
|
||||
useSiteTarget,
|
||||
KtFirConstantValueConverter.toNamedConstantValue(
|
||||
FirAnnotationValueConverter.toNamedConstantValue(
|
||||
mapAnnotationParameters(this, useSiteSession),
|
||||
useSiteSession,
|
||||
)
|
||||
|
||||
+10
-11
@@ -5,18 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.fir.components
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtErrorValue
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEvaluator
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtCompileTimeConstantProvider
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.KtFirConstantValueConverter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEvaluator
|
||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
internal class KtFirCompileTimeConstantProvider(
|
||||
@@ -24,14 +24,13 @@ internal class KtFirCompileTimeConstantProvider(
|
||||
override val token: ValidityToken,
|
||||
) : KtCompileTimeConstantProvider(), KtFirAnalysisSessionComponent {
|
||||
|
||||
override fun evaluate(expression: KtExpression): KtAnnotationValue? = withValidityAssertion {
|
||||
override fun evaluate(expression: KtExpression): KtConstantValue? = withValidityAssertion {
|
||||
when (val fir = expression.getOrBuildFir(firResolveState)) {
|
||||
is FirExpression -> {
|
||||
try {
|
||||
FirCompileTimeConstantEvaluator.evaluate(fir)?.let { KtFirConstantValueConverter.toConstantValue(it) }
|
||||
?: KtFirConstantValueConverter.toConstantValue(fir, firResolveState.rootModuleSession)
|
||||
FirCompileTimeConstantEvaluator.evaluateAsKtConstantExpression(fir)
|
||||
} catch (e: ArithmeticException) {
|
||||
KtErrorValue(e.localizedMessage)
|
||||
KtConstantValue.KtErrorConstantValue(e.localizedMessage, fir.psi as? KtElement)
|
||||
}
|
||||
}
|
||||
// For invalid code like the following,
|
||||
|
||||
+6
-9
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.analysis.api.fir.evaluate
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValueFactory
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
@@ -20,8 +21,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.ArrayFqNames
|
||||
|
||||
internal object KtFirConstantValueConverter {
|
||||
|
||||
internal object FirAnnotationValueConverter {
|
||||
fun toNamedConstantValue(
|
||||
argumentMapping: Map<String, FirExpression>,
|
||||
session: FirSession,
|
||||
@@ -33,13 +33,10 @@ internal object KtFirConstantValueConverter {
|
||||
)
|
||||
}
|
||||
|
||||
fun <T> toConstantValue(
|
||||
firConstExpression: FirConstExpression<T>,
|
||||
): KtLiteralAnnotationValue<T> =
|
||||
firConstExpression.convertConstantExpression()
|
||||
|
||||
private fun <T> FirConstExpression<T>.convertConstantExpression(): KtLiteralAnnotationValue<T> =
|
||||
KtLiteralAnnotationValue(kind, value, psi as? KtElement)
|
||||
private fun <T> FirConstExpression<T>.convertConstantExpression(): KtConstantAnnotationValue? {
|
||||
val constantValue = KtConstantValueFactory.createConstantValue(value, psi as? KtElement) ?: return null
|
||||
return KtConstantAnnotationValue(constantValue)
|
||||
}
|
||||
|
||||
private fun Collection<FirExpression>.convertConstantExpression(
|
||||
session: FirSession,
|
||||
+11
-8
@@ -6,7 +6,8 @@
|
||||
package org.jetbrains.kotlin.analysis.api.fir.evaluate
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValueFactory
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
@@ -14,10 +15,12 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.argument
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.*
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.CompileTimeType
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.evalBinaryOp
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.evalUnaryOp
|
||||
@@ -28,7 +31,6 @@ import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
* and the argument, are compile-time constant as well.
|
||||
*/
|
||||
internal object FirCompileTimeConstantEvaluator {
|
||||
|
||||
// TODO: Handle boolean operators, const property loading, class reference, array, annotation values, etc.
|
||||
fun evaluate(expression: FirExpression): FirConstExpression<*>? =
|
||||
when (expression) {
|
||||
@@ -37,9 +39,9 @@ internal object FirCompileTimeConstantEvaluator {
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun evaluateAsKtConstantExpression(expression: FirExpression): KtAnnotationValue? {
|
||||
fun evaluateAsKtConstantExpression(expression: FirExpression): KtConstantValue? {
|
||||
val evaluated = evaluate(expression) ?: return null
|
||||
return KtFirConstantValueConverter.toConstantValue(evaluated)
|
||||
return KtConstantValueFactory.createConstantValue(evaluated.value, evaluated.psi as? KtElement)
|
||||
}
|
||||
|
||||
// TODO: Rework to handle nested expressions
|
||||
@@ -106,7 +108,7 @@ internal object FirCompileTimeConstantEvaluator {
|
||||
kind.toCompileTimeType(),
|
||||
kind.convertToNumber(value as? Number)!!
|
||||
)?.let {
|
||||
it.toConstantValueKind()?.toConstExpression(source, it)
|
||||
it.toConstantValueKind().toConstExpression(source, it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +125,7 @@ internal object FirCompileTimeConstantEvaluator {
|
||||
other.kind.toCompileTimeType(),
|
||||
other.kind.convertToNumber(other.value as? Number)!!
|
||||
)?.let {
|
||||
it.toConstantValueKind()?.toConstExpression(source, it)
|
||||
it.toConstantValueKind().toConstExpression(source, it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +178,7 @@ internal object FirCompileTimeConstantEvaluator {
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun <T : Any> T.toConstantValueKind(): ConstantValueKind<*>? =
|
||||
private fun <T> T.toConstantValueKind(): ConstantValueKind<*> =
|
||||
when (this) {
|
||||
is Byte -> ConstantValueKind.Byte
|
||||
is Double -> ConstantValueKind.Double
|
||||
@@ -189,7 +191,8 @@ internal object FirCompileTimeConstantEvaluator {
|
||||
is String -> ConstantValueKind.String
|
||||
is Boolean -> ConstantValueKind.Boolean
|
||||
|
||||
else -> null
|
||||
null -> ConstantValueKind.Null
|
||||
else -> error("Unknown constant value")
|
||||
}
|
||||
|
||||
private fun ConstantValueKind<*>.convertToNumber(value: Number?): Number? {
|
||||
|
||||
+4
-4
@@ -7,8 +7,8 @@ package org.jetbrains.kotlin.analysis.api.fir.renderer
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.fir.annotations.mapAnnotationParameters
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEvaluator
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.KtFirConstantValueConverter
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtConstantValueRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValueRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
@@ -57,8 +57,8 @@ private fun renderAndSortAnnotationArguments(descriptor: FirAnnotation, session:
|
||||
|
||||
private fun renderConstant(value: FirExpression, useSiteSession: FirSession): String {
|
||||
val evaluated = FirCompileTimeConstantEvaluator.evaluate(value)
|
||||
val constantValue = KtFirConstantValueConverter.toConstantValue(evaluated ?: value, useSiteSession)
|
||||
val constantValue = FirAnnotationValueConverter.toConstantValue(evaluated ?: value, useSiteSession)
|
||||
?: KtUnsupportedAnnotationValue
|
||||
|
||||
return KtConstantValueRenderer.render(constantValue)
|
||||
return KtAnnotationValueRenderer.render(constantValue)
|
||||
}
|
||||
|
||||
-48
@@ -24,54 +24,6 @@ public class FirCompileTimeConstantEvaluatorTestGenerated extends AbstractFirCom
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_arrayOf.kt")
|
||||
public void testAnnotationInAnnotation_arrayOf() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/annotationInAnnotation_arrayOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_collectionLiteral.kt")
|
||||
public void testAnnotationInAnnotation_collectionLiteral() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/annotationInAnnotation_collectionLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_collectionLiteral_spread.kt")
|
||||
public void testAnnotationInAnnotation_collectionLiteral_spread() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/annotationInAnnotation_collectionLiteral_spread.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_multipleAnnotations_arrayOf.kt")
|
||||
public void testAnnotationInAnnotation_multipleAnnotations_arrayOf() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/annotationInAnnotation_multipleAnnotations_arrayOf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_multipleAnnotations_collectionLiteral.kt")
|
||||
public void testAnnotationInAnnotation_multipleAnnotations_collectionLiteral() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/annotationInAnnotation_multipleAnnotations_collectionLiteral.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_single.kt")
|
||||
public void testAnnotationInAnnotation_single() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/annotationInAnnotation_single.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationInAnnotation_vararg.kt")
|
||||
public void testAnnotationInAnnotation_vararg() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/annotationInAnnotation_vararg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumAsAnnotationValue.kt")
|
||||
public void testEnumAsAnnotationValue() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/enumAsAnnotationValue.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyInit_Byte.kt")
|
||||
public void testPropertyInit_Byte() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user