Analysis API: separate constant values from annotation values
This commit is contained in:
+2
-1
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
@@ -21,7 +22,7 @@ internal class KtFe10CompileTimeConstantProvider(
|
||||
override val token: ValidityToken
|
||||
get() = analysisSession.token
|
||||
|
||||
override fun evaluate(expression: KtExpression): KtAnnotationValue? {
|
||||
override fun evaluate(expression: KtExpression): KtConstantValue? {
|
||||
val bindingContext = analysisContext.analyze(expression)
|
||||
val constant = ConstantExpressionEvaluator.getPossiblyErrorConstant(expression, bindingContext)
|
||||
return constant?.toConstantValue(TypeUtils.NO_EXPECTED_TYPE)?.toKtConstantValue()
|
||||
|
||||
+26
-22
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.ba
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.*
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValueFactory
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.*
|
||||
@@ -266,37 +268,34 @@ internal val MemberDescriptor.ktModality: Modality
|
||||
return this.modality
|
||||
}
|
||||
|
||||
internal fun ConstantValue<*>.toKtConstantValue(): KtAnnotationValue {
|
||||
internal fun ConstantValue<*>.toKtConstantValue(): KtConstantValue {
|
||||
return when (this) {
|
||||
is BooleanValue -> KtLiteralAnnotationValue(ConstantValueKind.Boolean, value, null)
|
||||
is CharValue -> KtLiteralAnnotationValue(ConstantValueKind.Char, value, null)
|
||||
is ByteValue -> KtLiteralAnnotationValue(ConstantValueKind.Byte, value, null)
|
||||
is UByteValue -> KtLiteralAnnotationValue(ConstantValueKind.UnsignedByte, value, null)
|
||||
is ShortValue -> KtLiteralAnnotationValue(ConstantValueKind.Short, value, null)
|
||||
is UShortValue -> KtLiteralAnnotationValue(ConstantValueKind.UnsignedShort, value, null)
|
||||
is IntValue -> KtLiteralAnnotationValue(ConstantValueKind.Int, value, null)
|
||||
is UIntValue -> KtLiteralAnnotationValue(ConstantValueKind.UnsignedInt, value, null)
|
||||
is LongValue -> KtLiteralAnnotationValue(ConstantValueKind.Long, value, null)
|
||||
is ULongValue -> KtLiteralAnnotationValue(ConstantValueKind.UnsignedLong, value, null)
|
||||
is FloatValue -> KtLiteralAnnotationValue(ConstantValueKind.Float, value, null)
|
||||
is DoubleValue -> KtLiteralAnnotationValue(ConstantValueKind.Double, value, null)
|
||||
is NullValue -> KtLiteralAnnotationValue(ConstantValueKind.Null, null, null)
|
||||
is StringValue -> KtLiteralAnnotationValue(ConstantValueKind.String, value, null)
|
||||
is ArrayValue -> KtArrayAnnotationValue(value.map { it.toKtConstantValue() }, null)
|
||||
is ErrorValue.ErrorValueWithMessage -> KtConstantValue.KtErrorConstantValue(message, sourcePsi = null)
|
||||
else -> {
|
||||
KtConstantValueFactory.createConstantValue(value)
|
||||
?: error("Unexpected constant value $value")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ConstantValue<*>.toKtAnnotationValue(): KtAnnotationValue {
|
||||
return when (this) {
|
||||
is ArrayValue -> KtArrayAnnotationValue(value.map { it.toKtAnnotationValue() }, null)
|
||||
is EnumValue -> KtEnumEntryAnnotationValue(CallableId(enumClassId, enumEntryName), null)
|
||||
is AnnotationValue -> {
|
||||
val arguments = value.allValueArguments.map { (name, v) -> KtNamedAnnotationValue(name.asString(), v.toKtConstantValue()) }
|
||||
KtAnnotationApplicationValue(
|
||||
KtAnnotationApplication(
|
||||
value.annotationClass?.classId,
|
||||
psi = null,
|
||||
useSiteTarget = null,
|
||||
arguments = arguments
|
||||
arguments = arguments,
|
||||
)
|
||||
)
|
||||
}
|
||||
is ErrorValue -> KtErrorValue(this.toString())
|
||||
else -> KtUnsupportedAnnotationValue
|
||||
is KClassValue -> KtKClassValue(cl)
|
||||
else -> {
|
||||
KtConstantAnnotationValue(toKtConstantValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +435,11 @@ internal fun AnnotationDescriptor.toKtAnnotationApplication(): KtAnnotationAppli
|
||||
annotationClass?.maybeLocalClassId,
|
||||
(source as? PsiSourceElement)?.psi as? KtAnnotationEntry,
|
||||
(this as? LazyAnnotationDescriptor)?.annotationEntry?.useSiteTarget?.getAnnotationUseSiteTarget(),
|
||||
allValueArguments.map { (name, value) -> KtNamedAnnotationValue(name.asString(), value.toKtConstantValue()) }
|
||||
getKtNamedAnnotationArguments(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun AnnotationDescriptor.getKtNamedAnnotationArguments() =
|
||||
allValueArguments.map { (name, value) ->
|
||||
KtNamedAnnotationValue(name.asString(), value.toKtAnnotationValue())
|
||||
}
|
||||
-6
@@ -8,14 +8,11 @@ package org.jetbrains.kotlin.analysis.api.descriptors.utils
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.components.RendererModifier
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.*
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.classId
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.isExplicitOverride
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.ktModality
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.ktVisibility
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtConstantValueRenderer
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -31,9 +28,6 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
import org.jetbrains.kotlin.resolve.constants.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
+3
-3
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.api.descriptors.utils
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.classId
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.getKtNamedAnnotationArguments
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.maybeLocalClassId
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtConstantValue
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
@@ -88,7 +89,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderTypeAnnotationDebug(annotation: AnnotationDescriptor) {
|
||||
val namedValues = annotation.allValueArguments.map { KtNamedAnnotationValue(it.key.asString(), it.value.toKtConstantValue()) }
|
||||
val namedValues = annotation.getKtNamedAnnotationArguments()
|
||||
renderAnnotationDebug(annotation.annotationClass?.classId, namedValues)
|
||||
}
|
||||
|
||||
@@ -115,9 +116,8 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
is KtArrayAnnotationValue ->
|
||||
renderList(value.values, separator = ", ", prefix = "[", postfix = "]") { renderConstantValueDebug(it) }
|
||||
is KtEnumEntryAnnotationValue -> append(value.callableId)
|
||||
is KtLiteralAnnotationValue<*> -> append(value.constantValueKind.asString).append("(").append(value.value).append(")")
|
||||
is KtConstantAnnotationValue -> append(value.constantValue.constantValueKind.asString).append("(").append(value.constantValue.value).append(")")
|
||||
KtUnsupportedAnnotationValue -> append(KtUnsupportedAnnotationValue::class.java.simpleName)
|
||||
is KtErrorValue -> append("<ERROR>")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -7,7 +7,8 @@ package org.jetbrains.kotlin.analysis.api.descriptors.utils
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.classId
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtConstantValueRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValueRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtAnnotationValue
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -31,7 +32,7 @@ internal fun KtFe10RendererConsumer.renderFe10Annotations(annotations: Annotatio
|
||||
renderList(valueArguments, separator = ", ", prefix = "(", postfix = ")", renderWhenEmpty = false) { (name, value) ->
|
||||
append(name.render())
|
||||
append(" = ")
|
||||
append(KtConstantValueRenderer.render(value.toKtConstantValue()))
|
||||
append(KtAnnotationValueRenderer.render(value.toKtAnnotationValue()))
|
||||
}
|
||||
|
||||
append(' ')
|
||||
|
||||
-48
@@ -24,54 +24,6 @@ public class KtFe10CompileTimeConstantEvaluatorTestGenerated extends AbstractKtF
|
||||
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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+5
-41
@@ -5,7 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.impl.base.test.components.compileTimeConstantProvider
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.render
|
||||
import org.jetbrains.kotlin.analysis.api.base.render
|
||||
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
|
||||
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProvider
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest
|
||||
@@ -31,47 +32,10 @@ abstract class AbstractCompileTimeConstantEvaluatorTest(
|
||||
}
|
||||
val actual = buildString {
|
||||
appendLine("expression: ${expression.text}")
|
||||
appendLine("constant_value: ${analyseForTest(expression) { constantValue?.stringRepresentation() }}")
|
||||
appendLine("constant: ${(constantValue as? KtLiteralAnnotationValue<*>)?.toConst()}")
|
||||
appendLine("constant: ${constantValue?.render()}")
|
||||
appendLine("constantValueKind: ${constantValue?.constantValueKind}")
|
||||
}
|
||||
testServices.assertions.assertEqualsToTestDataFileSibling(actual)
|
||||
}
|
||||
|
||||
private fun KtAnnotationValue.stringRepresentation(): String {
|
||||
return when (this) {
|
||||
is KtArrayAnnotationValue -> buildString {
|
||||
appendLine("KtArrayConstantValue [")
|
||||
appendLine(INDENT, values.joinToString(separator = "\n") { it.stringRepresentation() })
|
||||
append("]")
|
||||
}
|
||||
is KtAnnotationApplicationValue -> buildString {
|
||||
append("KtAnnotationConstantValue(")
|
||||
append(annotationValue.classId?.relativeClassName)
|
||||
append(", ")
|
||||
annotationValue.arguments.joinTo(this, separator = ", ", prefix = "(", postfix = ")") {
|
||||
"${it.name} = ${it.expression.stringRepresentation()}"
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
is KtEnumEntryAnnotationValue -> buildString {
|
||||
append("KtEnumEntryConstantValue(")
|
||||
append("$callableId")
|
||||
append(")")
|
||||
}
|
||||
is KtLiteralAnnotationValue<*> -> buildString {
|
||||
append("KtLiteralConstantValue(")
|
||||
append("constantValueKind=${constantValueKind}")
|
||||
append(", ")
|
||||
append("value=${value})")
|
||||
}
|
||||
is KtErrorValue -> "KtErrorValue($message)"
|
||||
is KtUnsupportedAnnotationValue -> "KtUnsupportedConstantValue"
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendLine(indent: Int, value: String) {
|
||||
appendLine(value.prependIndent(" ".repeat(indent)))
|
||||
}
|
||||
}
|
||||
|
||||
private const val INDENT = 2
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.analysis.api
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
public sealed class KtInitializerValue {
|
||||
@@ -13,7 +14,7 @@ public sealed class KtInitializerValue {
|
||||
}
|
||||
|
||||
public class KtConstantInitializerValue(
|
||||
public val constant: KtAnnotationValue,
|
||||
public val constant: KtConstantValue,
|
||||
override val initializerPsi: KtExpression?
|
||||
) : KtInitializerValue()
|
||||
|
||||
|
||||
+12
-31
@@ -5,9 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.annotations
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
/**
|
||||
* Annotation values are expected to be compile-time constants. According to the
|
||||
@@ -19,7 +20,7 @@ import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
* * other annotation types, and
|
||||
* * array of aforementioned types
|
||||
*
|
||||
* [KtLiteralAnnotationValue] covers first two kinds;
|
||||
* [KtConstantAnnotationValue] covers first two kinds;
|
||||
* [KtEnumEntryAnnotationValue] corresponds to enum types;
|
||||
* [KtAnnotationApplicationValue] represents annotation types (with annotation fq name and arguments); and
|
||||
* [KtArrayAnnotationValue] abstracts an array of [KtAnnotationValue]s.
|
||||
@@ -28,12 +29,6 @@ public sealed class KtAnnotationValue(
|
||||
public open val sourcePsi: KtElement? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* This represents an error during expression evaluation or constant conversion.
|
||||
*/
|
||||
public class KtErrorValue(
|
||||
public val message: String
|
||||
) : KtAnnotationValue()
|
||||
|
||||
/**
|
||||
* This represents an unsupported expression used as an annotation value.
|
||||
@@ -47,33 +42,19 @@ public class KtArrayAnnotationValue(
|
||||
|
||||
public class KtAnnotationApplicationValue(
|
||||
public val annotationValue: KtAnnotationApplication,
|
||||
) : KtAnnotationValue()
|
||||
) : KtAnnotationValue() {
|
||||
override val sourcePsi: KtElement? get() = annotationValue.psi
|
||||
}
|
||||
|
||||
|
||||
public class KtEnumEntryAnnotationValue(
|
||||
public val callableId: CallableId?,
|
||||
override val sourcePsi: KtElement?,
|
||||
) : KtAnnotationValue()
|
||||
|
||||
public class KtLiteralAnnotationValue<T>(
|
||||
public val constantValueKind: ConstantValueKind<T>,
|
||||
public val value: T,
|
||||
override val sourcePsi: KtElement?,
|
||||
) : KtAnnotationValue() {
|
||||
public fun toConst(): Any? {
|
||||
return (value as? Long)?.let {
|
||||
when (constantValueKind) {
|
||||
ConstantValueKind.Byte -> it.toByte()
|
||||
ConstantValueKind.Short -> it.toShort()
|
||||
ConstantValueKind.Int -> it.toInt()
|
||||
ConstantValueKind.Float -> it.toFloat()
|
||||
ConstantValueKind.Double -> it.toDouble()
|
||||
public class KtConstantAnnotationValue(
|
||||
public val constantValue: KtConstantValue,
|
||||
) : KtAnnotationValue()
|
||||
|
||||
ConstantValueKind.UnsignedByte -> it.toUByte()
|
||||
ConstantValueKind.UnsignedShort -> it.toUShort()
|
||||
ConstantValueKind.UnsignedInt -> it.toUInt()
|
||||
ConstantValueKind.UnsignedLong -> it.toULong()
|
||||
else -> it
|
||||
}
|
||||
} ?: value
|
||||
}
|
||||
}
|
||||
public fun KtAnnotationValue.render(): String =
|
||||
KtAnnotationValueRenderer.render(this)
|
||||
+6
-26
@@ -3,12 +3,9 @@
|
||||
* 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.symbols.markers
|
||||
package org.jetbrains.kotlin.analysis.api.annotations
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
public object KtConstantValueRenderer {
|
||||
public object KtAnnotationValueRenderer {
|
||||
public fun render(value: KtAnnotationValue): String = buildString {
|
||||
renderConstantValue(value)
|
||||
}
|
||||
@@ -24,11 +21,8 @@ public object KtConstantValueRenderer {
|
||||
is KtEnumEntryAnnotationValue -> {
|
||||
renderEnumEntryConstantValue(value)
|
||||
}
|
||||
is KtErrorValue -> {
|
||||
append("ERROR")
|
||||
}
|
||||
is KtLiteralAnnotationValue<*> -> {
|
||||
renderLiteralConstantValue(value)
|
||||
is KtConstantAnnotationValue -> {
|
||||
renderConstantAnnotationValue(value)
|
||||
}
|
||||
KtUnsupportedAnnotationValue -> {
|
||||
append("KtUnsupportedConstantValue")
|
||||
@@ -36,22 +30,8 @@ public object KtConstantValueRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderLiteralConstantValue(value: KtLiteralAnnotationValue<*>) {
|
||||
when (value.constantValueKind) {
|
||||
ConstantValueKind.String -> {
|
||||
append('"')
|
||||
append(value.value)
|
||||
append('"')
|
||||
}
|
||||
ConstantValueKind.Char -> {
|
||||
append("'")
|
||||
append(value.value)
|
||||
append("'")
|
||||
}
|
||||
else -> {
|
||||
append(value.value)
|
||||
}
|
||||
}
|
||||
private fun StringBuilder.renderConstantAnnotationValue(value: KtConstantAnnotationValue) {
|
||||
append(KtConstantValueRenderer.render(value.constantValue))
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderEnumEntryConstantValue(value: KtEnumEntryAnnotationValue) {
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.annotations
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
public object KtConstantValueRenderer {
|
||||
public fun render(value: KtConstantValue): String = buildString {
|
||||
when (value) {
|
||||
is KtConstantValue.KtStringConstantValue -> {
|
||||
append('"')
|
||||
append(value.value)
|
||||
append('"')
|
||||
}
|
||||
is KtConstantValue.KtCharConstantValue -> {
|
||||
append("'")
|
||||
append(value.value)
|
||||
append("'")
|
||||
}
|
||||
is KtConstantValue.KtErrorConstantValue -> {
|
||||
append("error(\"${value.errorMessage}\")")
|
||||
}
|
||||
else -> {
|
||||
append(value.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.base
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtConstantValueRenderer
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
|
||||
public sealed class KtConstantValue(public val constantValueKind: ConstantValueKind<*>) {
|
||||
public abstract val value: Any?
|
||||
public abstract val sourcePsi: KtElement?
|
||||
|
||||
public class KtNullConstantValue(override val sourcePsi: KtElement?) : KtConstantValue(ConstantValueKind.Null) {
|
||||
override val value: Nothing? get() = null
|
||||
}
|
||||
|
||||
public class KtBooleanConstantValue(
|
||||
override val value: Boolean,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Boolean)
|
||||
|
||||
public class KtCharConstantValue(
|
||||
override val value: Char,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Char)
|
||||
|
||||
public class KtByteConstantValue(
|
||||
override val value: Byte,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Byte)
|
||||
|
||||
public class KtUnsignedByteConstantValue(
|
||||
override val value: UByte,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.UnsignedByte)
|
||||
|
||||
public class KtShortConstantValue(
|
||||
override val value: Short,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Short)
|
||||
|
||||
public class KtUnsignedShortConstantValue(
|
||||
override val value: UShort,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.UnsignedShort)
|
||||
|
||||
public class KtIntConstantValue(
|
||||
override val value: Int,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Int)
|
||||
|
||||
public class KtUnsignedIntConstantValue(
|
||||
override val value: UInt,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.UnsignedInt)
|
||||
|
||||
public class KtLongConstantValue(
|
||||
override val value: Long,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Long)
|
||||
|
||||
public class KtUnsignedLongConstantValue(
|
||||
override val value: ULong,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.UnsignedLong)
|
||||
|
||||
public class KtStringConstantValue(
|
||||
override val value: String,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.String)
|
||||
|
||||
public class KtFloatConstantValue(
|
||||
override val value: Float,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Float)
|
||||
|
||||
public class KtDoubleConstantValue(
|
||||
override val value: Double,
|
||||
override val sourcePsi: KtElement?
|
||||
) : KtConstantValue(ConstantValueKind.Double)
|
||||
|
||||
public class KtErrorConstantValue(
|
||||
public val errorMessage: String,
|
||||
override val sourcePsi: KtElement?,
|
||||
) : KtConstantValue(ConstantValueKind.Error) {
|
||||
override val value: ERROR_VALUE get() = ERROR_VALUE
|
||||
|
||||
public object ERROR_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public fun KtConstantValue.render(): String =
|
||||
KtConstantValueRenderer.render(this)
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.base
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
|
||||
public object KtConstantValueFactory {
|
||||
public fun createConstantValue(value: Any?, expression: KtElement? = null): KtConstantValue? = when (value) {
|
||||
null -> KtConstantValue.KtNullConstantValue(expression)
|
||||
is Boolean -> KtConstantValue.KtBooleanConstantValue(value, expression)
|
||||
is Char -> KtConstantValue.KtCharConstantValue(value, expression)
|
||||
is Byte -> KtConstantValue.KtByteConstantValue(value, expression)
|
||||
is UByte -> KtConstantValue.KtUnsignedByteConstantValue(value, expression)
|
||||
is Short -> KtConstantValue.KtShortConstantValue(value, expression)
|
||||
is UShort -> KtConstantValue.KtUnsignedShortConstantValue(value, expression)
|
||||
is Int -> KtConstantValue.KtIntConstantValue(value, expression)
|
||||
is UInt -> KtConstantValue.KtUnsignedIntConstantValue(value, expression)
|
||||
is Long -> KtConstantValue.KtLongConstantValue(value, expression)
|
||||
is ULong -> KtConstantValue.KtUnsignedLongConstantValue(value, expression)
|
||||
is String -> KtConstantValue.KtStringConstantValue(value, expression)
|
||||
is Float -> KtConstantValue.KtFloatConstantValue(value, expression)
|
||||
is Double -> KtConstantValue.KtDoubleConstantValue(value, expression)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -5,14 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.components
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
public abstract class KtCompileTimeConstantProvider : KtAnalysisSessionComponent() {
|
||||
public abstract fun evaluate(expression: KtExpression): KtAnnotationValue?
|
||||
public abstract fun evaluate(expression: KtExpression): KtConstantValue?
|
||||
}
|
||||
|
||||
public interface KtCompileTimeConstantProviderMixIn : KtAnalysisSessionMixIn {
|
||||
public fun KtExpression.evaluate(): KtAnnotationValue? =
|
||||
public fun KtExpression.evaluate(): KtConstantValue? =
|
||||
analysisSession.compileTimeConstantProvider.evaluate(this)
|
||||
}
|
||||
|
||||
+5
-4
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.analysis.api.KtConstantInitializerValue
|
||||
import org.jetbrains.kotlin.analysis.api.KtInitializerValue
|
||||
import org.jetbrains.kotlin.analysis.api.KtNonConstantInitializerValue
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.analysis.api.base.render
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtSymbolInfoProviderMixIn
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
|
||||
@@ -138,8 +139,8 @@ public object DebugSymbolRenderer {
|
||||
append(")")
|
||||
}
|
||||
|
||||
private fun Block.renderConstantValue(value: KtAnnotationValue) {
|
||||
append(KtConstantValueRenderer.render(value))
|
||||
private fun Block.renderAnnotationValue(value: KtAnnotationValue) {
|
||||
append(KtAnnotationValueRenderer.render(value))
|
||||
}
|
||||
|
||||
private fun Block.renderNamedConstantValue(value: KtNamedAnnotationValue) {
|
||||
@@ -188,7 +189,7 @@ public object DebugSymbolRenderer {
|
||||
// Symbol-related values
|
||||
is KtSymbol -> renderSymbolTag(value)
|
||||
is KtType -> renderType(value)
|
||||
is KtAnnotationValue -> renderConstantValue(value)
|
||||
is KtAnnotationValue -> renderAnnotationValue(value)
|
||||
is KtNamedAnnotationValue -> renderNamedConstantValue(value)
|
||||
is KtInitializerValue -> renderKtInitializerValue(value)
|
||||
is KtAnnotationApplication -> renderAnnotationApplication(value)
|
||||
@@ -215,7 +216,7 @@ public object DebugSymbolRenderer {
|
||||
when (value) {
|
||||
is KtConstantInitializerValue -> {
|
||||
append("KtConstantInitializerValue(")
|
||||
renderConstantValue(value.constant)
|
||||
append(value.constant.render())
|
||||
append(")")
|
||||
}
|
||||
is KtNonConstantInitializerValue -> {
|
||||
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation(strings = arrayOf("v1", "v2"))</expr>)
|
||||
class C
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
expression: Annotation(strings = arrayOf("v1", "v2"))
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation(strings = ["v1", "v2"])</expr>)
|
||||
class C
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
expression: Annotation(strings = ["v1", "v2"])
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation(*["v1", "v2"])</expr>)
|
||||
class C
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
expression: Annotation(*["v1", "v2"])
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationArray(vararg val annos: Annotation)
|
||||
|
||||
@AnnotationArray(annos = <expr>arrayOf(Annotation("v1", "v2"), Annotation(strings = arrayOf("v3", "v4")))</expr>)
|
||||
class C
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
expression: arrayOf(Annotation("v1", "v2"), Annotation(strings = arrayOf("v3", "v4")))
|
||||
constant_value: KtArrayConstantValue [
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v3)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v4)
|
||||
]))
|
||||
]
|
||||
constant: null
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationArray(vararg val annos: Annotation)
|
||||
|
||||
@AnnotationArray(annos = <expr>[Annotation("v1", "v2"), Annotation(strings = ["v3", "v4"])]</expr>)
|
||||
class C
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
expression: [Annotation("v1", "v2"), Annotation(strings = ["v3", "v4"])]
|
||||
constant_value: KtArrayConstantValue [
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v3)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v4)
|
||||
]))
|
||||
]
|
||||
constant: null
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation("v1")</expr>)
|
||||
class C
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
expression: Annotation("v1")
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
]))
|
||||
constant: null
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
annotation class Annotation(vararg val strings: String)
|
||||
|
||||
annotation class AnnotationInner(val value: Annotation)
|
||||
|
||||
@AnnotationInner(<expr>Annotation("v1", "v2")</expr>)
|
||||
class C
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
expression: Annotation("v1", "v2")
|
||||
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v1)
|
||||
KtLiteralConstantValue(constantValueKind=String, value=v2)
|
||||
]))
|
||||
constant: null
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
enum class Color {
|
||||
R,
|
||||
G,
|
||||
B
|
||||
}
|
||||
|
||||
annotation class Annotation(val color : Color)
|
||||
|
||||
@Annotation(<expr>Color.R</expr>)
|
||||
class C
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
expression: Color.R
|
||||
constant_value: KtEnumEntryConstantValue(/Color.R)
|
||||
constant: null
|
||||
analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/propertyInit_Byte.txt
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
expression: 42
|
||||
constant_value: KtLiteralConstantValue(constantValueKind=Byte, value=42)
|
||||
constant: 42
|
||||
constantValueKind: Byte
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: 42 / 0
|
||||
constant_value: KtErrorValue(Division by zero)
|
||||
constant: null
|
||||
constant: error("Division by zero")
|
||||
constantValueKind: Error
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: 42 / 0
|
||||
constant_value: KtErrorValue(/ by zero)
|
||||
constant: null
|
||||
constant: error("/ by zero")
|
||||
constantValueKind: Error
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
expression: 3.14
|
||||
constant_value: KtLiteralConstantValue(constantValueKind=Double, value=3.14)
|
||||
constant: 3.14
|
||||
constantValueKind: Double
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
expression: 3.14f
|
||||
constant_value: KtLiteralConstantValue(constantValueKind=Float, value=3.14)
|
||||
constant: 3.14
|
||||
constantValueKind: Float
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
expression: 42
|
||||
constant_value: KtLiteralConstantValue(constantValueKind=Int, value=42)
|
||||
constant: 42
|
||||
constantValueKind: Int
|
||||
|
||||
analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/propertyInit_Long.txt
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
expression: 42
|
||||
constant_value: KtLiteralConstantValue(constantValueKind=Long, value=42)
|
||||
constant: 42
|
||||
constantValueKind: Long
|
||||
|
||||
analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate/propertyInit_UInt.txt
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
expression: 42u
|
||||
constant_value: KtLiteralConstantValue(constantValueKind=UInt, value=42)
|
||||
constant: 42
|
||||
constantValueKind: Long
|
||||
|
||||
Vendored
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: "42"
|
||||
constant_value: KtLiteralConstantValue(constantValueKind=String, value=42)
|
||||
constant: 42
|
||||
constant: "42"
|
||||
constantValueKind: String
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotatedSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtLiteralAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue
|
||||
|
||||
internal fun KtAnnotatedSymbol.hasJvmSyntheticAnnotation(annotationUseSiteTarget: AnnotationUseSiteTarget? = null): Boolean =
|
||||
hasAnnotation("kotlin/jvm/JvmSynthetic", annotationUseSiteTarget)
|
||||
@@ -31,7 +31,7 @@ internal fun KtAnnotatedSymbol.getJvmNameFromAnnotation(annotationUseSiteTarget:
|
||||
}
|
||||
|
||||
return annotation?.let {
|
||||
(it.arguments.firstOrNull()?.expression as? KtLiteralAnnotationValue<*>)?.value as? String
|
||||
(it.arguments.firstOrNull()?.expression as? KtConstantAnnotationValue)?.constantValue?.value as? String
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -13,7 +13,8 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.analysis.api.isValid
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtKotlinPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtLiteralAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtTypeMappingMode
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
@@ -113,7 +114,7 @@ internal class FirLightFieldForPropertySymbol(
|
||||
if (!propertySymbol.isConst) return@lazyPub null
|
||||
if (!propertySymbol.isVal) return@lazyPub null
|
||||
val constInitializer = propertySymbol.initializer as? KtConstantInitializerValue ?: return@lazyPub null
|
||||
(constInitializer.constant as? KtLiteralAnnotationValue<*>)?.createPsiLiteral(this)
|
||||
(constInitializer.constant as? KtConstantValue)?.createPsiLiteral(this)
|
||||
}
|
||||
|
||||
override fun getInitializer(): PsiExpression? = _initializer
|
||||
|
||||
+20
-19
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.components.DefaultTypeClassIds
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
|
||||
@@ -184,36 +185,36 @@ internal fun KtAnnotationValue.toAnnotationMemberValue(parent: PsiElement): PsiA
|
||||
annotationValue.arguments,
|
||||
annotationValue.psi
|
||||
)
|
||||
else ->
|
||||
createPsiLiteral(parent)?.let {
|
||||
is KtConstantAnnotationValue -> {
|
||||
this.constantValue.createPsiLiteral(parent)?.let {
|
||||
when (it) {
|
||||
is PsiLiteral -> FirPsiLiteral(sourcePsi, parent, it)
|
||||
else -> FirPsiExpression(sourcePsi, parent, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
is KtEnumEntryAnnotationValue -> {
|
||||
val fqName = this.callableId?.asSingleFqName()?.asString() ?: return null
|
||||
val psiExpression = PsiElementFactory.getInstance(parent.project).createExpressionFromText(fqName, parent)
|
||||
FirPsiExpression(sourcePsi, parent, psiExpression)
|
||||
}
|
||||
KtUnsupportedAnnotationValue -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtAnnotationValue.asStringForPsiLiteral(): String? =
|
||||
when (this) {
|
||||
is KtEnumEntryAnnotationValue ->
|
||||
"${callableId?.classId?.asSingleFqName()?.asString() ?: ""}.${callableId?.callableName}"
|
||||
is KtLiteralAnnotationValue<*> -> {
|
||||
when (val value = this.value) {
|
||||
is String -> "\"${escapeString(value)}\""
|
||||
is Long -> "${value}L"
|
||||
is Float -> "${value}f"
|
||||
else -> value?.toString() ?: "null"
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
private fun KtConstantValue.asStringForPsiLiteral(): String =
|
||||
when (val value = value) {
|
||||
is String -> "\"${escapeString(value)}\""
|
||||
is Long -> "${value}L"
|
||||
is Float -> "${value}f"
|
||||
else -> value?.toString() ?: "null"
|
||||
}
|
||||
|
||||
internal fun KtAnnotationValue.createPsiLiteral(parent: PsiElement): PsiExpression? {
|
||||
val asString = asStringForPsiLiteral() ?: return null
|
||||
val instance = PsiElementFactory.getInstance(parent.project)
|
||||
|
||||
internal fun KtConstantValue.createPsiLiteral(parent: PsiElement): PsiExpression? {
|
||||
val asString = asStringForPsiLiteral()
|
||||
return try {
|
||||
instance.createExpressionFromText(asString, parent)
|
||||
PsiElementFactory.getInstance(parent.project).createExpressionFromText(asString, parent)
|
||||
} catch (_: IncorrectOperationException) {
|
||||
null
|
||||
}
|
||||
|
||||
@@ -824,6 +824,9 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
|
||||
+value.toString()
|
||||
+">"
|
||||
}
|
||||
ConstantValueKind.Error -> {
|
||||
+"ERROR_CONSTANT"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -290,6 +290,7 @@ private fun ConstantValueKind<*>.toIrConstKind(): IrConstKind<*> = when (this) {
|
||||
ConstantValueKind.Float -> IrConstKind.Float
|
||||
ConstantValueKind.Double -> IrConstKind.Double
|
||||
ConstantValueKind.IntegerLiteral, ConstantValueKind.UnsignedIntegerLiteral -> throw IllegalArgumentException()
|
||||
ConstantValueKind.Error -> throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
@@ -128,5 +128,6 @@ fun ConstantValueKind<*>.expectedConeType(session: FirSession): ConeKotlinType {
|
||||
|
||||
ConstantValueKind.IntegerLiteral -> constructLiteralType(StandardClassIds.Int)
|
||||
ConstantValueKind.UnsignedIntegerLiteral -> constructLiteralType(StandardClassIds.UInt)
|
||||
ConstantValueKind.Error -> error("Unexpected error ConstantValueKind")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ sealed class ConstantValueKind<T>(val asString: kotlin.String) {
|
||||
object Float : ConstantValueKind<kotlin.Float>("Float")
|
||||
object Double : ConstantValueKind<kotlin.Double>("Double")
|
||||
|
||||
object Error : ConstantValueKind<Nothing>("Error")
|
||||
|
||||
object IntegerLiteral : ConstantValueKind<kotlin.Long>("IntegerLiteral")
|
||||
object UnsignedIntegerLiteral : ConstantValueKind<kotlin.Long>("UnsignedIntegerLiteral")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user