Use EnumSerializer for explicitly serializable enum instead of auto-generated
Resolves Kotlin/kotlinx.serialization#683 Kotlin/kotlinx.serialization#1372
This commit is contained in:
+4
-1
@@ -33,7 +33,10 @@ abstract class SerializableCompanionCodegen(
|
||||
"probably clash with user-defined function has occurred"
|
||||
)
|
||||
|
||||
if (serializableDescriptor.isSerializableObject || serializableDescriptor.isAbstractOrSealedSerializableClass()) {
|
||||
if (serializableDescriptor.isSerializableObject
|
||||
|| serializableDescriptor.isAbstractOrSealedSerializableClass()
|
||||
|| serializableDescriptor.isSerializableEnum()
|
||||
) {
|
||||
generateLazySerializerGetter(serializerGetterDescriptor)
|
||||
} else {
|
||||
generateSerializerGetter(serializerGetterDescriptor)
|
||||
|
||||
+1
-1
@@ -225,7 +225,7 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
|
||||
|
||||
fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
|
||||
val classDescriptor = kType.toClassDescriptor ?: return null
|
||||
return if (classDescriptor.kind == ClassKind.ENUM_CLASS && !classDescriptor.isInternallySerializableEnum())
|
||||
return if (classDescriptor.kind == ClassKind.ENUM_CLASS && !classDescriptor.isEnumWithLegacyGeneratedSerializer())
|
||||
module.findClassAcrossModuleDependencies(enumSerializerId)
|
||||
else null
|
||||
}
|
||||
|
||||
+54
-6
@@ -52,6 +52,12 @@ interface IrBuilderExtension {
|
||||
private val throwMissedFieldExceptionArrayFunc
|
||||
get() = compilerContext.referenceFunctions(SerialEntityNames.ARRAY_MASK_FIELD_MISSING_FUNC_FQ).singleOrNull()
|
||||
|
||||
private val enumSerializerFactoryFunc
|
||||
get() = compilerContext.referenceFunctions(SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_FQ).singleOrNull()
|
||||
|
||||
private val markedEnumSerializerFactoryFunc
|
||||
get() = compilerContext.referenceFunctions(SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_FQ).singleOrNull()
|
||||
|
||||
private inline fun <reified T : IrDeclaration> IrClass.searchForDeclaration(descriptor: DeclarationDescriptor): T? {
|
||||
return declarations.singleOrNull { it.descriptor == descriptor } as? T
|
||||
}
|
||||
@@ -1041,13 +1047,55 @@ interface IrBuilderExtension {
|
||||
}
|
||||
enumSerializerId -> {
|
||||
serializerClass = module.getClassFromInternalSerializationPackage(SpecialBuiltins.enumSerializer)
|
||||
args = kType.toClassDescriptor!!.let { enumDesc ->
|
||||
listOf(
|
||||
irString(enumDesc.serialName()),
|
||||
irCall(findEnumValuesMethod(enumDesc))
|
||||
)
|
||||
}
|
||||
val enumDescriptor = kType.toClassDescriptor!!
|
||||
typeArgs = listOf(thisIrType)
|
||||
// instantiate serializer only inside enum Companion
|
||||
if (enclosingGenerator !is SerializableCompanionIrGenerator) {
|
||||
// otherwise call Companion.serializer()
|
||||
callSerializerFromCompanion(thisIrType, typeArgs, emptyList())?.let { return it }
|
||||
}
|
||||
|
||||
val enumArgs = mutableListOf(
|
||||
irString(enumDescriptor.serialName()),
|
||||
irCall(findEnumValuesMethod(enumDescriptor)),
|
||||
)
|
||||
|
||||
val enumSerializerFactoryFunc = enumSerializerFactoryFunc
|
||||
val markedEnumSerializerFactoryFunc = markedEnumSerializerFactoryFunc
|
||||
if (enumSerializerFactoryFunc != null && markedEnumSerializerFactoryFunc != null) {
|
||||
// runtime contains enum serializer factory functions
|
||||
val factoryFunc: IrSimpleFunctionSymbol = if (enumDescriptor.isEnumWithSerialInfoAnnotation()) {
|
||||
// need to store SerialInfo annotation in descriptor
|
||||
val enumEntries = enumDescriptor.enumEntries()
|
||||
val entriesNames = enumEntries.map { it.annotations.serialNameValue?.let { n -> irString(n) } ?: irNull() }
|
||||
val entriesAnnotations = enumEntries.map {
|
||||
val annotationConstructors = it.annotations.mapNotNull { a ->
|
||||
compilerContext.typeTranslator.constantValueGenerator.generateAnnotationConstructorCall(a)
|
||||
}
|
||||
val annotationsConstructors = copyAnnotationsFrom(annotationConstructors)
|
||||
if (annotationsConstructors.isEmpty()) {
|
||||
irNull()
|
||||
} else {
|
||||
createArrayOfExpression(compilerContext.irBuiltIns.annotationType, annotationsConstructors)
|
||||
}
|
||||
}
|
||||
val annotationArrayType =
|
||||
compilerContext.irBuiltIns.arrayClass.typeWith(compilerContext.irBuiltIns.annotationType.makeNullable())
|
||||
|
||||
enumArgs += createArrayOfExpression(compilerContext.irBuiltIns.stringType.makeNullable(), entriesNames)
|
||||
enumArgs += createArrayOfExpression(annotationArrayType, entriesAnnotations)
|
||||
|
||||
markedEnumSerializerFactoryFunc
|
||||
} else {
|
||||
enumSerializerFactoryFunc
|
||||
}
|
||||
|
||||
val factoryReturnType = factoryFunc.owner.returnType.substitute(factoryFunc.owner.typeParameters, typeArgs)
|
||||
return irInvoke(null, factoryFunc, typeArgs, enumArgs, factoryReturnType)
|
||||
} else {
|
||||
// support legacy serializer instantiation by constructor for old runtimes
|
||||
args = enumArgs
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
args = kType.arguments.map {
|
||||
|
||||
+1
-1
@@ -566,7 +566,7 @@ open class SerializerIrGenerator(
|
||||
) {
|
||||
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
|
||||
val generator = when {
|
||||
serializableDesc.isInternallySerializableEnum() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
|
||||
serializableDesc.isEnumWithLegacyGeneratedSerializer() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
|
||||
serializableDesc.isInlineClass() -> SerializerForInlineClassGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
|
||||
else -> SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator)
|
||||
}
|
||||
|
||||
+59
-11
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
|
||||
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -165,18 +166,65 @@ internal fun AbstractSerialGenerator.serializerInstance(
|
||||
serializerClass.classId == contextSerializerId || serializerClass.classId == polymorphicSerializerId -> listOf(
|
||||
ExpressionVisitor.getObjectKClass(context, kType.toClassDescriptor!!)
|
||||
)
|
||||
serializerClass.classId == enumSerializerId -> listOf(
|
||||
JsStringLiteral(kType.serialName()),
|
||||
// EnumClass.values() invocation
|
||||
JsInvocation(
|
||||
context.getInnerNameForDescriptor(
|
||||
DescriptorUtils.getFunctionByName(
|
||||
kType.toClassDescriptor!!.staticScope,
|
||||
StandardNames.ENUM_VALUES
|
||||
)
|
||||
).makeRef()
|
||||
serializerClass.classId == enumSerializerId -> {
|
||||
val enumDescriptor = kType.toClassDescriptor!!
|
||||
|
||||
val enumArgs = mutableListOf(
|
||||
JsStringLiteral(enumDescriptor.serialName()),
|
||||
// EnumClass.values() invocation
|
||||
JsInvocation(
|
||||
context.getInnerNameForDescriptor(
|
||||
DescriptorUtils.getFunctionByName(
|
||||
enumDescriptor.staticScope,
|
||||
StandardNames.ENUM_VALUES
|
||||
)
|
||||
).makeRef()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val packageScope = context.currentModule.getPackage(SerializationPackages.internalPackageFqName).memberScope
|
||||
val enumSerializerFactoryFunc = DescriptorUtils.getFunctionByNameOrNull(
|
||||
packageScope,
|
||||
SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME
|
||||
)
|
||||
val markedEnumSerializerFactoryFunc = DescriptorUtils.getFunctionByNameOrNull(
|
||||
packageScope,
|
||||
SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME
|
||||
)
|
||||
if (enumSerializerFactoryFunc != null && markedEnumSerializerFactoryFunc != null) {
|
||||
// runtime contains enum serializer factory functions
|
||||
val factoryFunc = if (enumDescriptor.isEnumWithSerialInfoAnnotation()) {
|
||||
val enumEntries = enumDescriptor.enumEntries()
|
||||
val entriesNames =
|
||||
enumEntries.map { it.annotations.serialNameValue?.let { n -> JsStringLiteral(n) } ?: JsNullLiteral() }
|
||||
|
||||
val entriesAnnotations = enumEntries.map {
|
||||
val annotationsConstructors = it.annotationsWithArguments().map { (annotationClass, args, _) ->
|
||||
val argExprs = args.map { arg ->
|
||||
Translation.translateAsExpression(arg.getArgumentExpression()!!, context)
|
||||
}
|
||||
val classRef = context.translateQualifiedReference(annotationClass)
|
||||
JsNew(classRef, argExprs)
|
||||
}
|
||||
|
||||
if (annotationsConstructors.isEmpty()) {
|
||||
JsNullLiteral()
|
||||
} else {
|
||||
JsArrayLiteral(annotationsConstructors)
|
||||
}
|
||||
}
|
||||
enumArgs += JsArrayLiteral(entriesNames)
|
||||
enumArgs += JsArrayLiteral(entriesAnnotations)
|
||||
markedEnumSerializerFactoryFunc
|
||||
} else {
|
||||
enumSerializerFactoryFunc
|
||||
}
|
||||
return JsInvocation(context.getInnerReference(factoryFunc), enumArgs)
|
||||
} else {
|
||||
// support legacy serializer instantiation by constructor for old runtimes
|
||||
enumArgs
|
||||
}
|
||||
}
|
||||
serializerClass.classId == objectSerializerId -> listOf(
|
||||
JsStringLiteral(kType.serialName()),
|
||||
context.serializerObjectGetter(kType.toClassDescriptor!!)
|
||||
|
||||
+1
-1
@@ -373,7 +373,7 @@ open class SerializerJsTranslator(
|
||||
metadataPlugin: SerializationDescriptorSerializerPlugin?
|
||||
) {
|
||||
val serializableDesc = getSerializableClassDescriptorBySerializer(descriptor) ?: return
|
||||
if (serializableDesc.isInternallySerializableEnum()) {
|
||||
if (serializableDesc.isEnumWithLegacyGeneratedSerializer()) {
|
||||
SerializerForEnumsTranslator(descriptor, translator, context).generate()
|
||||
} else {
|
||||
SerializerJsTranslator(descriptor, translator, context, metadataPlugin).generate()
|
||||
|
||||
+132
-25
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||
import org.jetbrains.kotlin.load.kotlin.internalName
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
@@ -38,7 +39,10 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENUMS_FILE
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.KSERIALIZER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.PLUGIN_EXCEPTIONS_FILE
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
||||
@@ -68,7 +72,9 @@ internal val kOutputType = Type.getObjectType("kotlinx/serialization/encoding/$S
|
||||
internal val encoderType = Type.getObjectType("kotlinx/serialization/encoding/$ENCODER_CLASS")
|
||||
internal val decoderType = Type.getObjectType("kotlinx/serialization/encoding/$DECODER_CLASS")
|
||||
internal val kInputType = Type.getObjectType("kotlinx/serialization/encoding/$STRUCTURE_DECODER_CLASS")
|
||||
|
||||
internal val pluginUtilsType = Type.getObjectType("kotlinx/serialization/internal/${PLUGIN_EXCEPTIONS_FILE}Kt")
|
||||
internal val enumFactoriesType = Type.getObjectType("kotlinx/serialization/internal/${ENUMS_FILE}Kt")
|
||||
|
||||
internal val jvmLambdaType = Type.getObjectType("kotlin/jvm/internal/Lambda")
|
||||
internal val kotlinLazyType = Type.getObjectType("kotlin/Lazy")
|
||||
@@ -84,6 +90,12 @@ internal val serializationExceptionName = "kotlinx/serialization/$SERIAL_EXC"
|
||||
internal val serializationExceptionMissingFieldName = "kotlinx/serialization/$MISSING_FIELD_EXC"
|
||||
internal val serializationExceptionUnknownIndexName = "kotlinx/serialization/$UNKNOWN_FIELD_EXC"
|
||||
|
||||
private val annotationType = Type.getObjectType("java/lang/annotation/Annotation")
|
||||
private val annotationArrayType = Type.getObjectType("[${annotationType.descriptor}")
|
||||
private val doubleAnnotationArrayType = Type.getObjectType("[${annotationArrayType.descriptor}")
|
||||
private val stringType = AsmTypes.JAVA_STRING_TYPE
|
||||
private val stringArrayType = Type.getObjectType("[${stringType.descriptor}")
|
||||
|
||||
internal val descriptorGetterName = JvmAbi.getterName(SERIAL_DESC_FIELD)
|
||||
internal val getLazyValueName = JvmAbi.getterName("value")
|
||||
|
||||
@@ -114,8 +126,8 @@ fun InstructionAdapter.genKOutputMethodCall(
|
||||
) {
|
||||
val propertyType = classCodegen.typeMapper.mapType(property.type)
|
||||
val sti = generator.getSerialTypeInfo(property, propertyType)
|
||||
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti, generator)
|
||||
else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar, generator)
|
||||
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(expressionCodegen, classCodegen, sti, generator)
|
||||
else stackValueSerializerInstanceFromClass(expressionCodegen, classCodegen, sti, fromClassStartVar, generator)
|
||||
val actualType = ImplementationBodyCodegen.genPropertyOnStack(
|
||||
this,
|
||||
expressionCodegen.context,
|
||||
@@ -179,14 +191,16 @@ internal val contextSerializerId = ClassId(packageFqName, Name.identifier(Specia
|
||||
|
||||
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(
|
||||
codegen: ClassBodyCodegen,
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
classCodegen: ClassBodyCodegen,
|
||||
sti: JVMSerialTypeInfo,
|
||||
varIndexStart: Int,
|
||||
serializerCodegen: AbstractSerialGenerator
|
||||
): Boolean {
|
||||
val serializer = sti.serializer
|
||||
return serializerCodegen.stackValueSerializerInstance(
|
||||
codegen,
|
||||
expressionCodegen,
|
||||
classCodegen,
|
||||
sti.property.module,
|
||||
sti.property.type,
|
||||
serializer,
|
||||
@@ -198,6 +212,7 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(
|
||||
}
|
||||
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializerWithoutSti(
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
codegen: ClassBodyCodegen,
|
||||
property: SerializableProperty,
|
||||
serializerCodegen: AbstractSerialGenerator
|
||||
@@ -210,6 +225,7 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializerWithou
|
||||
property.descriptor.findPsi()
|
||||
) else null
|
||||
return serializerCodegen.stackValueSerializerInstance(
|
||||
expressionCodegen,
|
||||
codegen,
|
||||
property.module,
|
||||
property.type,
|
||||
@@ -222,9 +238,14 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializerWithou
|
||||
}.also { if (it && property.type.isMarkedNullable) wrapStackValueIntoNullableSerializer() }
|
||||
}
|
||||
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, serializerCodegen: AbstractSerialGenerator): Boolean {
|
||||
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
codegen: ClassBodyCodegen,
|
||||
sti: JVMSerialTypeInfo,
|
||||
serializerCodegen: AbstractSerialGenerator
|
||||
): Boolean {
|
||||
return serializerCodegen.stackValueSerializerInstance(
|
||||
codegen, sti.property.module, sti.property.type,
|
||||
expressionCodegen, codegen, sti.property.module, sti.property.type,
|
||||
sti.serializer, this, sti.property.genericIndex
|
||||
) { idx, _ ->
|
||||
load(0, kSerializerType)
|
||||
@@ -234,7 +255,7 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codeg
|
||||
|
||||
// returns false is cannot not use serializer
|
||||
// use iv == null to check only (do not emit serializer onto stack)
|
||||
internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
|
||||
internal fun AbstractSerialGenerator.stackValueSerializerInstance(expressionCodegen: ExpressionCodegen, classCodegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
|
||||
iv: InstructionAdapter?,
|
||||
genericIndex: Int? = null,
|
||||
genericSerializerFieldGetter: (InstructionAdapter.(Int, KotlinType) -> Unit)? = null
|
||||
@@ -248,7 +269,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
if (serializer.kind == ClassKind.OBJECT) {
|
||||
// singleton serializer -- just get it
|
||||
if (iv != null)
|
||||
StackValue.singleton(serializer, codegen.typeMapper).put(kSerializerType, iv)
|
||||
StackValue.singleton(serializer, classCodegen.typeMapper).put(kSerializerType, iv)
|
||||
return true
|
||||
}
|
||||
// serializer is not singleton object and shall be instantiated
|
||||
@@ -256,12 +277,13 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
// bail out from stackValueSerializerInstance if any type argument is not serializable
|
||||
val argType = projection.type
|
||||
val argSerializer = if (argType.isTypeParameter()) null else {
|
||||
findTypeSerializerOrContext(module, argType, sourceElement = codegen.descriptor.findPsi())
|
||||
findTypeSerializerOrContext(module, argType, sourceElement = classCodegen.descriptor.findPsi())
|
||||
?: return false
|
||||
}
|
||||
// check if it can be properly serialized with its args recursively
|
||||
if (!stackValueSerializerInstance(
|
||||
codegen,
|
||||
expressionCodegen,
|
||||
classCodegen,
|
||||
module,
|
||||
argType,
|
||||
argSerializer,
|
||||
@@ -275,7 +297,65 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
}
|
||||
// new serializer if needed
|
||||
iv?.apply {
|
||||
val serializerType = codegen.typeMapper.mapClass(serializer)
|
||||
val serializerType = classCodegen.typeMapper.mapClass(serializer)
|
||||
val classDescriptor = kType.toClassDescriptor!!
|
||||
if (serializer.classId == enumSerializerId && !classDescriptor.useGeneratedEnumSerializer) {
|
||||
// runtime contains enum serializer factory functions
|
||||
val javaEnumArray = Type.getType("[Ljava/lang/Enum;")
|
||||
val enumJavaType = classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
|
||||
val serialName = classDescriptor.serialName()
|
||||
|
||||
if (classDescriptor.isEnumWithSerialInfoAnnotation()) {
|
||||
aconst(serialName)
|
||||
invokestatic(enumJavaType.internalName, "values", "()[${enumJavaType.descriptor}", false)
|
||||
checkcast(javaEnumArray)
|
||||
|
||||
val entries = classDescriptor.enumEntries()
|
||||
fillArray(stringType, entries) { _, entry ->
|
||||
entry.annotations.serialNameValue.let {
|
||||
if (it == null) {
|
||||
aconst(null)
|
||||
} else {
|
||||
aconst(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
checkcast(stringArrayType)
|
||||
|
||||
fillArray(annotationArrayType, entries) { _, entry ->
|
||||
val annotations = entry.annotationsWithArguments()
|
||||
if (annotations.isEmpty()) {
|
||||
aconst(null)
|
||||
} else {
|
||||
fillArray(annotationType, annotations) { _, annotation ->
|
||||
val (annotationClass, args, consParams) = annotation
|
||||
expressionCodegen.generateSyntheticAnnotationOnStack(annotationClass, args, consParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
checkcast(doubleAnnotationArrayType)
|
||||
|
||||
invokestatic(
|
||||
enumFactoriesType.internalName,
|
||||
MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME.asString(),
|
||||
"(${stringType.descriptor}${javaEnumArray.descriptor}${stringArrayType.descriptor}${doubleAnnotationArrayType.descriptor})${kSerializerType.descriptor}",
|
||||
false
|
||||
)
|
||||
} else {
|
||||
aconst(serialName)
|
||||
invokestatic(enumJavaType.internalName, "values", "()[${enumJavaType.descriptor}", false)
|
||||
checkcast(javaEnumArray)
|
||||
|
||||
invokestatic(
|
||||
enumFactoriesType.internalName,
|
||||
ENUM_SERIALIZER_FACTORY_FUNC_NAME.asString(),
|
||||
"(${stringType.descriptor}${javaEnumArray.descriptor})${kSerializerType.descriptor}",
|
||||
false
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// todo: support static factory methods for serializers for shorter bytecode
|
||||
anew(serializerType)
|
||||
dup()
|
||||
@@ -286,7 +366,8 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
val (argType, argSerializer) = typeArgument
|
||||
assert(
|
||||
stackValueSerializerInstance(
|
||||
codegen,
|
||||
expressionCodegen,
|
||||
classCodegen,
|
||||
module,
|
||||
argType,
|
||||
argSerializer,
|
||||
@@ -303,9 +384,10 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
val serialName = kType.serialName()
|
||||
when (serializer.classId) {
|
||||
enumSerializerId -> {
|
||||
// support legacy serializer instantiation by constructor for old runtimes
|
||||
aconst(serialName)
|
||||
signature.append("Ljava/lang/String;")
|
||||
val enumJavaType = codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
|
||||
val enumJavaType = classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT)
|
||||
val javaEnumArray = Type.getType("[Ljava/lang/Enum;")
|
||||
invokestatic(enumJavaType.internalName, "values","()[${enumJavaType.descriptor}", false)
|
||||
checkcast(javaEnumArray)
|
||||
@@ -314,7 +396,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
contextSerializerId, polymorphicSerializerId -> {
|
||||
// a special way to instantiate enum -- need a enum KClass reference
|
||||
// GENERIC_ARGUMENT forces boxing in order to obtain KClass
|
||||
aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
aconst(classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
AsmUtil.wrapJavaClassIntoKClass(this)
|
||||
signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
|
||||
if (serializer.classId == contextSerializerId && serializer.constructors.any { it.valueParameters.size == 3 }) {
|
||||
@@ -334,7 +416,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
}
|
||||
referenceArraySerializerId -> {
|
||||
// a special way to instantiate reference array serializer -- need an element KClass reference
|
||||
aconst(codegen.typeMapper.mapType(kType.arguments[0].type, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
aconst(classCodegen.typeMapper.mapType(kType.arguments[0].type, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
AsmUtil.wrapJavaClassIntoKClass(this)
|
||||
signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
|
||||
// Reference array serializer still needs serializer for its argument type
|
||||
@@ -343,13 +425,13 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
sealedSerializerId -> {
|
||||
aconst(serialName)
|
||||
signature.append("Ljava/lang/String;")
|
||||
aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
aconst(classCodegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
AsmUtil.wrapJavaClassIntoKClass(this)
|
||||
signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
|
||||
val (subClasses, subSerializers) = allSealedSerializableSubclassesFor(kType.toClassDescriptor!!, module)
|
||||
// KClasses vararg
|
||||
fillArray(AsmTypes.K_CLASS_TYPE, subClasses) { _, type ->
|
||||
aconst(codegen.typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
aconst(classCodegen.typeMapper.mapType(type, null, TypeMappingMode.GENERIC_ARGUMENT))
|
||||
AsmUtil.wrapJavaClassIntoKClass(this)
|
||||
}
|
||||
signature.append(AsmTypes.K_CLASS_ARRAY_TYPE.descriptor)
|
||||
@@ -358,7 +440,8 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
val (argType, argSerializer) = subClasses[i] to serializer
|
||||
assert(
|
||||
stackValueSerializerInstance(
|
||||
codegen,
|
||||
expressionCodegen,
|
||||
classCodegen,
|
||||
module,
|
||||
argType,
|
||||
argSerializer,
|
||||
@@ -368,7 +451,8 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
// if we encountered generic type parameter in one of subclasses of sealed class, use polymorphism from upper bound
|
||||
assert(
|
||||
stackValueSerializerInstance(
|
||||
codegen,
|
||||
expressionCodegen,
|
||||
classCodegen,
|
||||
module,
|
||||
(genericType.constructor.declarationDescriptor as TypeParameterDescriptor).representativeUpperBound,
|
||||
module.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer),
|
||||
@@ -384,7 +468,7 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
objectSerializerId -> {
|
||||
aconst(serialName)
|
||||
signature.append("Ljava/lang/String;")
|
||||
StackValue.singleton(kType.toClassDescriptor!!, codegen.typeMapper).put(Type.getType("Ljava/lang/Object;"), iv)
|
||||
StackValue.singleton(kType.toClassDescriptor!!, classCodegen.typeMapper).put(Type.getType("Ljava/lang/Object;"), iv)
|
||||
signature.append("Ljava/lang/Object;")
|
||||
}
|
||||
// all serializers get arguments with serializers of their generic types
|
||||
@@ -397,6 +481,29 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
|
||||
return true
|
||||
}
|
||||
|
||||
internal fun ExpressionCodegen.generateSyntheticAnnotationOnStack(
|
||||
annotationClass: ClassDescriptor,
|
||||
args: List<ValueArgument>,
|
||||
ctorParams: List<ValueParameterDescriptor>
|
||||
) {
|
||||
val implType = typeMapper.mapType(annotationClass).internalName + "\$" + SerialEntityNames.IMPL_NAME.identifier
|
||||
with(v) {
|
||||
// new Annotation$Impl(...)
|
||||
anew(Type.getObjectType(implType))
|
||||
dup()
|
||||
val sb = StringBuilder("(")
|
||||
for (i in ctorParams.indices) {
|
||||
val decl = args[i]
|
||||
val desc = ctorParams[i]
|
||||
val valAsmType = typeMapper.mapType(desc.type)
|
||||
this@generateSyntheticAnnotationOnStack.gen(decl.getArgumentExpression(), valAsmType)
|
||||
sb.append(valAsmType.descriptor)
|
||||
}
|
||||
sb.append(")V")
|
||||
invokespecial(implType, "<init>", sb.toString(), false)
|
||||
}
|
||||
}
|
||||
|
||||
fun InstructionAdapter.wrapStackValueIntoNullableSerializer() =
|
||||
invokestatic(
|
||||
"kotlinx/serialization/builtins/BuiltinSerializersKt", "getNullable",
|
||||
@@ -406,10 +513,10 @@ fun InstructionAdapter.wrapStackValueIntoNullableSerializer() =
|
||||
fun <T> InstructionAdapter.fillArray(type: Type, args: List<T>, onEach: (Int, T) -> Unit) {
|
||||
iconst(args.size)
|
||||
newarray(type)
|
||||
args.forEachIndexed { i, serializer ->
|
||||
args.forEachIndexed { i, arg ->
|
||||
dup()
|
||||
iconst(i)
|
||||
onEach(i, serializer)
|
||||
onEach(i, arg)
|
||||
astore(type)
|
||||
}
|
||||
}
|
||||
@@ -510,7 +617,7 @@ internal fun createSingletonLambda(
|
||||
lambdaName: String,
|
||||
outerClassCodegen: ImplementationBodyCodegen,
|
||||
resultSimpleType: SimpleType,
|
||||
block: InstructionAdapter.(ImplementationBodyCodegen) -> Unit
|
||||
block: InstructionAdapter.(ImplementationBodyCodegen, ExpressionCodegen) -> Unit
|
||||
): Type {
|
||||
val lambdaType = Type.getObjectType("${outerClassCodegen.className}\$$lambdaName")
|
||||
|
||||
@@ -631,8 +738,8 @@ internal fun createSingletonLambda(
|
||||
DescriptorVisibilities.PUBLIC
|
||||
)
|
||||
|
||||
lambdaCodegen.generateMethod(invokeFunction) { _, _ ->
|
||||
block(lambdaCodegen)
|
||||
lambdaCodegen.generateMethod(invokeFunction) { _, expressionCodegen ->
|
||||
block(lambdaCodegen, expressionCodegen)
|
||||
}
|
||||
|
||||
val bridgeInvokeFunction = SimpleFunctionDescriptorImpl.create(
|
||||
|
||||
+9
-1
@@ -103,7 +103,15 @@ class SerializableCodegenImpl(
|
||||
superTypeArguments.forEach {
|
||||
val genericIdx = serializableDescriptor.defaultType.arguments.indexOf(it).let { if (it == -1) null else it }
|
||||
val serial = findTypeSerializerOrContext(serializableDescriptor.module, it.type)
|
||||
stackValueSerializerInstance(classCodegen, serializableDescriptor.module, it.type, serial, this, genericIdx) { i, _ ->
|
||||
stackValueSerializerInstance(
|
||||
exprCodegen,
|
||||
classCodegen,
|
||||
serializableDescriptor.module,
|
||||
it.type,
|
||||
serial,
|
||||
this,
|
||||
genericIdx
|
||||
) { i, _ ->
|
||||
load(offsetI + i, kSerializerType)
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -57,7 +57,11 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
|
||||
|
||||
// create singleton lambda class
|
||||
val lambdaType =
|
||||
createSingletonLambda("serializer\$1", classCodegen, companionDescriptor.getKSerializer().defaultType) { lambdaCodegen ->
|
||||
createSingletonLambda(
|
||||
"serializer\$1",
|
||||
classCodegen,
|
||||
companionDescriptor.getKSerializer().defaultType
|
||||
) { lambdaCodegen, expressionCodegen ->
|
||||
val serializerDescriptor = requireNotNull(
|
||||
findTypeSerializer(
|
||||
serializableDescriptor.module,
|
||||
@@ -65,6 +69,7 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
|
||||
)
|
||||
)
|
||||
stackValueSerializerInstance(
|
||||
expressionCodegen,
|
||||
lambdaCodegen,
|
||||
serializableDescriptor.module,
|
||||
serializableDescriptor.defaultType,
|
||||
@@ -106,8 +111,9 @@ class SerializableCompanionCodegenImpl(private val classCodegen: ImplementationB
|
||||
serializableDescriptor.toSimpleType()
|
||||
)
|
||||
)
|
||||
classCodegen.generateMethod(methodDescriptor) { _, _ ->
|
||||
classCodegen.generateMethod(methodDescriptor) { _, expressionCodegen ->
|
||||
stackValueSerializerInstance(
|
||||
expressionCodegen,
|
||||
classCodegen,
|
||||
serializableDescriptor.module,
|
||||
serializableDescriptor.defaultType,
|
||||
|
||||
+7
-30
@@ -8,7 +8,6 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
|
||||
@@ -37,7 +36,7 @@ open class SerializerCodegenImpl(
|
||||
companion object {
|
||||
fun generateSerializerExtensions(codegen: ImplementationBodyCodegen, metadataPlugin: SerializationDescriptorSerializerPlugin?) {
|
||||
val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return
|
||||
val serializerCodegen = if (serializableClass.isInternallySerializableEnum()) {
|
||||
val serializerCodegen = if (serializableClass.isEnumWithLegacyGeneratedSerializer()) {
|
||||
SerializerForEnumsCodegen(codegen, serializableClass)
|
||||
} else {
|
||||
SerializerCodegenImpl(codegen, serializableClass, metadataPlugin)
|
||||
@@ -144,30 +143,6 @@ open class SerializerCodegenImpl(
|
||||
expr.generateSerialDescriptor(0, true)
|
||||
}
|
||||
|
||||
private fun ExpressionCodegen.generateSyntheticAnnotationOnStack(
|
||||
annotationClass: ClassDescriptor,
|
||||
args: List<ValueArgument>,
|
||||
ctorParams: List<ValueParameterDescriptor>
|
||||
) {
|
||||
val implType =
|
||||
codegen.typeMapper.mapType(annotationClass).internalName + "\$" + SerialEntityNames.IMPL_NAME.identifier
|
||||
with(v) {
|
||||
// new Annotation$Impl(...)
|
||||
anew(Type.getObjectType(implType))
|
||||
dup()
|
||||
val sb = StringBuilder("(")
|
||||
for (i in ctorParams.indices) {
|
||||
val decl = args[i]
|
||||
val desc = ctorParams[i]
|
||||
val valAsmType = codegen.typeMapper.mapType(desc.type)
|
||||
this@generateSyntheticAnnotationOnStack.gen(decl.getArgumentExpression(), valAsmType)
|
||||
sb.append(valAsmType.descriptor)
|
||||
}
|
||||
sb.append(")V")
|
||||
invokespecial(implType, "<init>", sb.toString(), false)
|
||||
}
|
||||
}
|
||||
|
||||
// use null to put value on stack, use number to store it to var
|
||||
protected fun InstructionAdapter.stackSerialClassDesc(classDescVar: Int?) {
|
||||
if (staticDescriptor)
|
||||
@@ -192,7 +167,7 @@ open class SerializerCodegenImpl(
|
||||
}
|
||||
|
||||
override fun generateChildSerializersGetter(function: FunctionDescriptor) {
|
||||
codegen.generateMethod(function) { _, _ ->
|
||||
codegen.generateMethod(function) { _, expressionCodegen ->
|
||||
val size = serializableProperties.size
|
||||
iconst(size)
|
||||
newarray(kSerializerType)
|
||||
@@ -202,6 +177,7 @@ open class SerializerCodegenImpl(
|
||||
val prop = serializableProperties[i]
|
||||
assert(
|
||||
stackValueSerializerInstanceFromSerializerWithoutSti(
|
||||
expressionCodegen,
|
||||
codegen,
|
||||
prop,
|
||||
this@SerializerCodegenImpl
|
||||
@@ -335,7 +311,7 @@ open class SerializerCodegenImpl(
|
||||
propVar = propsStartVar
|
||||
for ((index, property) in serializableProperties.withIndex()) {
|
||||
val propertyType = codegen.typeMapper.mapType(property.type)
|
||||
callReadProperty(property, propertyType, index, inputVar, descVar, propVar)
|
||||
callReadProperty(expressionCodegen, property, propertyType, index, inputVar, descVar, propVar)
|
||||
propVar += propertyType.size
|
||||
}
|
||||
// set all bit masks to true
|
||||
@@ -373,7 +349,7 @@ open class SerializerCodegenImpl(
|
||||
if (!property.transient) {
|
||||
// labelI:
|
||||
visitLabel(labels[labelNum + 1])
|
||||
callReadProperty(property, propertyType, index, inputVar, descVar, propVar)
|
||||
callReadProperty(expressionCodegen, property, propertyType, index, inputVar, descVar, propVar)
|
||||
|
||||
// mark read bit in mask
|
||||
// bitMask = bitMask | 1 << index
|
||||
@@ -449,6 +425,7 @@ open class SerializerCodegenImpl(
|
||||
}
|
||||
|
||||
private fun InstructionAdapter.callReadProperty(
|
||||
expressionCodegen: ExpressionCodegen,
|
||||
property: SerializableProperty,
|
||||
propertyType: Type,
|
||||
index: Int,
|
||||
@@ -462,7 +439,7 @@ open class SerializerCodegenImpl(
|
||||
iconst(index)
|
||||
|
||||
val sti = getSerialTypeInfo(property, propertyType)
|
||||
val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti, this@SerializerCodegenImpl)
|
||||
val useSerializer = stackValueSerializerInstanceFromSerializer(expressionCodegen, codegen, sti, this@SerializerCodegenImpl)
|
||||
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
|
||||
if (unknownSer) {
|
||||
aconst(codegen.typeMapper.mapType(property.type))
|
||||
|
||||
+10
-3
@@ -36,6 +36,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
internal val SERIALIZABLE_PROPERTIES: WritableSlice<ClassDescriptor, SerializableProperties> = Slices.createSimpleSlice()
|
||||
|
||||
open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
||||
private var useLegacyEnumSerializerCached: Boolean? = null
|
||||
|
||||
final override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (descriptor !is ClassDescriptor) return
|
||||
|
||||
@@ -139,8 +141,13 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.useLegacyGeneratedEnumSerializer(): Boolean {
|
||||
return useLegacyEnumSerializerCached ?: useGeneratedEnumSerializer.also { useLegacyEnumSerializerCached = it }
|
||||
}
|
||||
|
||||
private fun canBeSerializedInternally(descriptor: ClassDescriptor, declaration: KtDeclaration, trace: BindingTrace): Boolean {
|
||||
if (descriptor.isSerializableEnumWithMissingSerializer()) {
|
||||
// if enum has meta or SerialInfo annotation on a class or entries and used plugin-generated serializer
|
||||
if (descriptor.isSerializableEnumWithMissingSerializer() && descriptor.useLegacyGeneratedEnumSerializer()) {
|
||||
val declarationToReport = declaration.modifierList ?: declaration
|
||||
trace.report(SerializationErrors.EXPLICIT_SERIALIZABLE_IS_REQUIRED.on(declarationToReport))
|
||||
return false
|
||||
@@ -187,7 +194,7 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
// check that we can instantiate supertype
|
||||
if (!descriptor.isSerializableEnum()) { // enums are inherited from java.lang.Enum and can't be inherited from other classes
|
||||
if (descriptor.kind != ClassKind.ENUM_CLASS) { // enums are inherited from java.lang.Enum and can't be inherited from other classes
|
||||
val superClass = descriptor.getSuperClassOrAny()
|
||||
if (!superClass.isInternalSerializable && superClass.constructors.singleOrNull { it.valueParameters.size == 0 } == null) {
|
||||
trace.reportOnSerializableOrMetaAnnotation(descriptor, SerializationErrors.NON_SERIALIZABLE_PARENT_MUST_HAVE_NOARG_CTOR)
|
||||
@@ -429,4 +436,4 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.serializableAnnotationIsUseless: Boolean
|
||||
get() = hasSerializableOrMetaAnnotationWithoutArgs && !isInternalSerializable && !hasCompanionObjectAsSerializer && !isSerializableEnum() && !isSealedSerializableInterface
|
||||
get() = hasSerializableOrMetaAnnotationWithoutArgs && !isInternalSerializable && !hasCompanionObjectAsSerializer && kind != ClassKind.ENUM_CLASS && !isSealedSerializableInterface
|
||||
|
||||
+20
-1
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.inheritableSerialInfoFqName
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.metaSerializableAnnotationFqName
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName
|
||||
@@ -124,11 +126,20 @@ internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal check
|
||||
|
||||
internal fun ClassDescriptor.isSerializableEnum(): Boolean = kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotation
|
||||
|
||||
internal fun ClassDescriptor.isEnumWithLegacyGeneratedSerializer(): Boolean = isInternallySerializableEnum() && useGeneratedEnumSerializer
|
||||
|
||||
internal fun ClassDescriptor.isInternallySerializableEnum(): Boolean =
|
||||
kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotationWithoutArgs
|
||||
|
||||
internal val ClassDescriptor.shouldHaveGeneratedSerializer: Boolean
|
||||
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN)) || isInternallySerializableEnum()
|
||||
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN))
|
||||
|| isEnumWithLegacyGeneratedSerializer()
|
||||
|
||||
internal val ClassDescriptor.useGeneratedEnumSerializer: Boolean
|
||||
get() {
|
||||
val functions = module.getPackage(SerializationPackages.internalPackageFqName).memberScope.getFunctionNames()
|
||||
return !functions.contains(ENUM_SERIALIZER_FACTORY_FUNC_NAME) || !functions.contains(MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME)
|
||||
}
|
||||
|
||||
internal fun ClassDescriptor.enumEntries(): List<ClassDescriptor> {
|
||||
check(this.kind == ClassKind.ENUM_CLASS)
|
||||
@@ -138,6 +149,13 @@ internal fun ClassDescriptor.enumEntries(): List<ClassDescriptor> {
|
||||
.toList()
|
||||
}
|
||||
|
||||
// check enum or its elements has any SerialInfo annotation
|
||||
internal fun ClassDescriptor.isEnumWithSerialInfoAnnotation(): Boolean {
|
||||
if (kind != ClassKind.ENUM_CLASS) return false
|
||||
if (annotations.hasAnySerialAnnotation) return true
|
||||
return enumEntries().any { (it.annotations.hasAnySerialAnnotation) }
|
||||
}
|
||||
|
||||
internal val Annotations.hasAnySerialAnnotation: Boolean
|
||||
get() = serialNameValue != null || any { it.annotationClass?.isSerialInfoAnnotation == true }
|
||||
|
||||
@@ -242,6 +260,7 @@ internal fun ClassDescriptor.needSerializerFactory(): Boolean {
|
||||
if (!(this.platform?.isNative() == true || this.platform.isJs())) return false
|
||||
val serializableClass = getSerializableClassDescriptorByCompanion(this) ?: return false
|
||||
if (serializableClass.isSerializableObject) return true
|
||||
if (serializableClass.isSerializableEnum()) return true
|
||||
if (serializableClass.isAbstractOrSealedSerializableClass()) return true
|
||||
if (serializableClass.isSealedSerializableInterface) return true
|
||||
if (serializableClass.declaredTypeParameters.isEmpty()) return false
|
||||
|
||||
+6
@@ -78,6 +78,7 @@ object SerialEntityNames {
|
||||
const val SERIAL_DESCRIPTOR_FOR_INLINE = "InlineClassDescriptor"
|
||||
|
||||
const val PLUGIN_EXCEPTIONS_FILE = "PluginExceptions"
|
||||
const val ENUMS_FILE = "Enums"
|
||||
|
||||
//exceptions
|
||||
const val SERIAL_EXC = "SerializationException"
|
||||
@@ -94,11 +95,16 @@ object SerialEntityNames {
|
||||
val SERIALIZER_PROVIDER_NAME = Name.identifier("serializer")
|
||||
val SINGLE_MASK_FIELD_MISSING_FUNC_NAME = Name.identifier("throwMissingFieldException")
|
||||
val ARRAY_MASK_FIELD_MISSING_FUNC_NAME = Name.identifier("throwArrayMissingFieldException")
|
||||
val ENUM_SERIALIZER_FACTORY_FUNC_NAME = Name.identifier("createSimpleEnumSerializer")
|
||||
val MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME = Name.identifier("createMarkedEnumSerializer")
|
||||
val SINGLE_MASK_FIELD_MISSING_FUNC_FQ = SerializationPackages.internalPackageFqName.child(SINGLE_MASK_FIELD_MISSING_FUNC_NAME)
|
||||
val ARRAY_MASK_FIELD_MISSING_FUNC_FQ = SerializationPackages.internalPackageFqName.child(ARRAY_MASK_FIELD_MISSING_FUNC_NAME)
|
||||
val CACHED_SERIALIZER_PROPERTY_NAME = Name.identifier(CACHED_SERIALIZER_PROPERTY)
|
||||
val CACHED_DESCRIPTOR_FIELD_NAME = Name.identifier(CACHED_DESCRIPTOR_FIELD)
|
||||
|
||||
val ENUM_SERIALIZER_FACTORY_FUNC_FQ = SerializationPackages.internalPackageFqName.child(ENUM_SERIALIZER_FACTORY_FUNC_NAME)
|
||||
val MARKED_ENUM_SERIALIZER_FACTORY_FUNC_FQ = SerializationPackages.internalPackageFqName.child(MARKED_ENUM_SERIALIZER_FACTORY_FUNC_NAME)
|
||||
|
||||
// parameters
|
||||
val dummyParamName = Name.identifier("serializationConstructorMarker")
|
||||
internal const val typeArgPrefix = "typeSerial"
|
||||
|
||||
plugins/kotlin-serialization/kotlin-serialization-compiler/testData/diagnostics/SerializableEnums.kt
Vendored
+1
-1
@@ -21,4 +21,4 @@ object EnumSerializer: KSerializer<ExplicitlyMarkedEnumCustom> {
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class EnumUsage(val s: SimpleEnum, val m: MarkedNameEnum, val e: ExplicitlyMarkedEnum)
|
||||
data class EnumUsage(val s: SimpleEnum, val m: MarkedNameEnum, val e: ExplicitlyMarkedEnum)
|
||||
|
||||
Reference in New Issue
Block a user