All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.fir.serialization.constant.FirToConstantValueTransformer.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2020 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.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.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
import org.jetbrains.kotlin.fir.references.builder.buildSimpleNamedReference
import org.jetbrains.kotlin.fir.render
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
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.types.ConstantValueKind

internal fun FirExpression.toConstantValue(session: FirSession): ConstantValue<*>? = accept(FirToConstantValueTransformer, session)

internal object FirToConstantValueTransformer : FirDefaultVisitor?, FirSession>() {
    override fun visitElement(
        element: FirElement,
        data: FirSession
    ): ConstantValue<*>? {
        error("Illegal element as annotation argument: ${element::class.qualifiedName} -> ${element.render()}")
    }

    @OptIn(ExperimentalUnsignedTypes::class)
    override fun  visitConstExpression(
        constExpression: FirConstExpression,
        data: FirSession
    ): ConstantValue<*>? {
        val value = constExpression.value
        return when (constExpression.kind) {
            ConstantValueKind.Boolean -> BooleanValue(value as Boolean)
            ConstantValueKind.Char -> CharValue(value as Char)
            ConstantValueKind.Byte -> ByteValue((value as Number).toByte())
            ConstantValueKind.UnsignedByte -> UByteValue((value as Number).toByte())
            ConstantValueKind.Short -> ShortValue((value as Number).toShort())
            ConstantValueKind.UnsignedShort -> UShortValue((value as Number).toShort())
            ConstantValueKind.Int -> IntValue((value as Number).toInt())
            ConstantValueKind.UnsignedInt -> UIntValue((value as Number).toInt())
            ConstantValueKind.Long -> LongValue(value as Long)
            ConstantValueKind.UnsignedLong -> ULongValue(value as Long)
            ConstantValueKind.String -> StringValue(value as String)
            ConstantValueKind.Float -> FloatValue(value as Float)
            ConstantValueKind.Double -> DoubleValue(value as Double)
            ConstantValueKind.Null -> NullValue
            else -> null
        }
    }

    override fun visitArrayOfCall(
        arrayOfCall: FirArrayOfCall,
        data: FirSession
    ): ConstantValue<*> {
        return ArrayValue(arrayOfCall.argumentList.arguments.mapNotNull { it.accept(this, data) })
    }

    override fun visitAnnotation(
        annotation: FirAnnotation,
        data: FirSession
    ): ConstantValue<*> {
        return AnnotationValue(annotation)
    }

    override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: FirSession): ConstantValue<*> {
        return visitAnnotation(annotationCall, data)
    }

    override fun visitGetClassCall(
        getClassCall: FirGetClassCall,
        data: FirSession
    ): ConstantValue<*>? {
        return KClassValue.create(getClassCall.argument.typeRef.coneTypeUnsafe())
    }

    override fun visitQualifiedAccessExpression(
        qualifiedAccessExpression: FirQualifiedAccessExpression,
        data: FirSession
    ): ConstantValue<*>? {
        val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return null

        return when {
            symbol.fir is FirEnumEntry -> {
                val classId = symbol.fir.returnTypeRef.coneTypeSafe()?.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
                val dispatchReceiverValue by lazy { dispatchReceiver.accept(this, data) }
                when (symbol.callableId.callableName.asString()) {
                    "toByte" -> ByteValue((dispatchReceiverValue!!.value as Number).toByte())
                    "toLong" -> LongValue((dispatchReceiverValue!!.value as Number).toLong())
                    "toShort" -> ShortValue((dispatchReceiverValue!!.value as Number).toShort())
                    "toFloat" -> FloatValue((dispatchReceiverValue!!.value as Number).toFloat())
                    "toDouble" -> DoubleValue((dispatchReceiverValue!!.value as Number).toDouble())
                    "toChar" -> CharValue((dispatchReceiverValue!!.value as Number).toChar())
                    "unaryMinus" -> {
                        when (val receiverValue = dispatchReceiverValue) {
                            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: FirSession): ConstantValue<*>? {
        return visitQualifiedAccessExpression(propertyAccessExpression, data)
    }

    override fun visitFunctionCall(
        functionCall: FirFunctionCall,
        data: FirSession
    ): ConstantValue<*>? {
        return visitQualifiedAccessExpression(functionCall, data)
    }

    override fun visitVarargArgumentsExpression(
        varargArgumentsExpression: FirVarargArgumentsExpression,
        data: FirSession
    ): ConstantValue<*> {
        return ArrayValue(varargArgumentsExpression.arguments.mapNotNull { it.accept(this, data) })
    }

    override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression, data: FirSession): ConstantValue<*>? {
        return namedArgumentExpression.expression.accept(this, data)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy