Introduce FIR serializer (isn't in use yet, KT-38156)
This commit is contained in:
@@ -263,6 +263,7 @@ extra["compilerModules"] = arrayOf(
|
|||||||
":core:type-system",
|
":core:type-system",
|
||||||
":compiler:fir:cones",
|
":compiler:fir:cones",
|
||||||
":compiler:fir:resolve",
|
":compiler:fir:resolve",
|
||||||
|
":compiler:fir:fir-serialization",
|
||||||
":compiler:fir:tree",
|
":compiler:fir:tree",
|
||||||
":compiler:fir:raw-fir:fir-common",
|
":compiler:fir:raw-fir:fir-common",
|
||||||
":compiler:fir:raw-fir:psi2fir",
|
":compiler:fir:raw-fir:psi2fir",
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile(project(":core:descriptors"))
|
||||||
|
compile(project(":compiler:fir:cones"))
|
||||||
|
compile(project(":compiler:fir:tree"))
|
||||||
|
compile(project(":compiler:fir:resolve"))
|
||||||
|
|
||||||
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" { none() }
|
||||||
|
}
|
||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.*
|
||||||
|
|
||||||
|
class FirAnnotationSerializer(private val session: FirSession, private val stringTable: FirElementAwareStringTable) {
|
||||||
|
fun serializeAnnotation(annotation: FirAnnotationCall): ProtoBuf.Annotation = ProtoBuf.Annotation.newBuilder().apply {
|
||||||
|
val annotationSymbol = annotation.typeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.toSymbol(session)
|
||||||
|
val annotationClass = annotationSymbol?.fir ?: error("Annotation type is not a class: ${annotationSymbol?.fir}")
|
||||||
|
|
||||||
|
id = stringTable.getFqNameIndex(annotationClass)
|
||||||
|
|
||||||
|
for (argumentExpression in annotation.argumentList.arguments) {
|
||||||
|
if (argumentExpression !is FirNamedArgumentExpression) continue
|
||||||
|
val argument = ProtoBuf.Annotation.Argument.newBuilder()
|
||||||
|
argument.nameId = stringTable.getStringIndex(argumentExpression.name.asString())
|
||||||
|
val constant = argumentExpression.expression as? FirConstExpression<*> ?: continue
|
||||||
|
argument.setValue(valueProto(constant.value as? ConstantValue<*> ?: continue))
|
||||||
|
addArgument(argument)
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
fun valueProto(constant: ConstantValue<*>): ProtoBuf.Annotation.Argument.Value.Builder =
|
||||||
|
ProtoBuf.Annotation.Argument.Value.newBuilder().apply {
|
||||||
|
constant.accept(object : AnnotationArgumentVisitor<Unit, Unit> {
|
||||||
|
override fun visitAnnotationValue(value: AnnotationValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.ANNOTATION
|
||||||
|
// TODO: annotation = serializeAnnotation(value.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitArrayValue(value: ArrayValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.ARRAY
|
||||||
|
for (element in value.value) {
|
||||||
|
addArrayElement(valueProto(element).build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBooleanValue(value: BooleanValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.BOOLEAN
|
||||||
|
intValue = if (value.value) 1 else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitByteValue(value: ByteValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.BYTE
|
||||||
|
intValue = value.value.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCharValue(value: CharValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.CHAR
|
||||||
|
intValue = value.value.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoubleValue(value: DoubleValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.DOUBLE
|
||||||
|
doubleValue = value.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnumValue(value: EnumValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.ENUM
|
||||||
|
classId = stringTable.getQualifiedClassNameIndex(value.enumClassId)
|
||||||
|
enumValueId = stringTable.getStringIndex(value.enumEntryName.asString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitErrorValue(value: ErrorValue, data: Unit) {
|
||||||
|
throw UnsupportedOperationException("Error value: $value")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFloatValue(value: FloatValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.FLOAT
|
||||||
|
floatValue = value.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIntValue(value: IntValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.INT
|
||||||
|
intValue = value.value.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitKClassValue(value: KClassValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.CLASS
|
||||||
|
|
||||||
|
when (val classValue = value.value) {
|
||||||
|
is KClassValue.Value.NormalClass -> {
|
||||||
|
classId = stringTable.getQualifiedClassNameIndex(classValue.classId)
|
||||||
|
|
||||||
|
if (classValue.arrayDimensions > 0) {
|
||||||
|
arrayDimensionCount = classValue.arrayDimensions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KClassValue.Value.LocalClass -> {
|
||||||
|
var arrayDimensions = 0
|
||||||
|
var type = classValue.type
|
||||||
|
while (KotlinBuiltIns.isArray(type)) {
|
||||||
|
arrayDimensions++
|
||||||
|
type = type.arguments.single().type
|
||||||
|
}
|
||||||
|
|
||||||
|
//val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor
|
||||||
|
// ?: error("Type parameters are not allowed in class literal annotation arguments: $classValue")
|
||||||
|
// TODO: classId = stringTable.getFqNameIndex(descriptor)
|
||||||
|
|
||||||
|
if (arrayDimensions > 0) {
|
||||||
|
arrayDimensionCount = arrayDimensions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLongValue(value: LongValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.LONG
|
||||||
|
intValue = value.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitNullValue(value: NullValue, data: Unit) {
|
||||||
|
throw UnsupportedOperationException("Null should not appear in annotation arguments")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitShortValue(value: ShortValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.SHORT
|
||||||
|
intValue = value.value.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitStringValue(value: StringValue, data: Unit) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.STRING
|
||||||
|
stringValue = stringTable.getStringIndex(value.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitUByteValue(value: UByteValue, data: Unit?) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.BYTE
|
||||||
|
intValue = value.value.toLong()
|
||||||
|
flags = Flags.IS_UNSIGNED.toFlags(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitUShortValue(value: UShortValue, data: Unit?) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.SHORT
|
||||||
|
intValue = value.value.toLong()
|
||||||
|
flags = Flags.IS_UNSIGNED.toFlags(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitUIntValue(value: UIntValue, data: Unit?) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.INT
|
||||||
|
intValue = value.value.toLong()
|
||||||
|
flags = Flags.IS_UNSIGNED.toFlags(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitULongValue(value: ULongValue, data: Unit?) {
|
||||||
|
type = ProtoBuf.Annotation.Argument.Value.Type.LONG
|
||||||
|
intValue = value.value
|
||||||
|
flags = Flags.IS_UNSIGNED.toFlags(true)
|
||||||
|
}
|
||||||
|
}, Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
+216
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.contracts.description.*
|
||||||
|
import org.jetbrains.kotlin.contracts.description.expressions.*
|
||||||
|
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
|
||||||
|
import org.jetbrains.kotlin.fir.contracts.description.*
|
||||||
|
import org.jetbrains.kotlin.fir.contracts.effects
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.LogicOperationKind
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
|
|
||||||
|
class FirContractSerializer {
|
||||||
|
fun serializeContractOfFunctionIfAny(
|
||||||
|
function: FirFunction<*>,
|
||||||
|
proto: ProtoBuf.Function.Builder,
|
||||||
|
parentSerializer: FirElementSerializer
|
||||||
|
) {
|
||||||
|
val contractDescription = (function as? FirSimpleFunction)?.contractDescription
|
||||||
|
if (contractDescription == null || contractDescription.effects.isNullOrEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val worker = ContractSerializerWorker(parentSerializer)
|
||||||
|
proto.setContract(worker.contractProto(contractDescription))
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ContractSerializerWorker(private val parentSerializer: FirElementSerializer) {
|
||||||
|
fun contractProto(contractDescription: FirContractDescription): ProtoBuf.Contract.Builder {
|
||||||
|
return ProtoBuf.Contract.newBuilder().apply {
|
||||||
|
contractDescription.effects?.forEach { addEffect(effectProto(it, contractDescription)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun effectProto(
|
||||||
|
effectDeclaration: ConeEffectDeclaration, contractDescription: FirContractDescription
|
||||||
|
): ProtoBuf.Effect.Builder {
|
||||||
|
return ProtoBuf.Effect.newBuilder().apply {
|
||||||
|
fillEffectProto(this, effectDeclaration, contractDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fillEffectProto(
|
||||||
|
builder: ProtoBuf.Effect.Builder,
|
||||||
|
effectDeclaration: ConeEffectDeclaration,
|
||||||
|
contractDescription: FirContractDescription
|
||||||
|
) {
|
||||||
|
when (effectDeclaration) {
|
||||||
|
is ConeConditionalEffectDeclaration -> {
|
||||||
|
builder.setConclusionOfConditionalEffect(contractExpressionProto(effectDeclaration.condition, contractDescription))
|
||||||
|
fillEffectProto(builder, effectDeclaration.effect, contractDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
is ConeReturnsEffectDeclaration -> {
|
||||||
|
when (effectDeclaration.value) {
|
||||||
|
ConstantReference.NOT_NULL ->
|
||||||
|
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL
|
||||||
|
ConstantReference.WILDCARD ->
|
||||||
|
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
||||||
|
else -> {
|
||||||
|
builder.effectType = ProtoBuf.Effect.EffectType.RETURNS_CONSTANT
|
||||||
|
builder.addEffectConstructorArgument(contractExpressionProto(effectDeclaration.value, contractDescription))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is ConeCallsEffectDeclaration -> {
|
||||||
|
builder.effectType = ProtoBuf.Effect.EffectType.CALLS
|
||||||
|
builder.addEffectConstructorArgument(
|
||||||
|
contractExpressionProto(effectDeclaration.valueParameterReference, contractDescription)
|
||||||
|
)
|
||||||
|
val invocationKindProtobufEnum = invocationKindProtobufEnum(effectDeclaration.kind)
|
||||||
|
if (invocationKindProtobufEnum != null) {
|
||||||
|
builder.kind = invocationKindProtobufEnum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
throw IllegalStateException("Unsupported effect type: ${effectDeclaration::class.simpleName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun contractExpressionProto(
|
||||||
|
contractDescriptionElement: ConeContractDescriptionElement,
|
||||||
|
contractDescription: FirContractDescription
|
||||||
|
): ProtoBuf.Expression.Builder {
|
||||||
|
return contractDescriptionElement.accept(object : ConeContractDescriptionVisitor<ProtoBuf.Expression.Builder, Unit>() {
|
||||||
|
override fun visitLogicalBinaryOperationContractExpression(
|
||||||
|
binaryLogicExpression: ConeBinaryLogicExpression,
|
||||||
|
data: Unit
|
||||||
|
): ProtoBuf.Expression.Builder {
|
||||||
|
return if (binaryLogicExpression.kind == LogicOperationKind.AND) {
|
||||||
|
visitLogicalAnd(binaryLogicExpression, data)
|
||||||
|
} else {
|
||||||
|
visitLogicalOr(binaryLogicExpression, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitLogicalOr(logicalOr: ConeBinaryLogicExpression, data: Unit): ProtoBuf.Expression.Builder {
|
||||||
|
val leftBuilder = logicalOr.left.accept(this, data)
|
||||||
|
|
||||||
|
return if (leftBuilder.andArgumentCount != 0) {
|
||||||
|
// can't flatten and re-use left builder
|
||||||
|
ProtoBuf.Expression.newBuilder().apply {
|
||||||
|
addOrArgument(leftBuilder)
|
||||||
|
addOrArgument(contractExpressionProto(logicalOr.right, contractDescription))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we can save some space by re-using left builder instead of nesting new one
|
||||||
|
leftBuilder.apply { addOrArgument(contractExpressionProto(logicalOr.right, contractDescription)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun visitLogicalAnd(logicalAnd: ConeBinaryLogicExpression, data: Unit): ProtoBuf.Expression.Builder {
|
||||||
|
val leftBuilder = logicalAnd.left.accept(this, data)
|
||||||
|
|
||||||
|
return if (leftBuilder.orArgumentCount != 0) {
|
||||||
|
// leftBuilder is already a sequence of Or-operators, so we can't re-use it
|
||||||
|
ProtoBuf.Expression.newBuilder().apply {
|
||||||
|
addAndArgument(leftBuilder)
|
||||||
|
addAndArgument(contractExpressionProto(logicalAnd.right, contractDescription))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we can save some space by re-using left builder instead of nesting new one
|
||||||
|
leftBuilder.apply { addAndArgument(contractExpressionProto(logicalAnd.right, contractDescription)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLogicalNot(logicalNot: ConeLogicalNot, data: Unit): ProtoBuf.Expression.Builder =
|
||||||
|
logicalNot.arg.accept(this, data).apply {
|
||||||
|
writeFlags(Flags.IS_NEGATED.invert(flags))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsInstancePredicate(
|
||||||
|
isInstancePredicate: ConeIsInstancePredicate, data: Unit
|
||||||
|
): ProtoBuf.Expression.Builder {
|
||||||
|
// write variable
|
||||||
|
val builder = visitValueParameterReference(isInstancePredicate.arg, data)
|
||||||
|
|
||||||
|
// write rhs type
|
||||||
|
builder.isInstanceTypeId = parentSerializer.typeId(isInstancePredicate.type)
|
||||||
|
|
||||||
|
// set flags
|
||||||
|
builder.writeFlags(Flags.getContractExpressionFlags(isInstancePredicate.isNegated, false))
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIsNullPredicate(isNullPredicate: ConeIsNullPredicate, data: Unit): ProtoBuf.Expression.Builder {
|
||||||
|
// get builder with variable embedded into it
|
||||||
|
val builder = visitValueParameterReference(isNullPredicate.arg, data)
|
||||||
|
|
||||||
|
// set flags
|
||||||
|
builder.writeFlags(Flags.getContractExpressionFlags(isNullPredicate.isNegated, true))
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstantDescriptor(constantReference: ConeConstantReference, data: Unit): ProtoBuf.Expression.Builder {
|
||||||
|
val builder = ProtoBuf.Expression.newBuilder()
|
||||||
|
|
||||||
|
// write constant value
|
||||||
|
val constantValueProtobufEnum = constantValueProtobufEnum(constantReference)
|
||||||
|
if (constantValueProtobufEnum != null) {
|
||||||
|
builder.constantValue = constantValueProtobufEnum
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitValueParameterReference(
|
||||||
|
valueParameterReference: ConeValueParameterReference, data: Unit
|
||||||
|
): ProtoBuf.Expression.Builder {
|
||||||
|
val builder = ProtoBuf.Expression.newBuilder()
|
||||||
|
|
||||||
|
val indexOfParameter = valueParameterReference.parameterIndex
|
||||||
|
builder.valueParameterReference = indexOfParameter
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
}, Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ProtoBuf.Expression.Builder.writeFlags(newFlagsValue: Int) {
|
||||||
|
if (flags != newFlagsValue) {
|
||||||
|
flags = newFlagsValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invocationKindProtobufEnum(kind: InvocationKind): ProtoBuf.Effect.InvocationKind? = when (kind) {
|
||||||
|
InvocationKind.AT_MOST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE
|
||||||
|
InvocationKind.EXACTLY_ONCE -> ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE
|
||||||
|
InvocationKind.AT_LEAST_ONCE -> ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE
|
||||||
|
InvocationKind.UNKNOWN -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun constantValueProtobufEnum(constantReference: ConeConstantReference): ProtoBuf.Expression.ConstantValue? =
|
||||||
|
when (constantReference) {
|
||||||
|
ConeBooleanConstantReference.TRUE -> ProtoBuf.Expression.ConstantValue.TRUE
|
||||||
|
ConeBooleanConstantReference.FALSE -> ProtoBuf.Expression.ConstantValue.FALSE
|
||||||
|
ConeConstantReference.NULL -> ProtoBuf.Expression.ConstantValue.NULL
|
||||||
|
ConeConstantReference.NOT_NULL -> throw IllegalStateException(
|
||||||
|
"Internal error during serialization of function contract: NOT_NULL constant isn't denotable in protobuf format. " +
|
||||||
|
"Its serialization should be handled at higher level"
|
||||||
|
)
|
||||||
|
ConeConstantReference.WILDCARD -> null
|
||||||
|
else -> throw IllegalArgumentException("Unknown constant: $constantReference")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.render
|
||||||
|
import org.jetbrains.kotlin.metadata.serialization.StringTable
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
|
interface FirElementAwareStringTable : StringTable {
|
||||||
|
fun getQualifiedClassNameIndex(classId: ClassId): Int =
|
||||||
|
getQualifiedClassNameIndex(classId.asString(), classId.isLocal)
|
||||||
|
|
||||||
|
fun getFqNameIndex(classLikeDeclaration: FirClassLikeDeclaration<*>): Int {
|
||||||
|
val classId = classLikeDeclaration.symbol.classId.takeIf { !it.isLocal }
|
||||||
|
?: getLocalClassIdReplacement(classLikeDeclaration)
|
||||||
|
?: throw IllegalStateException("Cannot get FQ name of local class: ${classLikeDeclaration.render()}")
|
||||||
|
|
||||||
|
return getQualifiedClassNameIndex(classId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLocalClassIdReplacement(classLikeDeclaration: FirClassLikeDeclaration<*>): ClassId? = null
|
||||||
|
}
|
||||||
+863
@@ -0,0 +1,863 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
|
||||||
|
import org.jetbrains.kotlin.fir.render
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.varargElementType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.isKotlin1Dot4OrLater
|
||||||
|
import org.jetbrains.kotlin.metadata.serialization.Interner
|
||||||
|
import org.jetbrains.kotlin.metadata.serialization.MutableTypeTable
|
||||||
|
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.RequireKotlinConstants
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.IntValue
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
|
class FirElementSerializer private constructor(
|
||||||
|
private val session: FirSession,
|
||||||
|
private val containingDeclaration: FirDeclaration?,
|
||||||
|
private val typeParameters: Interner<FirTypeParameter>,
|
||||||
|
private val extension: FirSerializerExtension,
|
||||||
|
val typeTable: MutableTypeTable,
|
||||||
|
private val versionRequirementTable: MutableVersionRequirementTable?,
|
||||||
|
private val serializeTypeTableToFunction: Boolean,
|
||||||
|
) {
|
||||||
|
private val contractSerializer = FirContractSerializer()
|
||||||
|
|
||||||
|
fun classProto(klass: FirClass<*>): ProtoBuf.Class.Builder {
|
||||||
|
val builder = ProtoBuf.Class.newBuilder()
|
||||||
|
|
||||||
|
val regularClass = klass as? FirRegularClass
|
||||||
|
val modality = regularClass?.modality ?: Modality.FINAL
|
||||||
|
val flags = Flags.getClassFlags(
|
||||||
|
klass.annotations.isNotEmpty(),
|
||||||
|
ProtoEnumFlags.visibility(regularClass?.let { normalizeVisibility(it) } ?: Visibilities.LOCAL),
|
||||||
|
ProtoEnumFlags.modality(modality),
|
||||||
|
ProtoEnumFlags.classKind(klass.classKind, regularClass?.isCompanion == true),
|
||||||
|
regularClass?.isInner == true,
|
||||||
|
regularClass?.isData == true,
|
||||||
|
regularClass?.isExternal == true,
|
||||||
|
regularClass?.isExpect == true,
|
||||||
|
regularClass?.isInline == true,
|
||||||
|
false // TODO: klass.isFun not supported yet
|
||||||
|
)
|
||||||
|
if (flags != builder.flags) {
|
||||||
|
builder.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.fqName = getClassifierId(klass)
|
||||||
|
|
||||||
|
for (typeParameter in klass.typeParameters) {
|
||||||
|
if (typeParameter !is FirTypeParameter) continue
|
||||||
|
builder.addTypeParameter(typeParameterProto(typeParameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
val classId = klass.symbol.classId
|
||||||
|
if (classId != StandardClassIds.Any && classId != StandardClassIds.Nothing) {
|
||||||
|
// Special classes (Any, Nothing) have no supertypes
|
||||||
|
for (superTypeRef in klass.superTypeRefs) {
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.addSupertypeId(typeId(superTypeRef))
|
||||||
|
} else {
|
||||||
|
builder.addSupertype(typeProto(superTypeRef))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regularClass != null && regularClass.classKind != ClassKind.ENUM_ENTRY) {
|
||||||
|
for (constructor in regularClass.declarations.filterIsInstance<FirConstructor>()) {
|
||||||
|
builder.addConstructor(constructorProto(constructor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: member sorting, see KT-20980
|
||||||
|
val callableMembers =
|
||||||
|
extension.customClassMembersProducer?.getCallableMembers(klass)
|
||||||
|
?: klass.declarations.filterIsInstance<FirCallableMemberDeclaration<*>>()
|
||||||
|
|
||||||
|
for (declaration in callableMembers) {
|
||||||
|
when (declaration) {
|
||||||
|
is FirProperty -> propertyProto(declaration)?.let { builder.addProperty(it) }
|
||||||
|
is FirSimpleFunction -> functionProto(declaration)?.let { builder.addFunction(it) }
|
||||||
|
is FirEnumEntry -> enumEntryProto(declaration).let { builder.addEnumEntry(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val nestedClassifiers = klass.declarations.filterIsInstance<FirClassLikeDeclaration<*>>()
|
||||||
|
for (nestedClassifier in nestedClassifiers) {
|
||||||
|
if (nestedClassifier is FirTypeAlias) {
|
||||||
|
typeAliasProto(nestedClassifier)?.let { builder.addTypeAlias(it) }
|
||||||
|
} else if (nestedClassifier is FirRegularClass) {
|
||||||
|
if (!extension.shouldSerializeNestedClass(nestedClassifier)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addNestedClassName(getSimpleNameIndex(nestedClassifier.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (klass is FirSealedClass) {
|
||||||
|
for (inheritorId in klass.inheritors) {
|
||||||
|
builder.addSealedSubclassFqName(stringTable.getQualifiedClassNameIndex(inheritorId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val companionObject = regularClass?.companionObject
|
||||||
|
if (companionObject != null) {
|
||||||
|
builder.companionObjectName = getSimpleNameIndex(companionObject.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
val typeTableProto = typeTable.serialize()
|
||||||
|
if (typeTableProto != null) {
|
||||||
|
builder.typeTable = typeTableProto
|
||||||
|
}
|
||||||
|
|
||||||
|
if (versionRequirementTable == null) error("Version requirements must be serialized for classes: ${klass.render()}")
|
||||||
|
|
||||||
|
builder.addAllVersionRequirement(versionRequirementTable.serializeVersionRequirements(klass))
|
||||||
|
|
||||||
|
extension.serializeClass(klass, builder, versionRequirementTable, this)
|
||||||
|
|
||||||
|
writeVersionRequirementForInlineClasses(klass, builder, versionRequirementTable)
|
||||||
|
|
||||||
|
val versionRequirementTableProto = versionRequirementTable.serialize()
|
||||||
|
if (versionRequirementTableProto != null) {
|
||||||
|
builder.versionRequirementTable = versionRequirementTableProto
|
||||||
|
}
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun propertyProto(property: FirProperty): ProtoBuf.Property.Builder? {
|
||||||
|
if (!extension.shouldSerializeProperty(property)) return null
|
||||||
|
|
||||||
|
val builder = ProtoBuf.Property.newBuilder()
|
||||||
|
|
||||||
|
val local = createChildSerializer(property)
|
||||||
|
|
||||||
|
var hasGetter = false
|
||||||
|
var hasSetter = false
|
||||||
|
|
||||||
|
//val compileTimeConstant = property.compileTimeInitializer
|
||||||
|
val hasConstant = false // TODO: compileTimeConstant != null && compileTimeConstant !is NullValue
|
||||||
|
|
||||||
|
val hasAnnotations = property.annotations.isNotEmpty()
|
||||||
|
// TODO: hasAnnotations(descriptor) || hasAnnotations(descriptor.backingField) || hasAnnotations(descriptor.delegateField)
|
||||||
|
|
||||||
|
val modality = property.modality!!
|
||||||
|
val defaultAccessorFlags = Flags.getAccessorFlags(
|
||||||
|
hasAnnotations,
|
||||||
|
ProtoEnumFlags.visibility(normalizeVisibility(property)),
|
||||||
|
ProtoEnumFlags.modality(modality),
|
||||||
|
false, false, false
|
||||||
|
)
|
||||||
|
|
||||||
|
val getter = property.getter
|
||||||
|
if (getter != null) {
|
||||||
|
hasGetter = true
|
||||||
|
val accessorFlags = getAccessorFlags(getter, property)
|
||||||
|
if (accessorFlags != defaultAccessorFlags) {
|
||||||
|
builder.getterFlags = accessorFlags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val setter = property.setter
|
||||||
|
if (setter != null) {
|
||||||
|
hasSetter = true
|
||||||
|
val accessorFlags = getAccessorFlags(setter, property)
|
||||||
|
if (accessorFlags != defaultAccessorFlags) {
|
||||||
|
builder.setterFlags = accessorFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setter !is FirDefaultPropertyAccessor ||
|
||||||
|
setter.annotations.isNotEmpty() ||
|
||||||
|
setter.visibility != property.visibility
|
||||||
|
) {
|
||||||
|
val setterLocal = local.createChildSerializer(setter)
|
||||||
|
for (valueParameterDescriptor in setter.valueParameters) {
|
||||||
|
builder.setSetterValueParameter(setterLocal.valueParameterProto(valueParameterDescriptor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val flags = Flags.getPropertyFlags(
|
||||||
|
hasAnnotations,
|
||||||
|
ProtoEnumFlags.visibility(normalizeVisibility(property)),
|
||||||
|
ProtoEnumFlags.modality(modality),
|
||||||
|
ProtoEnumFlags.memberKind(CallableMemberDescriptor.Kind.DECLARATION),
|
||||||
|
property.isVar, hasGetter, hasSetter, hasConstant, property.isConst, property.isLateInit,
|
||||||
|
property.isExternal, property.delegateFieldSymbol != null, property.isExpect
|
||||||
|
)
|
||||||
|
if (flags != builder.flags) {
|
||||||
|
builder.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.name = getSimpleNameIndex(property.name)
|
||||||
|
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.returnTypeId = local.typeId(property.returnTypeRef)
|
||||||
|
} else {
|
||||||
|
builder.setReturnType(local.typeProto(property.returnTypeRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (typeParameter in property.typeParameters) {
|
||||||
|
builder.addTypeParameter(local.typeParameterProto(typeParameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverTypeRef = property.receiverTypeRef
|
||||||
|
if (receiverTypeRef != null) {
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.receiverTypeId = local.typeId(receiverTypeRef)
|
||||||
|
} else {
|
||||||
|
builder.setReceiverType(local.typeProto(receiverTypeRef))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
versionRequirementTable?.run {
|
||||||
|
builder.addAllVersionRequirement(serializeVersionRequirements(property))
|
||||||
|
|
||||||
|
if (property.isSuspendOrHasSuspendTypesInSignature()) {
|
||||||
|
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property.hasInlineClassTypesInSignature()) {
|
||||||
|
builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.serializeProperty(property, builder, versionRequirementTable, local)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun functionProto(function: FirFunction<*>): ProtoBuf.Function.Builder? {
|
||||||
|
if (!extension.shouldSerializeFunction(function)) return null
|
||||||
|
|
||||||
|
val builder = ProtoBuf.Function.newBuilder()
|
||||||
|
val simpleFunction = function as? FirSimpleFunction
|
||||||
|
|
||||||
|
val local = createChildSerializer(function)
|
||||||
|
|
||||||
|
val flags = Flags.getFunctionFlags(
|
||||||
|
function.annotations.isNotEmpty(),
|
||||||
|
ProtoEnumFlags.visibility(simpleFunction?.let { normalizeVisibility(it) } ?: Visibilities.LOCAL),
|
||||||
|
ProtoEnumFlags.modality(simpleFunction?.modality ?: Modality.FINAL),
|
||||||
|
ProtoEnumFlags.memberKind(CallableMemberDescriptor.Kind.DECLARATION),
|
||||||
|
simpleFunction?.isOperator == true,
|
||||||
|
simpleFunction?.isInfix == true,
|
||||||
|
simpleFunction?.isInline == true,
|
||||||
|
simpleFunction?.isTailRec == true,
|
||||||
|
simpleFunction?.isExternal == true,
|
||||||
|
simpleFunction?.isSuspend == true,
|
||||||
|
simpleFunction?.isExpect == true
|
||||||
|
)
|
||||||
|
if (flags != builder.flags) {
|
||||||
|
builder.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
val name = when (function) {
|
||||||
|
is FirSimpleFunction -> {
|
||||||
|
function.name
|
||||||
|
}
|
||||||
|
is FirAnonymousFunction -> {
|
||||||
|
if (function.isLambda) Name.special("<anonymous>") else Name.special("<no name provided>")
|
||||||
|
}
|
||||||
|
else -> throw AssertionError("Unsupported function: ${function.render()}")
|
||||||
|
}
|
||||||
|
builder.name = getSimpleNameIndex(name)
|
||||||
|
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.returnTypeId = local.typeId(function.returnTypeRef)
|
||||||
|
} else {
|
||||||
|
builder.setReturnType(local.typeProto(function.returnTypeRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (typeParameter in function.typeParameters) {
|
||||||
|
if (typeParameter !is FirTypeParameter) continue
|
||||||
|
builder.addTypeParameter(local.typeParameterProto(typeParameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverTypeRef = function.receiverTypeRef
|
||||||
|
if (receiverTypeRef != null) {
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.receiverTypeId = local.typeId(receiverTypeRef)
|
||||||
|
} else {
|
||||||
|
builder.setReceiverType(local.typeProto(receiverTypeRef))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (valueParameter in function.valueParameters) {
|
||||||
|
builder.addValueParameter(local.valueParameterProto(valueParameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serializeTypeTableToFunction) {
|
||||||
|
val typeTableProto = typeTable.serialize()
|
||||||
|
if (typeTableProto != null) {
|
||||||
|
builder.typeTable = typeTableProto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
versionRequirementTable?.run {
|
||||||
|
builder.addAllVersionRequirement(serializeVersionRequirements(function))
|
||||||
|
|
||||||
|
if (function.isSuspendOrHasSuspendTypesInSignature()) {
|
||||||
|
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function.hasInlineClassTypesInSignature()) {
|
||||||
|
builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contractSerializer.serializeContractOfFunctionIfAny(function, builder, this)
|
||||||
|
|
||||||
|
extension.serializeFunction(function, builder, versionRequirementTable, local)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun typeAliasProto(typeAlias: FirTypeAlias): ProtoBuf.TypeAlias.Builder? {
|
||||||
|
if (!extension.shouldSerializeTypeAlias(typeAlias)) return null
|
||||||
|
|
||||||
|
val builder = ProtoBuf.TypeAlias.newBuilder()
|
||||||
|
val local = createChildSerializer(typeAlias)
|
||||||
|
|
||||||
|
val flags = Flags.getTypeAliasFlags(
|
||||||
|
typeAlias.annotations.isNotEmpty(),
|
||||||
|
ProtoEnumFlags.visibility(normalizeVisibility(typeAlias))
|
||||||
|
)
|
||||||
|
if (flags != builder.flags) {
|
||||||
|
builder.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.name = getSimpleNameIndex(typeAlias.name)
|
||||||
|
|
||||||
|
for (typeParameter in typeAlias.typeParameters) {
|
||||||
|
builder.addTypeParameter(local.typeParameterProto(typeParameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
val underlyingType = typeAlias.expandedConeType!!
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.underlyingTypeId = local.typeId(underlyingType)
|
||||||
|
} else {
|
||||||
|
builder.setUnderlyingType(local.typeProto(underlyingType))
|
||||||
|
}
|
||||||
|
|
||||||
|
val expandedType = underlyingType.fullyExpandedType(session)
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.expandedTypeId = local.typeId(expandedType)
|
||||||
|
} else {
|
||||||
|
builder.setExpandedType(local.typeProto(expandedType))
|
||||||
|
}
|
||||||
|
|
||||||
|
versionRequirementTable?.run {
|
||||||
|
builder.addAllVersionRequirement(serializeVersionRequirements(typeAlias))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (annotation in typeAlias.annotations) {
|
||||||
|
builder.addAnnotation(extension.annotationSerializer.serializeAnnotation(annotation))
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.serializeTypeAlias(typeAlias, builder)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enumEntryProto(enumEntry: FirEnumEntry): ProtoBuf.EnumEntry.Builder {
|
||||||
|
val builder = ProtoBuf.EnumEntry.newBuilder()
|
||||||
|
builder.name = getSimpleNameIndex(enumEntry.name)
|
||||||
|
extension.serializeEnumEntry(enumEntry, builder)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun constructorProto(constructor: FirConstructor): ProtoBuf.Constructor.Builder {
|
||||||
|
val builder = ProtoBuf.Constructor.newBuilder()
|
||||||
|
|
||||||
|
val local = createChildSerializer(constructor)
|
||||||
|
|
||||||
|
val flags = Flags.getConstructorFlags(
|
||||||
|
constructor.annotations.isNotEmpty(),
|
||||||
|
ProtoEnumFlags.visibility(normalizeVisibility(constructor)),
|
||||||
|
!constructor.isPrimary
|
||||||
|
)
|
||||||
|
if (flags != builder.flags) {
|
||||||
|
builder.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
for (valueParameter in constructor.valueParameters) {
|
||||||
|
builder.addValueParameter(local.valueParameterProto(valueParameter))
|
||||||
|
}
|
||||||
|
|
||||||
|
versionRequirementTable?.run {
|
||||||
|
builder.addAllVersionRequirement(serializeVersionRequirements(constructor))
|
||||||
|
|
||||||
|
if (constructor.isSuspendOrHasSuspendTypesInSignature()) {
|
||||||
|
builder.addVersionRequirement(writeVersionRequirementDependingOnCoroutinesVersion())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constructor.hasInlineClassTypesInSignature()) {
|
||||||
|
builder.addVersionRequirement(writeVersionRequirement(LanguageFeature.InlineClasses))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.serializeConstructor(constructor, builder, local)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun valueParameterProto(parameter: FirValueParameter): ProtoBuf.ValueParameter.Builder {
|
||||||
|
val builder = ProtoBuf.ValueParameter.newBuilder()
|
||||||
|
|
||||||
|
val declaresDefaultValue = parameter.defaultValue != null // TODO: || parameter.isActualParameterWithAnyExpectedDefault
|
||||||
|
|
||||||
|
val flags = Flags.getValueParameterFlags(
|
||||||
|
parameter.annotations.isNotEmpty(), declaresDefaultValue,
|
||||||
|
parameter.isCrossinline, parameter.isNoinline
|
||||||
|
)
|
||||||
|
if (flags != builder.flags) {
|
||||||
|
builder.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.name = getSimpleNameIndex(parameter.name)
|
||||||
|
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.typeId = typeId(parameter.returnTypeRef)
|
||||||
|
} else {
|
||||||
|
builder.setType(typeProto(parameter.returnTypeRef))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameter.isVararg) {
|
||||||
|
val varargElementType = parameter.returnTypeRef.coneTypeSafe<ConeKotlinType>()?.varargElementType(session)
|
||||||
|
if (varargElementType != null) {
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.varargElementTypeId = typeId(varargElementType)
|
||||||
|
} else {
|
||||||
|
builder.setVarargElementType(typeProto(varargElementType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.serializeValueParameter(parameter, builder)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun typeParameterProto(typeParameter: FirTypeParameter): ProtoBuf.TypeParameter.Builder {
|
||||||
|
val builder = ProtoBuf.TypeParameter.newBuilder()
|
||||||
|
|
||||||
|
builder.id = getTypeParameterId(typeParameter)
|
||||||
|
|
||||||
|
builder.name = getSimpleNameIndex(typeParameter.name)
|
||||||
|
|
||||||
|
if (typeParameter.isReified != builder.reified) {
|
||||||
|
builder.reified = typeParameter.isReified
|
||||||
|
}
|
||||||
|
|
||||||
|
val variance = variance(typeParameter.variance)
|
||||||
|
if (variance != builder.variance) {
|
||||||
|
builder.variance = variance
|
||||||
|
}
|
||||||
|
extension.serializeTypeParameter(typeParameter, builder)
|
||||||
|
|
||||||
|
val upperBounds = typeParameter.bounds
|
||||||
|
if (upperBounds.size == 1 && upperBounds.single() is FirImplicitNullableAnyTypeRef) return builder
|
||||||
|
|
||||||
|
for (upperBound in upperBounds) {
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.addUpperBoundId(typeId(upperBound))
|
||||||
|
} else {
|
||||||
|
builder.addUpperBound(typeProto(upperBound))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun typeId(typeRef: FirTypeRef): Int {
|
||||||
|
if (typeRef !is FirResolvedTypeRef) {
|
||||||
|
return -1 // TODO: serializeErrorType?
|
||||||
|
}
|
||||||
|
return typeId(typeRef.type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun typeId(type: ConeKotlinType): Int = typeTable[typeProto(type)]
|
||||||
|
|
||||||
|
internal fun typeProto(typeRef: FirTypeRef): ProtoBuf.Type.Builder {
|
||||||
|
return typeProto((typeRef as FirResolvedTypeRef).type)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun typeProto(type: ConeKotlinType): ProtoBuf.Type.Builder {
|
||||||
|
val builder = ProtoBuf.Type.newBuilder()
|
||||||
|
|
||||||
|
if (type is ConeKotlinErrorType) {
|
||||||
|
extension.serializeErrorType(type, builder)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type is ConeFlexibleType) {
|
||||||
|
val lowerBound = typeProto(type.lowerBound)
|
||||||
|
val upperBound = typeProto(type.upperBound)
|
||||||
|
extension.serializeFlexibleType(type, lowerBound, upperBound)
|
||||||
|
if (useTypeTable()) {
|
||||||
|
lowerBound.flexibleUpperBoundId = typeTable[upperBound]
|
||||||
|
} else {
|
||||||
|
lowerBound.setFlexibleUpperBound(upperBound)
|
||||||
|
}
|
||||||
|
return lowerBound
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (type is ConeClassLikeType && type.isSuspendFunctionType(session)) {
|
||||||
|
// TODO: suspend function type
|
||||||
|
// val functionType = typeProto(transformSuspendFunctionToRuntimeFunctionType(type, extension.releaseCoroutines()))
|
||||||
|
// functionType.flags = Flags.getTypeFlags(true)
|
||||||
|
// return functionType
|
||||||
|
}
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
is ConeClassLikeType -> {
|
||||||
|
fillFromPossiblyInnerType(builder, type)
|
||||||
|
}
|
||||||
|
is ConeTypeParameterType -> {
|
||||||
|
// TODO: type parameter containing declaration?
|
||||||
|
if (false /*descriptor.containingDeclaration === containingDeclaration*/) {
|
||||||
|
//builder.typeParameterName = getSimpleNameIndex(descriptor.name)
|
||||||
|
} else {
|
||||||
|
builder.typeParameter = getTypeParameterId(type.lookupTag.typeParameterSymbol.fir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.isMarkedNullable != builder.nullable) {
|
||||||
|
builder.nullable = type.isMarkedNullable
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: abbreviated type
|
||||||
|
// val abbreviation = type.getAbbreviatedType()?.abbreviation
|
||||||
|
// if (abbreviation != null) {
|
||||||
|
// if (useTypeTable()) {
|
||||||
|
// builder.abbreviatedTypeId = typeId(abbreviation)
|
||||||
|
// } else {
|
||||||
|
// builder.setAbbreviatedType(typeProto(abbreviation))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
extension.serializeType(type, builder)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fillFromPossiblyInnerType(builder: ProtoBuf.Type.Builder, type: ConeClassLikeType) {
|
||||||
|
val classifierSymbol = type.lookupTag.toSymbol(session)!!
|
||||||
|
val classifier = classifierSymbol.fir
|
||||||
|
val classifierId = getClassifierId(classifier)
|
||||||
|
builder.className = classifierId
|
||||||
|
|
||||||
|
for (projection in type.typeArguments) {
|
||||||
|
builder.addArgument(typeArgument(projection))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: outer type
|
||||||
|
// if (type.outerType != null) {
|
||||||
|
// val outerBuilder = ProtoBuf.Type.newBuilder()
|
||||||
|
// fillFromPossiblyInnerType(outerBuilder, type.outerType!!)
|
||||||
|
// if (useTypeTable()) {
|
||||||
|
// builder.outerTypeId = typeTable[outerBuilder]
|
||||||
|
// } else {
|
||||||
|
// builder.setOuterType(outerBuilder)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun typeArgument(typeProjection: ConeTypeProjection): ProtoBuf.Type.Argument.Builder {
|
||||||
|
val builder = ProtoBuf.Type.Argument.newBuilder()
|
||||||
|
|
||||||
|
if (typeProjection is ConeStarProjection) {
|
||||||
|
builder.projection = ProtoBuf.Type.Argument.Projection.STAR
|
||||||
|
} else if (typeProjection is ConeKotlinTypeProjection) {
|
||||||
|
val projection = projection(typeProjection.kind)
|
||||||
|
|
||||||
|
if (projection != builder.projection) {
|
||||||
|
builder.projection = projection
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useTypeTable()) {
|
||||||
|
builder.typeId = typeId(typeProjection.type)
|
||||||
|
} else {
|
||||||
|
builder.setType(typeProto(typeProjection.type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAccessorFlags(accessor: FirPropertyAccessor, property: FirProperty): Int {
|
||||||
|
val isDefault = accessor is FirDefaultPropertyAccessor &&
|
||||||
|
accessor.annotations.isEmpty() && accessor.visibility == property.visibility
|
||||||
|
return Flags.getAccessorFlags(
|
||||||
|
accessor.annotations.isNotEmpty(),
|
||||||
|
ProtoEnumFlags.visibility(normalizeVisibility(accessor)),
|
||||||
|
ProtoEnumFlags.modality(accessor.modality!!),
|
||||||
|
!isDefault,
|
||||||
|
accessor.status.isExternal,
|
||||||
|
accessor.status.isInline
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createChildSerializer(declaration: FirDeclaration): FirElementSerializer =
|
||||||
|
FirElementSerializer(
|
||||||
|
session, declaration, Interner(typeParameters), extension,
|
||||||
|
typeTable, versionRequirementTable, serializeTypeTableToFunction = false
|
||||||
|
)
|
||||||
|
|
||||||
|
private val stringTable: FirElementAwareStringTable
|
||||||
|
get() = extension.stringTable
|
||||||
|
|
||||||
|
private fun useTypeTable(): Boolean = extension.shouldUseTypeTable()
|
||||||
|
|
||||||
|
private fun FirDeclaration.hasInlineClassTypesInSignature(): Boolean {
|
||||||
|
// TODO
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirCallableDeclaration<*>.isSuspendOrHasSuspendTypesInSignature(): Boolean {
|
||||||
|
// TODO
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeVersionRequirementForInlineClasses(
|
||||||
|
klass: FirClass<*>,
|
||||||
|
builder: ProtoBuf.Class.Builder,
|
||||||
|
versionRequirementTable: MutableVersionRequirementTable
|
||||||
|
) {
|
||||||
|
if (klass !is FirRegularClass || !klass.isInline && !klass.hasInlineClassTypesInSignature()) return
|
||||||
|
|
||||||
|
builder.addVersionRequirement(
|
||||||
|
writeLanguageVersionRequirement(LanguageFeature.InlineClasses, versionRequirementTable)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableVersionRequirementTable.serializeVersionRequirements(container: FirAnnotationContainer): List<Int> =
|
||||||
|
serializeVersionRequirements(container.annotations)
|
||||||
|
|
||||||
|
private fun MutableVersionRequirementTable.serializeVersionRequirements(annotations: List<FirAnnotationCall>): List<Int> =
|
||||||
|
annotations
|
||||||
|
.filter {
|
||||||
|
val annotationConeType = it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()
|
||||||
|
annotationConeType?.lookupTag?.classId?.asSingleFqName() == RequireKotlinConstants.FQ_NAME
|
||||||
|
}
|
||||||
|
.mapNotNull(::serializeVersionRequirementFromRequireKotlin)
|
||||||
|
.map(::get)
|
||||||
|
|
||||||
|
private fun MutableVersionRequirementTable.writeVersionRequirement(languageFeature: LanguageFeature): Int {
|
||||||
|
return writeLanguageVersionRequirement(languageFeature, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableVersionRequirementTable.writeVersionRequirementDependingOnCoroutinesVersion(): Int =
|
||||||
|
writeVersionRequirement(LanguageFeature.ReleaseCoroutines)
|
||||||
|
|
||||||
|
private operator fun FirArgumentList.get(name: Name): ConstantValue<*>? {
|
||||||
|
// TODO: constant evaluation
|
||||||
|
val expression = arguments.filterIsInstance<FirNamedArgumentExpression>().find {
|
||||||
|
name == name
|
||||||
|
}?.expression
|
||||||
|
if (expression !is FirConstExpression<*>) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return expression.value as? ConstantValue<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun serializeVersionRequirementFromRequireKotlin(annotation: FirAnnotationCall): ProtoBuf.VersionRequirement.Builder? {
|
||||||
|
val args = annotation.argumentList
|
||||||
|
|
||||||
|
val versionString = (args[RequireKotlinConstants.VERSION] as? StringValue)?.value ?: return null
|
||||||
|
val matchResult = RequireKotlinConstants.VERSION_REGEX.matchEntire(versionString) ?: return null
|
||||||
|
|
||||||
|
val major = matchResult.groupValues.getOrNull(1)?.toIntOrNull() ?: return null
|
||||||
|
val minor = matchResult.groupValues.getOrNull(2)?.toIntOrNull() ?: 0
|
||||||
|
val patch = matchResult.groupValues.getOrNull(4)?.toIntOrNull() ?: 0
|
||||||
|
|
||||||
|
val proto = ProtoBuf.VersionRequirement.newBuilder()
|
||||||
|
VersionRequirement.Version(major, minor, patch).encode(
|
||||||
|
writeVersion = { proto.version = it },
|
||||||
|
writeVersionFull = { proto.versionFull = it }
|
||||||
|
)
|
||||||
|
|
||||||
|
val message = (args[RequireKotlinConstants.MESSAGE] as? StringValue)?.value
|
||||||
|
if (message != null) {
|
||||||
|
proto.message = stringTable.getStringIndex(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
when ((args[RequireKotlinConstants.LEVEL] as? EnumValue)?.enumEntryName?.asString()) {
|
||||||
|
DeprecationLevel.ERROR.name -> {
|
||||||
|
// ERROR is the default level
|
||||||
|
}
|
||||||
|
DeprecationLevel.WARNING.name -> proto.level = ProtoBuf.VersionRequirement.Level.WARNING
|
||||||
|
DeprecationLevel.HIDDEN.name -> proto.level = ProtoBuf.VersionRequirement.Level.HIDDEN
|
||||||
|
}
|
||||||
|
|
||||||
|
when ((args[RequireKotlinConstants.VERSION_KIND] as? EnumValue)?.enumEntryName?.asString()) {
|
||||||
|
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION.name -> {
|
||||||
|
// LANGUAGE_VERSION is the default kind
|
||||||
|
}
|
||||||
|
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION.name ->
|
||||||
|
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION
|
||||||
|
ProtoBuf.VersionRequirement.VersionKind.API_VERSION.name ->
|
||||||
|
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.API_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
val errorCode = (args[RequireKotlinConstants.ERROR_CODE] as? IntValue)?.value
|
||||||
|
if (errorCode != null && errorCode != -1) {
|
||||||
|
proto.errorCode = errorCode
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun normalizeVisibility(declaration: FirMemberDeclaration): Visibility {
|
||||||
|
// It can be necessary for Java classes serialization having package-private visibility
|
||||||
|
return if (extension.shouldUseNormalizedVisibility()) declaration.visibility.normalize()
|
||||||
|
else declaration.visibility
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun normalizeVisibility(declaration: FirPropertyAccessor): Visibility {
|
||||||
|
// It can be necessary for Java classes serialization having package-private visibility
|
||||||
|
return if (extension.shouldUseNormalizedVisibility()) declaration.visibility.normalize()
|
||||||
|
else declaration.visibility
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getClassifierId(declaration: FirClassLikeDeclaration<*>): Int =
|
||||||
|
stringTable.getFqNameIndex(declaration)
|
||||||
|
|
||||||
|
private fun getSimpleNameIndex(name: Name): Int =
|
||||||
|
stringTable.getStringIndex(name.asString())
|
||||||
|
|
||||||
|
private fun getTypeParameterId(typeParameter: FirTypeParameter): Int =
|
||||||
|
typeParameters.intern(typeParameter)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun createTopLevel(session: FirSession, extension: FirSerializerExtension): FirElementSerializer =
|
||||||
|
FirElementSerializer(
|
||||||
|
session, null,
|
||||||
|
Interner(), extension, MutableTypeTable(), MutableVersionRequirementTable(),
|
||||||
|
serializeTypeTableToFunction = false
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun createForLambda(session: FirSession, extension: FirSerializerExtension): FirElementSerializer =
|
||||||
|
FirElementSerializer(
|
||||||
|
session, null,
|
||||||
|
Interner(), extension, MutableTypeTable(),
|
||||||
|
versionRequirementTable = null, serializeTypeTableToFunction = true
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun create(
|
||||||
|
klass: FirClass<*>,
|
||||||
|
extension: FirSerializerExtension,
|
||||||
|
parentSerializer: FirElementSerializer?
|
||||||
|
): FirElementSerializer {
|
||||||
|
val parentClassId = klass.symbol.classId.outerClassId
|
||||||
|
val parent = if (parentClassId != null && !parentClassId.isLocal) {
|
||||||
|
val parentClass = klass.session.firSymbolProvider.getClassLikeSymbolByFqName(parentClassId)!!.fir as FirRegularClass
|
||||||
|
parentSerializer ?: create(parentClass, extension, null)
|
||||||
|
} else {
|
||||||
|
createTopLevel(klass.session, extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
|
||||||
|
// serializing outer classes before nested classes.
|
||||||
|
// Otherwise our interner can get wrong ids because we may serialize classes in any order.
|
||||||
|
val serializer = FirElementSerializer(
|
||||||
|
klass.session,
|
||||||
|
klass,
|
||||||
|
Interner(parent.typeParameters),
|
||||||
|
extension,
|
||||||
|
MutableTypeTable(),
|
||||||
|
if (parentClassId != null && !isKotlin1Dot4OrLater(extension.metadataVersion)) {
|
||||||
|
parent.versionRequirementTable
|
||||||
|
} else {
|
||||||
|
MutableVersionRequirementTable()
|
||||||
|
},
|
||||||
|
serializeTypeTableToFunction = false
|
||||||
|
)
|
||||||
|
for (typeParameter in klass.typeParameters) {
|
||||||
|
if (typeParameter !is FirTypeParameter) continue
|
||||||
|
serializer.typeParameters.intern(typeParameter)
|
||||||
|
}
|
||||||
|
return serializer
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeLanguageVersionRequirement(
|
||||||
|
languageFeature: LanguageFeature,
|
||||||
|
versionRequirementTable: MutableVersionRequirementTable
|
||||||
|
): Int {
|
||||||
|
val languageVersion = languageFeature.sinceVersion!!
|
||||||
|
return writeVersionRequirement(
|
||||||
|
languageVersion.major, languageVersion.minor, 0,
|
||||||
|
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION,
|
||||||
|
versionRequirementTable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun writeVersionRequirement(
|
||||||
|
major: Int,
|
||||||
|
minor: Int,
|
||||||
|
patch: Int,
|
||||||
|
versionKind: ProtoBuf.VersionRequirement.VersionKind,
|
||||||
|
versionRequirementTable: MutableVersionRequirementTable
|
||||||
|
): Int {
|
||||||
|
val requirement = ProtoBuf.VersionRequirement.newBuilder().apply {
|
||||||
|
VersionRequirement.Version(major, minor, patch).encode(
|
||||||
|
writeVersion = { version = it },
|
||||||
|
writeVersionFull = { versionFull = it }
|
||||||
|
)
|
||||||
|
if (versionKind != defaultInstanceForType.versionKind) {
|
||||||
|
this.versionKind = versionKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return versionRequirementTable[requirement]
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun variance(variance: Variance): ProtoBuf.TypeParameter.Variance = when (variance) {
|
||||||
|
Variance.INVARIANT -> ProtoBuf.TypeParameter.Variance.INV
|
||||||
|
Variance.IN_VARIANCE -> ProtoBuf.TypeParameter.Variance.IN
|
||||||
|
Variance.OUT_VARIANCE -> ProtoBuf.TypeParameter.Variance.OUT
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun projection(projectionKind: ProjectionKind): ProtoBuf.Type.Argument.Projection = when (projectionKind) {
|
||||||
|
ProjectionKind.INVARIANT -> ProtoBuf.Type.Argument.Projection.INV
|
||||||
|
ProjectionKind.IN -> ProtoBuf.Type.Argument.Projection.IN
|
||||||
|
ProjectionKind.OUT -> ProtoBuf.Type.Argument.Projection.OUT
|
||||||
|
ProjectionKind.STAR -> throw AssertionError("Should not be here")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||||
|
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
|
abstract class FirSerializerExtension {
|
||||||
|
abstract val session: FirSession
|
||||||
|
|
||||||
|
abstract val stringTable: FirElementAwareStringTable
|
||||||
|
|
||||||
|
abstract val metadataVersion: BinaryVersion
|
||||||
|
|
||||||
|
val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable) }
|
||||||
|
|
||||||
|
open fun shouldSerializeNestedClass(nestedClass: FirRegularClass): Boolean = true
|
||||||
|
open fun shouldSerializeTypeAlias(typeAlias: FirTypeAlias): Boolean = true
|
||||||
|
open fun shouldUseTypeTable(): Boolean = false
|
||||||
|
open fun shouldUseNormalizedVisibility(): Boolean = false
|
||||||
|
open fun shouldSerializeFunction(function: FirFunction<*>): Boolean = false
|
||||||
|
open fun shouldSerializeProperty(property: FirProperty): Boolean = false
|
||||||
|
|
||||||
|
open fun serializePackage(packageFqName: FqName, proto: ProtoBuf.Package.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeClass(
|
||||||
|
klass: FirClass<*>,
|
||||||
|
proto: ProtoBuf.Class.Builder,
|
||||||
|
versionRequirementTable: MutableVersionRequirementTable,
|
||||||
|
childSerializer: FirElementSerializer
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeConstructor(
|
||||||
|
constructor: FirConstructor,
|
||||||
|
proto: ProtoBuf.Constructor.Builder,
|
||||||
|
childSerializer: FirElementSerializer
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeFunction(
|
||||||
|
function: FirFunction<*>,
|
||||||
|
proto: ProtoBuf.Function.Builder,
|
||||||
|
versionRequirementTable: MutableVersionRequirementTable?,
|
||||||
|
childSerializer: FirElementSerializer
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeProperty(
|
||||||
|
property: FirProperty,
|
||||||
|
proto: ProtoBuf.Property.Builder,
|
||||||
|
versionRequirementTable: MutableVersionRequirementTable?,
|
||||||
|
childSerializer: FirElementSerializer
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeEnumEntry(enumEntry: FirEnumEntry, proto: ProtoBuf.EnumEntry.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeValueParameter(parameter: FirValueParameter, proto: ProtoBuf.ValueParameter.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeFlexibleType(type: ConeFlexibleType, lowerProto: ProtoBuf.Type.Builder, upperProto: ProtoBuf.Type.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeType(type: ConeKotlinType, proto: ProtoBuf.Type.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeTypeParameter(typeParameter: FirTypeParameter, proto: ProtoBuf.TypeParameter.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeTypeAlias(typeAlias: FirTypeAlias, proto: ProtoBuf.TypeAlias.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun serializeErrorType(type: ConeKotlinErrorType, builder: ProtoBuf.Type.Builder) {
|
||||||
|
throw IllegalStateException("Cannot serialize error type: $type")
|
||||||
|
}
|
||||||
|
|
||||||
|
open val customClassMembersProducer: ClassMembersProducer?
|
||||||
|
get() = null
|
||||||
|
|
||||||
|
interface ClassMembersProducer {
|
||||||
|
fun getCallableMembers(klass: FirClass<*>): Collection<FirCallableMemberDeclaration<*>>
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ dependencies {
|
|||||||
compileOnly(project(":core:descriptors"))
|
compileOnly(project(":core:descriptors"))
|
||||||
compileOnly(project(":compiler:fir:cones"))
|
compileOnly(project(":compiler:fir:cones"))
|
||||||
compileOnly(project(":compiler:fir:resolve"))
|
compileOnly(project(":compiler:fir:resolve"))
|
||||||
|
compileOnly(project(":compiler:fir:fir-serialization"))
|
||||||
compileOnly(project(":compiler:fir:tree"))
|
compileOnly(project(":compiler:fir:tree"))
|
||||||
compileOnly(project(":compiler:ir.tree"))
|
compileOnly(project(":compiler:ir.tree"))
|
||||||
compileOnly(project(":compiler:ir.psi2ir"))
|
compileOnly(project(":compiler:ir.psi2ir"))
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ internal fun FirExpression.getExpectedType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
|
fun ConeKotlinType.varargElementType(session: FirSession): ConeKotlinType {
|
||||||
return this.arrayElementType(session) ?: error("Failed to extract! ${this.render()}!")
|
return this.arrayElementType(session) ?: error("Failed to extract! ${this.render()}!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ val projectsToShadow by extra(listOf(
|
|||||||
":compiler:fir:cones",
|
":compiler:fir:cones",
|
||||||
":compiler:fir:checkers",
|
":compiler:fir:checkers",
|
||||||
":compiler:fir:resolve",
|
":compiler:fir:resolve",
|
||||||
|
":compiler:fir:fir-serialization",
|
||||||
":compiler:fir:tree",
|
":compiler:fir:tree",
|
||||||
":compiler:fir:java",
|
":compiler:fir:java",
|
||||||
":compiler:fir:jvm",
|
":compiler:fir:jvm",
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ include ":kotlin-build-common",
|
|||||||
":compiler:fir:fir2ir",
|
":compiler:fir:fir2ir",
|
||||||
":compiler:fir:fir2ir:jvm-backend",
|
":compiler:fir:fir2ir:jvm-backend",
|
||||||
":compiler:fir:resolve",
|
":compiler:fir:resolve",
|
||||||
|
":compiler:fir:fir-serialization",
|
||||||
":compiler:fir:java",
|
":compiler:fir:java",
|
||||||
":compiler:fir:modularized-tests",
|
":compiler:fir:modularized-tests",
|
||||||
":compiler:fir:dump",
|
":compiler:fir:dump",
|
||||||
|
|||||||
Reference in New Issue
Block a user