Correctly determine the type of serializable property
when supertype of serializable class is generic and also serializable, and contains the property with type with its generic parameter. Fixes https://github.com/Kotlin/kotlinx.serialization/issues/1264 #KT-43910 Fixed #KT-49660 Fixed
This commit is contained in:
committed by
Space Team
parent
2ea0cdf46d
commit
2a626b27d3
+43
-16
@@ -10,27 +10,25 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.hasDefaultValue
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.util.properties
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
class IrSerializableProperty(
|
||||
val ir: IrProperty,
|
||||
override val isConstructorParameterWithDefault: Boolean,
|
||||
hasBackingField: Boolean,
|
||||
declaresDefaultValue: Boolean
|
||||
declaresDefaultValue: Boolean,
|
||||
val type: IrSimpleType
|
||||
) : ISerializableProperty {
|
||||
override val name = ir.annotations.serialNameValue ?: ir.name.asString()
|
||||
override val originalDescriptorName: Name = ir.name
|
||||
val type = ir.getter!!.returnType as IrSimpleType
|
||||
val genericIndex = type.genericIndex
|
||||
fun serializableWith(ctx: SerializationBaseContext) = ir.annotations.serializableWith() ?: analyzeSpecialSerializers(ctx, ir.annotations)
|
||||
fun serializableWith(ctx: SerializationBaseContext) =
|
||||
ir.annotations.serializableWith() ?: analyzeSpecialSerializers(ctx, ir.annotations)
|
||||
|
||||
override val optional = !ir.annotations.hasAnnotation(SerializationAnnotations.requiredAnnotationFqName) && declaresDefaultValue
|
||||
override val transient = ir.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName) || !hasBackingField
|
||||
}
|
||||
@@ -42,10 +40,27 @@ class IrSerializableProperties(
|
||||
override val serializableStandaloneProperties: List<IrSerializableProperty>
|
||||
) : ISerializableProperties<IrSerializableProperty>
|
||||
|
||||
/**
|
||||
* typeReplacement should be populated from FakeOverrides and is used when we want to determine the type for property
|
||||
* accounting for generic substitutions performed in subclasses:
|
||||
*
|
||||
* ```
|
||||
* @Serializable
|
||||
* sealed class TypedSealedClass<T>(val a: T) {
|
||||
* @Serializable
|
||||
* data class Child(val y: Int) : TypedSealedClass<String>("10")
|
||||
* }
|
||||
* ```
|
||||
* In this case, serializableProperties for TypedSealedClass is a listOf(IrSerProp(val a: T)),
|
||||
* but for Child is a listOf(IrSerProp(val a: String), IrSerProp(val y: Int)).
|
||||
*
|
||||
* Using this approach, we can correctly deserialize parent's properties in Child.Companion.deserialize()
|
||||
*/
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
internal fun serializablePropertiesForIrBackend(
|
||||
irClass: IrClass,
|
||||
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
|
||||
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null,
|
||||
typeReplacement: Map<IrProperty, IrSimpleType>? = null
|
||||
): IrSerializableProperties {
|
||||
val properties = irClass.properties.toList()
|
||||
val primaryConstructorParams = irClass.primaryConstructor?.valueParameters.orEmpty()
|
||||
@@ -68,14 +83,17 @@ internal fun serializablePropertiesForIrBackend(
|
||||
.map {
|
||||
val isConstructorParameterWithDefault = primaryParamsAsProps[it] ?: false
|
||||
// FIXME: workaround because IrLazyProperty doesn't deserialize information about backing fields. Fallback to descriptor won't work with FIR.
|
||||
val isPropertyFromAnotherModuleDeclaresDefaultValue = it.descriptor is DeserializedPropertyDescriptor && it.descriptor.declaresDefaultValue()
|
||||
val isPropertyWithBackingFieldFromAnotherModule = it.descriptor is DeserializedPropertyDescriptor && (it.descriptor.backingField != null || isPropertyFromAnotherModuleDeclaresDefaultValue)
|
||||
val isPropertyFromAnotherModuleDeclaresDefaultValue =
|
||||
it.descriptor is DeserializedPropertyDescriptor && it.descriptor.declaresDefaultValue()
|
||||
val isPropertyWithBackingFieldFromAnotherModule =
|
||||
it.descriptor is DeserializedPropertyDescriptor && (it.descriptor.backingField != null || isPropertyFromAnotherModuleDeclaresDefaultValue)
|
||||
IrSerializableProperty(
|
||||
it,
|
||||
isConstructorParameterWithDefault,
|
||||
it.backingField != null || isPropertyWithBackingFieldFromAnotherModule,
|
||||
it.backingField?.initializer.let { init -> init != null && !init.expression.isInitializePropertyFromParameter() } || isConstructorParameterWithDefault
|
||||
|| isPropertyFromAnotherModuleDeclaresDefaultValue
|
||||
|| isPropertyFromAnotherModuleDeclaresDefaultValue,
|
||||
typeReplacement?.get(it) ?: it.getter!!.returnType as IrSimpleType
|
||||
)
|
||||
}
|
||||
.filterNot { it.transient }
|
||||
@@ -83,13 +101,22 @@ internal fun serializablePropertiesForIrBackend(
|
||||
|
||||
var serializableProps = run {
|
||||
val supers = irClass.getSuperClassNotAny()
|
||||
if (supers == null || !supers.isInternalSerializable)
|
||||
if (supers == null || !supers.isInternalSerializable) {
|
||||
primaryCtorSerializableProps + bodySerializableProps
|
||||
else
|
||||
} else {
|
||||
val originalToTypeFromFO = typeReplacement ?: buildMap<IrProperty, IrSimpleType> {
|
||||
irClass.properties.filter { it.isFakeOverride }.forEach { prop ->
|
||||
val orig = prop.resolveFakeOverride()
|
||||
val type = prop.getter?.returnType as? IrSimpleType
|
||||
if (orig != null && type != null) put(orig, type)
|
||||
}
|
||||
}
|
||||
serializablePropertiesForIrBackend(
|
||||
supers,
|
||||
serializationDescriptorSerializer
|
||||
serializationDescriptorSerializer,
|
||||
originalToTypeFromFO
|
||||
).serializableProperties + primaryCtorSerializableProps + bodySerializableProps
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: since descriptor from FIR does not have classProto in it(?), this line won't do anything
|
||||
@@ -99,4 +126,4 @@ internal fun serializablePropertiesForIrBackend(
|
||||
irClass.isInternallySerializableEnum() || primaryConstructorParams.size == primaryParamsAsProps.size
|
||||
|
||||
return IrSerializableProperties(serializableProps, isExternallySerializable, primaryCtorSerializableProps, bodySerializableProps)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user