[K2] Rewrite the way of extraction const values from IR for FIR
Right now it is much easier to extract constant values from `EvaluatedConstTracker` #KT-57928 #KT-57929
This commit is contained in:
+14
-12
@@ -9,27 +9,32 @@ import org.jetbrains.kotlin.constant.AnnotationValue
|
||||
import org.jetbrains.kotlin.constant.ConstantValue
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.convertToConstantValues
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class FirAnnotationSerializer(private val session: FirSession, internal val stringTable: FirElementAwareStringTable) {
|
||||
class FirAnnotationSerializer(
|
||||
private val session: FirSession,
|
||||
internal val stringTable: FirElementAwareStringTable,
|
||||
private val constValueProvider: ConstValueProvider?
|
||||
) {
|
||||
fun serializeAnnotation(annotation: FirAnnotation): ProtoBuf.Annotation {
|
||||
return serializeAnnotation(
|
||||
annotation.typeRef.coneTypeSafe<ConeClassLikeType>(),
|
||||
annotation.argumentMapping.mapping.convertToConstantValues(session)
|
||||
)
|
||||
// TODO this logic can be significantly simplified if we will find the way to convert `IrAnnotation` to `AnnotationValue`
|
||||
val annotationValue = annotation.toConstantValue(session, constValueProvider) as? AnnotationValue
|
||||
?: error("Cannot serialize annotation ${annotation.render()}")
|
||||
return serializeAnnotation(annotationValue)
|
||||
}
|
||||
|
||||
fun serializeAnnotation(annotation: AnnotationValue): ProtoBuf.Annotation {
|
||||
return serializeAnnotation(annotation.coneTypeSafe<ConeClassLikeType>(), annotation.value.argumentsMapping)
|
||||
}
|
||||
|
||||
private fun serializeAnnotation(coneType: ConeClassLikeType?, argumentsMapping: Map<Name, ConstantValue<*>?>): ProtoBuf.Annotation {
|
||||
private fun serializeAnnotation(coneType: ConeClassLikeType?, argumentsMapping: Map<Name, ConstantValue<*>>): ProtoBuf.Annotation {
|
||||
return ProtoBuf.Annotation.newBuilder().apply {
|
||||
val lookupTag = coneType?.lookupTag
|
||||
?: error { "Annotation without proper lookup tag: $coneType" }
|
||||
@@ -37,10 +42,7 @@ class FirAnnotationSerializer(private val session: FirSession, internal val stri
|
||||
id = lookupTag.toSymbol(session)?.let { stringTable.getFqNameIndex(it.fir) }
|
||||
?: stringTable.getQualifiedClassNameIndex(lookupTag.classId)
|
||||
|
||||
fun addArgument(argumentExpression: ConstantValue<*>?, parameterName: Name) {
|
||||
if (argumentExpression == null) {
|
||||
error("Cannot use null argument expression for parameter $parameterName")
|
||||
}
|
||||
fun addArgument(argumentExpression: ConstantValue<*>, parameterName: Name) {
|
||||
val argument = ProtoBuf.Annotation.Argument.newBuilder()
|
||||
argument.nameId = stringTable.getStringIndex(parameterName.asString())
|
||||
argument.setValue(valueProto(argumentExpression))
|
||||
|
||||
+2
-5
@@ -9,12 +9,10 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.buildValueProtoBufIfPropertyHasConst
|
||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
@@ -25,7 +23,7 @@ abstract class FirSerializerExtension {
|
||||
|
||||
abstract val metadataVersion: BinaryVersion
|
||||
|
||||
val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable) }
|
||||
val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable, constValueProvider) }
|
||||
|
||||
protected abstract val constValueProvider: ConstValueProvider?
|
||||
|
||||
@@ -83,8 +81,7 @@ abstract class FirSerializerExtension {
|
||||
|
||||
open fun serializeTypeAlias(typeAlias: FirTypeAlias, proto: ProtoBuf.TypeAlias.Builder) {
|
||||
for (annotation in typeAlias.nonSourceAnnotations(session)) {
|
||||
val annotationWithConstants = constValueProvider?.getNewFirAnnotationWithConstantValues(typeAlias, annotation) ?: annotation
|
||||
proto.addAnnotation(annotationSerializer.serializeAnnotation(annotationWithConstants))
|
||||
proto.addAnnotation(annotationSerializer.serializeAnnotation(annotation))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-28
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.buildValueProtoBufIfPropertyHasConst
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||
@@ -50,7 +50,7 @@ abstract class FirSerializerExtensionBase(
|
||||
childSerializer: FirElementSerializer
|
||||
) {
|
||||
function.serializeAnnotations(proto, protocol.functionAnnotation)
|
||||
function.receiverParameter?.serializeAnnotations(proto, protocol.functionExtensionReceiverAnnotation, function)
|
||||
function.receiverParameter?.serializeAnnotations(proto, protocol.functionExtensionReceiverAnnotation)
|
||||
}
|
||||
|
||||
override fun serializeProperty(
|
||||
@@ -72,17 +72,17 @@ abstract class FirSerializerExtensionBase(
|
||||
destination += annotation
|
||||
}
|
||||
|
||||
regularPropertyAnnotations.serializeAnnotations(proto, protocol.propertyAnnotation, property)
|
||||
fieldPropertyAnnotations.serializeAnnotations(proto, protocol.propertyBackingFieldAnnotation, property)
|
||||
delegatePropertyAnnotations.serializeAnnotations(proto, protocol.propertyDelegatedFieldAnnotation, property)
|
||||
regularPropertyAnnotations.serializeAnnotations(proto, protocol.propertyAnnotation)
|
||||
fieldPropertyAnnotations.serializeAnnotations(proto, protocol.propertyBackingFieldAnnotation)
|
||||
delegatePropertyAnnotations.serializeAnnotations(proto, protocol.propertyDelegatedFieldAnnotation)
|
||||
|
||||
property.getter?.serializeAnnotations(proto, protocol.propertyGetterAnnotation)
|
||||
property.setter?.serializeAnnotations(proto, protocol.propertySetterAnnotation)
|
||||
property.receiverParameter?.serializeAnnotations(proto, protocol.propertyExtensionReceiverAnnotation, property)
|
||||
property.receiverParameter?.serializeAnnotations(proto, protocol.propertyExtensionReceiverAnnotation)
|
||||
|
||||
if (!Flags.HAS_CONSTANT.get(proto.flags)) return
|
||||
constValueProvider?.buildValueProtoBufIfPropertyHasConst(property, annotationSerializer)?.let { constProtoBuf ->
|
||||
proto.setExtension(protocol.compileTimeValue, constProtoBuf)
|
||||
property.initializer?.toConstantValue(session, constValueProvider)?.let {
|
||||
proto.setExtension(protocol.compileTimeValue, annotationSerializer.valueProto(it).build())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ abstract class FirSerializerExtensionBase(
|
||||
|
||||
override fun serializeTypeAnnotations(annotations: List<FirAnnotation>, proto: ProtoBuf.Type.Builder) {
|
||||
// TODO support const extraction for type annotations
|
||||
annotations.serializeAnnotations(proto, protocol.typeAnnotation, container = null)
|
||||
annotations.serializeAnnotations(proto, protocol.typeAnnotation)
|
||||
}
|
||||
|
||||
override fun serializeTypeParameter(typeParameter: FirTypeParameter, proto: ProtoBuf.TypeParameter.Builder) {
|
||||
@@ -112,11 +112,10 @@ abstract class FirSerializerExtensionBase(
|
||||
BuilderType : GeneratedMessageLite.ExtendableBuilder<MessageType, BuilderType>,
|
||||
> FirAnnotationContainer.serializeAnnotations(
|
||||
proto: GeneratedMessageLite.ExtendableBuilder<MessageType, BuilderType>,
|
||||
extension: GeneratedMessageLite.GeneratedExtension<MessageType, List<ProtoBuf.Annotation>>?,
|
||||
container: FirAnnotationContainer? = this
|
||||
extension: GeneratedMessageLite.GeneratedExtension<MessageType, List<ProtoBuf.Annotation>>?
|
||||
) {
|
||||
if (extension == null) return
|
||||
this.nonSourceAnnotations(session).serializeAnnotations(proto, extension, container)
|
||||
this.nonSourceAnnotations(session).serializeAnnotations(proto, extension)
|
||||
}
|
||||
|
||||
@Suppress("Reformat")
|
||||
@@ -126,25 +125,10 @@ abstract class FirSerializerExtensionBase(
|
||||
> List<FirAnnotation>.serializeAnnotations(
|
||||
proto: GeneratedMessageLite.ExtendableBuilder<MessageType, BuilderType>,
|
||||
extension: GeneratedMessageLite.GeneratedExtension<MessageType, List<ProtoBuf.Annotation>>?,
|
||||
container: FirAnnotationContainer?,
|
||||
) {
|
||||
if (extension == null) return
|
||||
for (annotation in this) {
|
||||
val annotationWithConstants = when {
|
||||
container == null -> null
|
||||
extension == protocol.propertyExtensionReceiverAnnotation || extension == protocol.functionExtensionReceiverAnnotation ->
|
||||
constValueProvider?.getNewFirAnnotationWithConstantValues(
|
||||
container,
|
||||
annotation,
|
||||
(container as FirCallableDeclaration).receiverParameter!!,
|
||||
)
|
||||
else ->
|
||||
constValueProvider?.getNewFirAnnotationWithConstantValues(
|
||||
container,
|
||||
annotation,
|
||||
)
|
||||
} ?: annotation
|
||||
proto.addExtensionOrNull(extension, annotationSerializer.serializeAnnotation(annotationWithConstants))
|
||||
proto.addExtensionOrNull(extension, annotationSerializer.serializeAnnotation(annotation))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-30
@@ -5,40 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.serialization.constant
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.constant.ConstantValue
|
||||
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirReceiverParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.serialization.FirAnnotationSerializer
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
|
||||
abstract class ConstValueProvider {
|
||||
abstract val session: FirSession
|
||||
abstract val evaluatedConstTracker: EvaluatedConstTracker
|
||||
|
||||
abstract fun getConstantValueForProperty(firProperty: FirProperty): FirExpression?
|
||||
|
||||
abstract fun getNewFirAnnotationWithConstantValues(
|
||||
firAnnotationContainer: FirAnnotationContainer,
|
||||
firAnnotation: FirAnnotation,
|
||||
): FirAnnotation
|
||||
|
||||
abstract fun getNewFirAnnotationWithConstantValues(
|
||||
firExtensionReceiverContainer: FirAnnotationContainer,
|
||||
firAnnotation: FirAnnotation,
|
||||
receiverParameter: FirReceiverParameter,
|
||||
): FirAnnotation
|
||||
|
||||
fun FirExpression?.toProtoBuf(annotationSerializer: FirAnnotationSerializer): ProtoBuf.Annotation.Argument.Value? {
|
||||
val constantValue = this?.toConstantValue(session) ?: return null
|
||||
return annotationSerializer.valueProto(constantValue).build()
|
||||
}
|
||||
}
|
||||
|
||||
fun ConstValueProvider.buildValueProtoBufIfPropertyHasConst(
|
||||
firProperty: FirProperty, annotationSerializer: FirAnnotationSerializer
|
||||
): ProtoBuf.Annotation.Argument.Value? {
|
||||
return getConstantValueForProperty(firProperty).toProtoBuf(annotationSerializer)
|
||||
abstract fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>?
|
||||
}
|
||||
|
||||
+14
-4
@@ -12,20 +12,30 @@ import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal fun Map<Name, FirExpression>.convertToConstantValues(session: FirSession): Map<Name, ConstantValue<*>?> {
|
||||
internal fun Map<Name, FirExpression>.convertToConstantValues(
|
||||
session: FirSession,
|
||||
constValueProvider: ConstValueProvider?
|
||||
): Map<Name, ConstantValue<*>> {
|
||||
return this.map { (name, firExpression) ->
|
||||
name to firExpression.toConstantValue(session)
|
||||
val constantValue = constValueProvider?.findConstantValueFor(firExpression)
|
||||
?: firExpression.toConstantValue(session, constValueProvider)
|
||||
?: error("Cannot convert expression ${firExpression.render()} to constant")
|
||||
name to constantValue
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
internal fun LinkedHashMap<FirExpression, FirValueParameter>.convertToConstantValues(session: FirSession): Map<Name, ConstantValue<*>?> {
|
||||
internal fun LinkedHashMap<FirExpression, FirValueParameter>.convertToConstantValues(
|
||||
session: FirSession,
|
||||
constValueProvider: ConstValueProvider?,
|
||||
): Map<Name, ConstantValue<*>> {
|
||||
return this.map { (firExpression, firValueParameter) -> firValueParameter.name to firExpression }
|
||||
.toMap().convertToConstantValues(session)
|
||||
.toMap().convertToConstantValues(session, constValueProvider)
|
||||
}
|
||||
|
||||
inline fun <reified T : ConeKotlinType> AnnotationValue.coneTypeSafe(): T? {
|
||||
|
||||
+14
-7
@@ -25,19 +25,26 @@ import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
internal fun FirExpression.toConstantValue(session: FirSession): ConstantValue<*>? {
|
||||
return accept(FirToConstantValueTransformerUnsafe, session)
|
||||
internal fun FirExpression.toConstantValue(session: FirSession, constValueProvider: ConstValueProvider? = null): ConstantValue<*>? {
|
||||
constValueProvider?.findConstantValueFor(this)?.let { return it }
|
||||
return accept(FirToConstantValueTransformerUnsafe(constValueProvider), session)
|
||||
}
|
||||
|
||||
internal fun FirExpression?.hasConstantValue(session: FirSession): Boolean {
|
||||
return this?.accept(FirToConstantValueChecker, session) == true
|
||||
}
|
||||
|
||||
private object FirToConstantValueTransformerSafe : FirToConstantValueTransformer(failOnNonConst = false)
|
||||
private object FirToConstantValueTransformerUnsafe : FirToConstantValueTransformer(failOnNonConst = true)
|
||||
private class FirToConstantValueTransformerSafe(
|
||||
constValueProvider: ConstValueProvider?
|
||||
) : FirToConstantValueTransformer(failOnNonConst = false, constValueProvider)
|
||||
|
||||
private class FirToConstantValueTransformerUnsafe(
|
||||
constValueProvider: ConstValueProvider?
|
||||
) : FirToConstantValueTransformer(failOnNonConst = true, constValueProvider)
|
||||
|
||||
private abstract class FirToConstantValueTransformer(
|
||||
private val failOnNonConst: Boolean
|
||||
private val failOnNonConst: Boolean,
|
||||
private val constValueProvider: ConstValueProvider?
|
||||
) : FirDefaultVisitor<ConstantValue<*>?, FirSession>() {
|
||||
override fun visitElement(
|
||||
element: FirElement,
|
||||
@@ -90,7 +97,7 @@ private abstract class FirToConstantValueTransformer(
|
||||
annotation: FirAnnotation,
|
||||
data: FirSession
|
||||
): ConstantValue<*> {
|
||||
val mapping = annotation.argumentMapping.mapping.convertToConstantValues(data)
|
||||
val mapping = annotation.argumentMapping.mapping.convertToConstantValues(data, constValueProvider)
|
||||
return AnnotationValue.create(annotation.annotationTypeRef.coneType, mapping)
|
||||
}
|
||||
|
||||
@@ -135,7 +142,7 @@ private abstract class FirToConstantValueTransformer(
|
||||
val constructedClassSymbol = symbol.containingClassLookupTag()?.toFirRegularClassSymbol(data) ?: return null
|
||||
if (constructedClassSymbol.classKind != ClassKind.ANNOTATION_CLASS) return null
|
||||
|
||||
val mapping = constructorCall.resolvedArgumentMapping?.convertToConstantValues(data) ?: return null
|
||||
val mapping = constructorCall.resolvedArgumentMapping?.convertToConstantValues(data, constValueProvider) ?: return null
|
||||
return AnnotationValue.create(qualifiedAccessExpression.typeRef.coneType, mapping)
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -176,8 +176,7 @@ class FirJvmSerializerExtension(
|
||||
|
||||
override fun serializeTypeParameter(typeParameter: FirTypeParameter, proto: ProtoBuf.TypeParameter.Builder) {
|
||||
for (annotation in typeParameter.nonSourceAnnotations(session)) {
|
||||
val annotationWithConstants = constValueProvider?.getNewFirAnnotationWithConstantValues(typeParameter, annotation) ?: annotation
|
||||
proto.addExtension(JvmProtoBuf.typeParameterAnnotation, annotationSerializer.serializeAnnotation(annotationWithConstants))
|
||||
proto.addExtension(JvmProtoBuf.typeParameterAnnotation, annotationSerializer.serializeAnnotation(annotation))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-208
@@ -5,222 +5,32 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.backend
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.constant.ConstantValue
|
||||
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
|
||||
class ConstValueProviderImpl(
|
||||
private val components: Fir2IrComponents,
|
||||
components: Fir2IrComponents,
|
||||
) : ConstValueProvider() {
|
||||
override val session: FirSession = components.session
|
||||
override val evaluatedConstTracker: EvaluatedConstTracker = components.configuration.evaluatedConstTracker
|
||||
|
||||
override fun getConstantValueForProperty(firProperty: FirProperty): FirExpression? {
|
||||
val firInitializer = firProperty.initializer
|
||||
val irProperty: IrProperty = components.declarationStorage.getCachedIrProperty(firProperty) ?: return firInitializer
|
||||
val irConst = irProperty.backingField?.initializer?.expression as? IrConst<*> ?: return firInitializer
|
||||
return irConst.toFirConst() ?: firInitializer
|
||||
}
|
||||
override fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>? {
|
||||
if (firExpression == null) return null
|
||||
|
||||
override fun getNewFirAnnotationWithConstantValues(
|
||||
firAnnotationContainer: FirAnnotationContainer,
|
||||
firAnnotation: FirAnnotation,
|
||||
): FirAnnotation {
|
||||
if (firAnnotation is FirErrorAnnotationCall || firAnnotation.source == null) return firAnnotation
|
||||
|
||||
val irDeclaration = when (firAnnotationContainer) {
|
||||
is FirClass -> components.classifierStorage.getCachedIrClass(firAnnotationContainer)
|
||||
is FirEnumEntry -> components.classifierStorage.getCachedIrEnumEntry(firAnnotationContainer)
|
||||
is FirTypeAlias -> components.classifierStorage.getCachedTypeAlias(firAnnotationContainer)
|
||||
is FirTypeParameter -> components.classifierStorage.getCachedIrTypeParameter(firAnnotationContainer)
|
||||
|
||||
is FirScript -> components.declarationStorage.getCachedIrScript(firAnnotationContainer)
|
||||
is FirConstructor -> components.declarationStorage.getCachedIrConstructor(firAnnotationContainer)
|
||||
is FirPropertyAccessor -> components.declarationStorage.getCachedIrProperty(firAnnotationContainer.propertySymbol.fir)
|
||||
?.let { if (firAnnotationContainer.isGetter) it.getter else it.setter }
|
||||
is FirFunction -> components.declarationStorage.getCachedIrFunction(firAnnotationContainer)
|
||||
is FirProperty -> components.declarationStorage.getCachedIrProperty(firAnnotationContainer)
|
||||
is FirValueParameter -> components.declarationStorage.getCachedIrFunction(firAnnotationContainer.containingFunctionSymbol.fir)
|
||||
?.valueParameters?.single { it.name == firAnnotationContainer.name }
|
||||
else -> error("Cannot extract IR declaration for ${firAnnotationContainer.render()}")
|
||||
} ?: return firAnnotation
|
||||
|
||||
val correctFirContainer = when (firAnnotation.useSiteTarget) {
|
||||
AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> {
|
||||
(firAnnotationContainer as? FirProperty)?.backingField ?: return firAnnotation
|
||||
}
|
||||
else -> firAnnotationContainer
|
||||
return if (firExpression is FirQualifiedAccessExpression) {
|
||||
// TODO check that this behavior is expected in ConversionUtils and if not fix it
|
||||
val calleeReference = firExpression.calleeReference
|
||||
val start = calleeReference.source?.startOffsetSkippingComments() ?: calleeReference.source?.startOffset ?: return null
|
||||
val end = firExpression.source?.endOffset ?: return null
|
||||
evaluatedConstTracker.load(start, end)
|
||||
} else {
|
||||
val start = firExpression.source?.startOffset ?: return null
|
||||
val end = firExpression.source?.endOffset ?: return null
|
||||
evaluatedConstTracker.load(start, end)
|
||||
}
|
||||
|
||||
val correctIrDeclaration = when (firAnnotation.useSiteTarget) {
|
||||
AnnotationUseSiteTarget.FIELD, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> {
|
||||
(irDeclaration as? IrProperty)?.backingField ?: return firAnnotation
|
||||
}
|
||||
else -> irDeclaration
|
||||
}
|
||||
|
||||
return buildNewFirAnnotationByCorrespondingIrAnnotation(correctIrDeclaration, correctFirContainer, firAnnotation)
|
||||
}
|
||||
|
||||
override fun getNewFirAnnotationWithConstantValues(
|
||||
firExtensionReceiverContainer: FirAnnotationContainer,
|
||||
firAnnotation: FirAnnotation,
|
||||
receiverParameter: FirReceiverParameter
|
||||
): FirAnnotation {
|
||||
if (firAnnotation is FirErrorAnnotationCall || firAnnotation.source == null) return firAnnotation
|
||||
|
||||
val extensionReceiver = when (firExtensionReceiverContainer) {
|
||||
is FirFunction -> components.declarationStorage.getCachedIrFunction(firExtensionReceiverContainer)?.extensionReceiverParameter
|
||||
is FirProperty -> components.declarationStorage.getCachedIrProperty(firExtensionReceiverContainer)?.getter?.extensionReceiverParameter
|
||||
else -> error("Cannot extract IR extension receiver for ${firExtensionReceiverContainer::class}")
|
||||
} ?: return firAnnotation
|
||||
|
||||
return buildNewFirAnnotationByCorrespondingIrAnnotation(extensionReceiver, receiverParameter, firAnnotation)
|
||||
}
|
||||
|
||||
private fun buildNewFirAnnotationByCorrespondingIrAnnotation(
|
||||
irDeclaration: IrDeclarationBase,
|
||||
firAnnotationContainer: FirAnnotationContainer,
|
||||
firAnnotation: FirAnnotation
|
||||
): FirAnnotation {
|
||||
val unwrappedIrAnnotations = irDeclaration.annotations.flatMap {
|
||||
val containerClass = it.symbol.owner.parentAsClass
|
||||
val realAnnotation = containerClass.parentClassOrNull ?: return@flatMap listOf(it)
|
||||
if (realAnnotation.kind != ClassKind.ANNOTATION_CLASS || !realAnnotation.hasAnnotation(StandardNames.FqNames.repeatable)) {
|
||||
return@flatMap listOf(it)
|
||||
}
|
||||
|
||||
(it.getValueArgument(0) as IrVararg).elements.map { repAnno -> repAnno as IrConstructorCall }
|
||||
}.filter { it.startOffset != -1 && it.endOffset != -1 }
|
||||
|
||||
assert(unwrappedIrAnnotations.size == firAnnotationContainer.annotations.size) {
|
||||
"Number of annotations for IR and FIR declaration are not equal"
|
||||
}
|
||||
|
||||
val irArguments = unwrappedIrAnnotations
|
||||
.find { it.startOffset == firAnnotation.source?.startOffset && it.endOffset == firAnnotation.source?.endOffset }
|
||||
?.getArgumentsWithIr()
|
||||
?: error("Could not find corresponding IR annotation for ${firAnnotation.render()}")
|
||||
|
||||
val annotationArgsMapping = buildAnnotationArgumentMapping {
|
||||
firAnnotation.argumentMapping.mapping.forEach { (name, firExpression) ->
|
||||
if (firExpression is FirConstExpression<*>) {
|
||||
mapping[name] = firExpression
|
||||
return@forEach
|
||||
}
|
||||
val irExpression = irArguments.single { it.first.name == name }.second
|
||||
mapping[name] = irExpression.convertToFir(firExpression)
|
||||
}
|
||||
}
|
||||
|
||||
return when (firAnnotation) {
|
||||
is FirAnnotationCall -> buildAnnotationCall {
|
||||
this.annotationTypeRef = firAnnotation.annotationTypeRef
|
||||
this.calleeReference = firAnnotation.calleeReference
|
||||
this.argumentMapping = annotationArgsMapping
|
||||
}
|
||||
else -> buildAnnotation {
|
||||
this.annotationTypeRef = firAnnotation.annotationTypeRef
|
||||
this.argumentMapping = annotationArgsMapping
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrElement.convertToFir(firExpression: FirExpression): FirExpression {
|
||||
return when {
|
||||
this is IrConst<*> -> toFirConst() ?: firExpression
|
||||
this is IrConstructorCall && firExpression is FirFunctionCall -> {
|
||||
val resolvedArgumentMapping = firExpression.resolvedArgumentMapping ?: return firExpression
|
||||
val irArgs = this.getArgumentsWithIr()
|
||||
buildFunctionCall {
|
||||
this.source = firExpression.source
|
||||
this.typeRef = firExpression.typeRef
|
||||
this.dispatchReceiver = firExpression.dispatchReceiver
|
||||
this.extensionReceiver = firExpression.extensionReceiver
|
||||
this.explicitReceiver = firExpression.explicitReceiver
|
||||
this.calleeReference = firExpression.calleeReference
|
||||
this.annotations.addAll(firExpression.annotations)
|
||||
this.typeArguments.addAll(firExpression.typeArguments)
|
||||
|
||||
val newArgMapping = LinkedHashMap(
|
||||
resolvedArgumentMapping.map { (key, value) ->
|
||||
irArgs.first { it.first.name == value.name }.second.convertToFir(key) to value
|
||||
}.toMap()
|
||||
)
|
||||
this.argumentList = buildResolvedArgumentList(newArgMapping, firExpression.argumentList.source)
|
||||
}
|
||||
}
|
||||
this is IrVararg && firExpression is FirVarargArgumentsExpression -> buildVarargArgumentsExpression {
|
||||
this.source = firExpression.source
|
||||
this.typeRef = firExpression.typeRef
|
||||
this.annotations.addAll(firExpression.annotations)
|
||||
this.varargElementType = firExpression.varargElementType
|
||||
this.arguments.addAll(
|
||||
firExpression.arguments.zip(this@convertToFir.elements).map { it.second.convertToFir(it.first) }
|
||||
)
|
||||
}
|
||||
this is IrVararg && firExpression is FirArrayOfCall -> buildArrayOfCall {
|
||||
this.source = firExpression.source
|
||||
this.typeRef = firExpression.typeRef
|
||||
this.annotations.addAll(firExpression.annotations)
|
||||
this.argumentList = buildArgumentList {
|
||||
this.source = firExpression.argumentList.source
|
||||
this.arguments.addAll(
|
||||
firExpression.argumentList.arguments.zip(this@convertToFir.elements).map { it.second.convertToFir(it.first) }
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> firExpression
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrConst<*>.getConstantKind(): ConstantValueKind<*>? {
|
||||
if (this.kind == IrConstKind.Null) return ConstantValueKind.Null
|
||||
|
||||
val constType = this.type.makeNotNull().removeAnnotations()
|
||||
return when (this.type.getPrimitiveType()) {
|
||||
PrimitiveType.BOOLEAN -> ConstantValueKind.Boolean
|
||||
PrimitiveType.CHAR -> ConstantValueKind.Char
|
||||
PrimitiveType.BYTE -> ConstantValueKind.Byte
|
||||
PrimitiveType.SHORT -> ConstantValueKind.Short
|
||||
PrimitiveType.INT -> ConstantValueKind.Int
|
||||
PrimitiveType.LONG -> ConstantValueKind.Long
|
||||
PrimitiveType.FLOAT -> ConstantValueKind.Float
|
||||
PrimitiveType.DOUBLE -> ConstantValueKind.Double
|
||||
null -> when (constType.getUnsignedType()) {
|
||||
UnsignedType.UBYTE -> ConstantValueKind.UnsignedByte
|
||||
UnsignedType.USHORT -> ConstantValueKind.UnsignedShort
|
||||
UnsignedType.UINT -> ConstantValueKind.UnsignedInt
|
||||
UnsignedType.ULONG -> ConstantValueKind.UnsignedLong
|
||||
null -> when {
|
||||
constType.isString() -> ConstantValueKind.String
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> IrConst<T>.toFirConst(): FirConstExpression<T>? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val kind = getConstantKind() as? ConstantValueKind<T> ?: return null
|
||||
return buildConstExpression(null, kind, this.value)
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
private fun AbstractKtSourceElement?.startOffsetSkippingComments(): Int? {
|
||||
fun AbstractKtSourceElement?.startOffsetSkippingComments(): Int? {
|
||||
return when (this) {
|
||||
is KtPsiSourceElement -> this.psi.startOffsetSkippingComments
|
||||
is KtLightSourceElement -> this.startOffsetSkippingComments
|
||||
|
||||
@@ -30,12 +30,12 @@ abstract class IntegerValueConstant<out T> protected constructor(value: T) : Con
|
||||
abstract class UnsignedValueConstant<out T> protected constructor(value: T) : ConstantValue<T>(value)
|
||||
|
||||
class AnnotationValue private constructor(value: Value) : ConstantValue<AnnotationValue.Value>(value) {
|
||||
class Value(val type: KotlinTypeMarker, val argumentsMapping: Map<Name, ConstantValue<*>?>)
|
||||
class Value(val type: KotlinTypeMarker, val argumentsMapping: Map<Name, ConstantValue<*>>)
|
||||
|
||||
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D): R = visitor.visitAnnotationValue(this, data)
|
||||
|
||||
companion object {
|
||||
fun create(type: KotlinTypeMarker, argumentsMapping: Map<Name, ConstantValue<*>?>): AnnotationValue {
|
||||
fun create(type: KotlinTypeMarker, argumentsMapping: Map<Name, ConstantValue<*>>): AnnotationValue {
|
||||
return AnnotationValue(
|
||||
Value(type, argumentsMapping)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user