Analysis API: separate constant values from annotation values

This commit is contained in:
Ilya Kirillov
2021-11-23 20:44:39 +01:00
parent 47c1da2845
commit f722a54c78
53 changed files with 302 additions and 415 deletions
@@ -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()
@@ -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)
@@ -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) {
@@ -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)
@@ -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
}
}
@@ -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)
}
@@ -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 -> {
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,6 +0,0 @@
annotation class Annotation(vararg val strings: String)
annotation class AnnotationInner(val value: Annotation)
@AnnotationInner(<expr>Annotation("v1")</expr>)
class C
@@ -1,5 +0,0 @@
expression: Annotation("v1")
constant_value: KtAnnotationConstantValue(Annotation, (strings = KtArrayConstantValue [
KtLiteralConstantValue(constantValueKind=String, value=v1)
]))
constant: null
@@ -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
@@ -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
@@ -1,10 +0,0 @@
enum class Color {
R,
G,
B
}
annotation class Annotation(val color : Color)
@Annotation(<expr>Color.R</expr>)
class C
@@ -1,3 +0,0 @@
expression: Color.R
constant_value: KtEnumEntryConstantValue(/Color.R)
constant: null
@@ -1,3 +1,3 @@
expression: 42
constant_value: KtLiteralConstantValue(constantValueKind=Byte, value=42)
constant: 42
constantValueKind: Byte
@@ -1,3 +1,3 @@
expression: 42 / 0
constant_value: KtErrorValue(Division by zero)
constant: null
constant: error("Division by zero")
constantValueKind: Error
@@ -1,3 +1,3 @@
expression: 42 / 0
constant_value: KtErrorValue(/ by zero)
constant: null
constant: error("/ by zero")
constantValueKind: Error
@@ -1,3 +1,3 @@
expression: 3.14
constant_value: KtLiteralConstantValue(constantValueKind=Double, value=3.14)
constant: 3.14
constantValueKind: Double
@@ -1,3 +1,3 @@
expression: 3.14f
constant_value: KtLiteralConstantValue(constantValueKind=Float, value=3.14)
constant: 3.14
constantValueKind: Float
@@ -1,3 +1,3 @@
expression: 42
constant_value: KtLiteralConstantValue(constantValueKind=Int, value=42)
constant: 42
constantValueKind: Int
@@ -1,3 +1,3 @@
expression: 42
constant_value: KtLiteralConstantValue(constantValueKind=Long, value=42)
constant: 42
constantValueKind: Long
@@ -1,3 +1,3 @@
expression: 42u
constant_value: KtLiteralConstantValue(constantValueKind=UInt, value=42)
constant: 42
constantValueKind: Long
@@ -1,3 +1,3 @@
expression: "42"
constant_value: KtLiteralConstantValue(constantValueKind=String, value=42)
constant: 42
constant: "42"
constantValueKind: String