[FIR] Fix a couple of issues in annotation serialization.
This commit is contained in:
committed by
TeamCityServer
parent
3dd27b9b1f
commit
f220e4a5ed
+1
-1
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||
internal object FirAnnotationArgumentVisitor : AnnotationArgumentVisitor<Unit, FirAnnotationArgumentVisitorData>() {
|
||||
override fun visitAnnotationValue(value: AnnotationValue, data: FirAnnotationArgumentVisitorData) {
|
||||
data.builder.type = ProtoBuf.Annotation.Argument.Value.Type.ANNOTATION
|
||||
// TODO: annotation = serializeAnnotation(value.value)
|
||||
data.builder.annotation = data.serializer.serializeAnnotation(value.value)
|
||||
}
|
||||
|
||||
override fun visitArrayValue(value: ArrayValue, data: FirAnnotationArgumentVisitorData) {
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class FirAnnotationSerializer(private val session: FirSession, internal val stri
|
||||
fun addArgument(argumentExpression: FirExpression, parameterName: Name) {
|
||||
val argument = ProtoBuf.Annotation.Argument.newBuilder()
|
||||
argument.nameId = stringTable.getStringIndex(parameterName.asString())
|
||||
argument.setValue(valueProto(argumentExpression.toConstantValue() ?: return))
|
||||
argument.setValue(valueProto(argumentExpression.toConstantValue(session) ?: return))
|
||||
addArgument(argument)
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -884,7 +884,7 @@ class FirElementSerializer private constructor(
|
||||
private fun serializeVersionRequirementFromRequireKotlin(annotation: FirAnnotation): ProtoBuf.VersionRequirement.Builder? {
|
||||
val argumentMapping = annotation.argumentMapping.mapping
|
||||
|
||||
val versionString = (argumentMapping[RequireKotlinConstants.VERSION]?.toConstantValue() as? StringValue)?.value ?: return null
|
||||
val versionString = (argumentMapping[RequireKotlinConstants.VERSION]?.toConstantValue(session) as? StringValue)?.value ?: return null
|
||||
val matchResult = RequireKotlinConstants.VERSION_REGEX.matchEntire(versionString) ?: return null
|
||||
|
||||
val major = matchResult.groupValues.getOrNull(1)?.toIntOrNull() ?: return null
|
||||
@@ -897,12 +897,12 @@ class FirElementSerializer private constructor(
|
||||
writeVersionFull = { proto.versionFull = it }
|
||||
)
|
||||
|
||||
val message = (argumentMapping[RequireKotlinConstants.MESSAGE]?.toConstantValue() as? StringValue)?.value
|
||||
val message = (argumentMapping[RequireKotlinConstants.MESSAGE]?.toConstantValue(session) as? StringValue)?.value
|
||||
if (message != null) {
|
||||
proto.message = stringTable.getStringIndex(message)
|
||||
}
|
||||
|
||||
when ((argumentMapping[RequireKotlinConstants.LEVEL]?.toConstantValue() as? EnumValue)?.enumEntryName?.asString()) {
|
||||
when ((argumentMapping[RequireKotlinConstants.LEVEL]?.toConstantValue(session) as? EnumValue)?.enumEntryName?.asString()) {
|
||||
DeprecationLevel.ERROR.name -> {
|
||||
// ERROR is the default level
|
||||
}
|
||||
@@ -910,7 +910,7 @@ class FirElementSerializer private constructor(
|
||||
DeprecationLevel.HIDDEN.name -> proto.level = ProtoBuf.VersionRequirement.Level.HIDDEN
|
||||
}
|
||||
|
||||
when ((argumentMapping[RequireKotlinConstants.VERSION_KIND]?.toConstantValue() as? EnumValue)?.enumEntryName?.asString()) {
|
||||
when ((argumentMapping[RequireKotlinConstants.VERSION_KIND]?.toConstantValue(session) as? EnumValue)?.enumEntryName?.asString()) {
|
||||
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION.name -> {
|
||||
// LANGUAGE_VERSION is the default kind
|
||||
}
|
||||
@@ -920,7 +920,7 @@ class FirElementSerializer private constructor(
|
||||
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.API_VERSION
|
||||
}
|
||||
|
||||
val errorCode = (argumentMapping[RequireKotlinConstants.ERROR_CODE]?.toConstantValue() as? IntValue)?.value
|
||||
val errorCode = (argumentMapping[RequireKotlinConstants.ERROR_CODE]?.toConstantValue(session) as? IntValue)?.value
|
||||
if (errorCode != null && errorCode != -1) {
|
||||
proto.errorCode = errorCode
|
||||
}
|
||||
|
||||
+1
@@ -157,6 +157,7 @@ internal class KClassValue(value: Value) : ConstantValue<KClassValue.Value>(valu
|
||||
var type = argumentType
|
||||
var arrayDimensions = 0
|
||||
while (true) {
|
||||
if (type.isPrimitiveArray) break
|
||||
type = type.arrayElementType() ?: break
|
||||
arrayDimensions++
|
||||
}
|
||||
|
||||
+85
-21
@@ -5,10 +5,23 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.serialization.constant
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirEnumEntry
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.FirAnnotationCallBuilder
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
@@ -16,12 +29,12 @@ import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
internal fun FirExpression.toConstantValue(): ConstantValue<*>? = accept(FirToConstantValueTransformer, null)
|
||||
internal fun FirExpression.toConstantValue(session: FirSession): ConstantValue<*>? = accept(FirToConstantValueTransformer, session)
|
||||
|
||||
internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<*>?, Nothing?>() {
|
||||
internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<*>?, FirSession>() {
|
||||
override fun visitElement(
|
||||
element: FirElement,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*>? {
|
||||
error("Illegal element as annotation argument: ${element::class.qualifiedName} -> ${element.render()}")
|
||||
}
|
||||
@@ -29,7 +42,7 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
override fun <T> visitConstExpression(
|
||||
constExpression: FirConstExpression<T>,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*>? {
|
||||
val value = constExpression.value
|
||||
return when (constExpression.kind) {
|
||||
@@ -53,59 +66,110 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<
|
||||
|
||||
override fun visitArrayOfCall(
|
||||
arrayOfCall: FirArrayOfCall,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*> {
|
||||
return ArrayValue(arrayOfCall.argumentList.arguments.mapNotNull { it.accept(this, null) })
|
||||
return ArrayValue(arrayOfCall.argumentList.arguments.mapNotNull { it.accept(this, data) })
|
||||
}
|
||||
|
||||
override fun visitAnnotation(
|
||||
annotation: FirAnnotation,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*> {
|
||||
return AnnotationValue(annotation)
|
||||
}
|
||||
|
||||
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: Nothing?): ConstantValue<*> {
|
||||
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: FirSession): ConstantValue<*> {
|
||||
return visitAnnotation(annotationCall, data)
|
||||
}
|
||||
|
||||
override fun visitGetClassCall(
|
||||
getClassCall: FirGetClassCall,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*>? {
|
||||
return KClassValue.create(getClassCall.typeRef.coneTypeUnsafe())
|
||||
return KClassValue.create(getClassCall.argument.typeRef.coneTypeUnsafe())
|
||||
}
|
||||
|
||||
override fun visitQualifiedAccessExpression(
|
||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*>? {
|
||||
val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return null
|
||||
val enumEntry = symbol.fir as? FirEnumEntry ?: return null
|
||||
val classId = enumEntry.returnTypeRef.coneTypeSafe<ConeClassLikeType>()?.classId ?: return null
|
||||
val outerClassId = classId.outerClassId ?: return null
|
||||
return EnumValue(outerClassId, enumEntry.name)
|
||||
|
||||
return when {
|
||||
symbol.fir is FirEnumEntry -> {
|
||||
val classId = symbol.fir.returnTypeRef.coneTypeSafe<ConeClassLikeType>()?.classId ?: return null
|
||||
EnumValue(classId, (symbol.fir as FirEnumEntry).name)
|
||||
}
|
||||
|
||||
symbol is FirConstructorSymbol -> {
|
||||
val constructorCall = qualifiedAccessExpression as FirFunctionCall
|
||||
val constructedClassSymbol = symbol.containingClass()?.toFirRegularClassSymbol(data) ?: return null
|
||||
return if (constructedClassSymbol.classKind == ClassKind.ANNOTATION_CLASS) {
|
||||
AnnotationValue(
|
||||
buildAnnotationCall {
|
||||
argumentMapping = buildAnnotationArgumentMapping {
|
||||
constructorCall.argumentMapping?.forEach { (firExpression, firValueParameter) ->
|
||||
mapping[firValueParameter.name] = firExpression
|
||||
}
|
||||
}
|
||||
annotationTypeRef = qualifiedAccessExpression.typeRef
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
source = qualifiedAccessExpression.source
|
||||
name = qualifiedAccessExpression.calleeReference.name
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
symbol.callableId.packageName.asString() == "kotlin" -> {
|
||||
val dispatchReceiver = qualifiedAccessExpression.dispatchReceiver
|
||||
when (symbol.callableId.callableName.asString()) {
|
||||
"toByte" -> ByteValue((dispatchReceiver.accept(this, data)!!.value as Number).toByte())
|
||||
"toLong" -> LongValue((dispatchReceiver.accept(this, data)!!.value as Number).toLong())
|
||||
"toShort" -> ShortValue((dispatchReceiver.accept(this, data)!!.value as Number).toShort())
|
||||
"toFloat" -> FloatValue((dispatchReceiver.accept(this, data)!!.value as Number).toFloat())
|
||||
"toDouble" -> DoubleValue((dispatchReceiver.accept(this, data)!!.value as Number).toDouble())
|
||||
"toChar" -> CharValue((dispatchReceiver.accept(this, data)!!.value as Number).toChar())
|
||||
"unaryMinus" -> {
|
||||
when (val receiverValue = dispatchReceiver.accept(this, data)) {
|
||||
is ByteValue -> ByteValue((-receiverValue.value).toByte())
|
||||
is LongValue -> LongValue(-receiverValue.value)
|
||||
is ShortValue -> ShortValue((-receiverValue.value).toShort())
|
||||
is FloatValue -> FloatValue(-receiverValue.value)
|
||||
is DoubleValue -> DoubleValue(-receiverValue.value)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: Nothing?): ConstantValue<*>? {
|
||||
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: FirSession): ConstantValue<*>? {
|
||||
return visitQualifiedAccessExpression(propertyAccessExpression, data)
|
||||
}
|
||||
|
||||
override fun visitFunctionCall(
|
||||
functionCall: FirFunctionCall,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*>? {
|
||||
return visitQualifiedAccessExpression(functionCall, data)
|
||||
}
|
||||
|
||||
override fun visitVarargArgumentsExpression(
|
||||
varargArgumentsExpression: FirVarargArgumentsExpression,
|
||||
data: Nothing?
|
||||
data: FirSession
|
||||
): ConstantValue<*> {
|
||||
return ArrayValue(varargArgumentsExpression.arguments.mapNotNull { it.accept(this, null) })
|
||||
return ArrayValue(varargArgumentsExpression.arguments.mapNotNull { it.accept(this, data) })
|
||||
}
|
||||
|
||||
override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression, data: Nothing?): ConstantValue<*>? {
|
||||
return namedArgumentExpression.expression.accept(this, null)
|
||||
override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression, data: FirSession): ConstantValue<*>? {
|
||||
return namedArgumentExpression.expression.accept(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// FIR status: Fail: class kotlin.reflect.KClass
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
|
||||
Vendored
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// FIR status: assertEquals fails
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// FIR status: assertEquals fails (something wrong with argument order/mapping)
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
package test
|
||||
|
||||
Reference in New Issue
Block a user