Add .serializer() to enum companion and object with custom serializer

Fixes Kotlin/kotlinx.serialization#1386
This commit is contained in:
Sergey Shanshin
2021-05-26 16:07:59 +03:00
committed by GitHub
parent f431b4b171
commit 16dbafced1
6 changed files with 21 additions and 17 deletions
@@ -43,7 +43,7 @@ fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module
return null return null
} }
fun KotlinType.isSerializableObject() = fun KotlinType.isGeneratedSerializableObject() =
toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs } == true toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs } == true
@Suppress("FunctionName", "LocalVariableName") @Suppress("FunctionName", "LocalVariableName")
@@ -151,7 +151,7 @@ fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescri
if (userOverride != null) return userOverride.toClassDescriptor if (userOverride != null) return userOverride.toClassDescriptor
if (kType.isTypeParameter()) return null if (kType.isTypeParameter()) return null
if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer) if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer)
if (kType.isSerializableObject()) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.objectSerializer) if (kType.isGeneratedSerializableObject()) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.objectSerializer)
val stdSer = findStandardKotlinTypeSerializer(module, kType) // see if there is a standard serializer val stdSer = findStandardKotlinTypeSerializer(module, kType) // see if there is a standard serializer
?: findEnumTypeSerializer(module, kType) ?: findEnumTypeSerializer(module, kType)
if (stdSer != null) return stdSer if (stdSer != null) return stdSer
@@ -216,7 +216,7 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
val classDescriptor = kType.toClassDescriptor ?: return null val classDescriptor = kType.toClassDescriptor ?: return null
return if (classDescriptor.kind == ClassKind.ENUM_CLASS && !classDescriptor.isSerializableEnum()) return if (classDescriptor.kind == ClassKind.ENUM_CLASS && !classDescriptor.isInternallySerializableEnum())
module.findClassAcrossModuleDependencies(enumSerializerId) module.findClassAcrossModuleDependencies(enumSerializerId)
else null else null
} }
@@ -572,7 +572,7 @@ open class SerializerIrGenerator(
) { ) {
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
val generator = when { val generator = when {
serializableDesc.isSerializableEnum() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator) serializableDesc.isInternallySerializableEnum() -> SerializerForEnumsGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
serializableDesc.isInlineClass() -> SerializerForInlineClassGenerator(irClass, context, bindingContext, serialInfoJvmGenerator) serializableDesc.isInlineClass() -> SerializerForInlineClassGenerator(irClass, context, bindingContext, serialInfoJvmGenerator)
else -> SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator) else -> SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin, serialInfoJvmGenerator)
} }
@@ -373,7 +373,7 @@ open class SerializerJsTranslator(
metadataPlugin: SerializationDescriptorSerializerPlugin? metadataPlugin: SerializationDescriptorSerializerPlugin?
) { ) {
val serializableDesc = getSerializableClassDescriptorBySerializer(descriptor) ?: return val serializableDesc = getSerializableClassDescriptorBySerializer(descriptor) ?: return
if (serializableDesc.isSerializableEnum()) { if (serializableDesc.isInternallySerializableEnum()) {
SerializerForEnumsTranslator(descriptor, translator, context).generate() SerializerForEnumsTranslator(descriptor, translator, context).generate()
} else { } else {
SerializerJsTranslator(descriptor, translator, context, metadataPlugin).generate() SerializerJsTranslator(descriptor, translator, context, metadataPlugin).generate()
@@ -38,7 +38,7 @@ open class SerializerCodegenImpl(
companion object { companion object {
fun generateSerializerExtensions(codegen: ImplementationBodyCodegen, metadataPlugin: SerializationDescriptorSerializerPlugin?) { fun generateSerializerExtensions(codegen: ImplementationBodyCodegen, metadataPlugin: SerializationDescriptorSerializerPlugin?) {
val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return
val serializerCodegen = if (serializableClass.isSerializableEnum()) { val serializerCodegen = if (serializableClass.isInternallySerializableEnum()) {
SerializerForEnumsCodegen(codegen, serializableClass) SerializerForEnumsCodegen(codegen, serializableClass)
} else { } else {
SerializerCodegenImpl(codegen, serializableClass, metadataPlugin) SerializerCodegenImpl(codegen, serializableClass, metadataPlugin)
@@ -97,9 +97,12 @@ val KotlinType?.toClassDescriptor: ClassDescriptor?
} }
internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean
get() = this.isSerializableObject || this.isSerializableEnum() || this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName) get() = this.isSerializableObject || this.isSerializableEnum() || this.kind == ClassKind.CLASS && hasSerializableAnnotation
internal val ClassDescriptor.isSerializableObject: Boolean internal val ClassDescriptor.isSerializableObject: Boolean
get() = kind == ClassKind.OBJECT && hasSerializableAnnotation
internal val ClassDescriptor.isInternallySerializableObject: Boolean
get() = kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs get() = kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs
internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking
@@ -108,14 +111,12 @@ internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal check
return hasSerializableAnnotationWithoutArgs return hasSerializableAnnotationWithoutArgs
} }
internal fun ClassDescriptor.isSerializableEnum(): Boolean { internal fun ClassDescriptor.isSerializableEnum(): Boolean = kind == ClassKind.ENUM_CLASS && hasSerializableAnnotation
if (this.kind != ClassKind.ENUM_CLASS) return false
if (hasSerializableAnnotationWithoutArgs) return true internal fun ClassDescriptor.isInternallySerializableEnum(): Boolean = kind == ClassKind.ENUM_CLASS && hasSerializableAnnotationWithoutArgs
return false
}
internal val ClassDescriptor.shouldHaveGeneratedSerializer: Boolean internal val ClassDescriptor.shouldHaveGeneratedSerializer: Boolean
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN)) || isSerializableEnum() get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN)) || isInternallySerializableEnum()
internal fun ClassDescriptor.enumEntries(): List<ClassDescriptor> { internal fun ClassDescriptor.enumEntries(): List<ClassDescriptor> {
check(this.kind == ClassKind.ENUM_CLASS) check(this.kind == ClassKind.ENUM_CLASS)
@@ -128,9 +129,12 @@ internal fun ClassDescriptor.enumEntries(): List<ClassDescriptor> {
internal val Annotations.hasAnySerialAnnotation: Boolean internal val Annotations.hasAnySerialAnnotation: Boolean
get() = serialNameValue != null || any { it.annotationClass?.isSerialInfoAnnotation == true } get() = serialNameValue != null || any { it.annotationClass?.isSerialInfoAnnotation == true }
private val ClassDescriptor.hasSerializableAnnotation
get() = annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)
internal val ClassDescriptor.hasSerializableAnnotationWithoutArgs: Boolean internal val ClassDescriptor.hasSerializableAnnotationWithoutArgs: Boolean
get() { get() {
if (!annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)) return false if (!hasSerializableAnnotation) return false
// If provided descriptor is lazy, carefully look at psi in order not to trigger full resolve which may be recursive. // If provided descriptor is lazy, carefully look at psi in order not to trigger full resolve which may be recursive.
// Otherwise, this descriptor is deserialized from another module and it is OK to check value right away. // Otherwise, this descriptor is deserialized from another module and it is OK to check value right away.
val psi = findSerializableAnnotationDeclaration() ?: return (serializableWith == null) val psi = findSerializableAnnotationDeclaration() ?: return (serializableWith == null)
@@ -178,7 +182,7 @@ internal val ClassDescriptor?.classSerializer: ClassDescriptor?
} }
internal val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean internal val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean
get() = isSerializableObject || companionObjectDescriptor?.serializerForClass == this.defaultType get() = isInternallySerializableObject || companionObjectDescriptor?.serializerForClass == this.defaultType
// returns only user-overriden Serializer // returns only user-overriden Serializer
internal val KotlinType.overridenSerializer: KotlinType? internal val KotlinType.overridenSerializer: KotlinType?
@@ -68,7 +68,7 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
.let { unsort(serializableClass, it) } .let { unsort(serializableClass, it) }
isExternallySerializable = isExternallySerializable =
serializableClass.isSerializableEnum() || primaryConstructorParameters.size == primaryConstructorProperties.size serializableClass.isInternallySerializableEnum() || primaryConstructorParameters.size == primaryConstructorProperties.size
} }