Adapt IR serialization plugin so it works both with FIR and old FE
(except some places that are not currently supported by FIR part of plugin)
This commit is contained in:
+4
-1
@@ -264,6 +264,7 @@ internal fun IrCall.getCorrespondingProperty(): IrProperty =
|
||||
symbol.owner.correspondingPropertySymbol?.owner
|
||||
?: error("Atomic property accessor ${this.render()} expected to have non-null correspondingPropertySymbol")
|
||||
|
||||
@OptIn(FirIncompatiblePluginAPI::class)
|
||||
internal fun IrPluginContext.referencePackageFunction(
|
||||
packageName: String,
|
||||
name: String,
|
||||
@@ -274,6 +275,7 @@ internal fun IrPluginContext.referencePackageFunction(
|
||||
error("Exception while looking for the function `$name` in package `$packageName`: ${e.message}")
|
||||
}
|
||||
|
||||
@OptIn(FirIncompatiblePluginAPI::class)
|
||||
internal fun IrPluginContext.referenceFunction(classSymbol: IrClassSymbol, functionName: String): IrSimpleFunctionSymbol {
|
||||
val functionId = FqName("$KOTLIN.${classSymbol.owner.name}.$functionName")
|
||||
return try {
|
||||
@@ -283,18 +285,19 @@ internal fun IrPluginContext.referenceFunction(classSymbol: IrClassSymbol, funct
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(FirIncompatiblePluginAPI::class)
|
||||
private fun IrPluginContext.referenceArrayClass(irType: IrSimpleType): IrClassSymbol {
|
||||
val jsArrayName = irType.getArrayClassFqName()
|
||||
return referenceClass(jsArrayName) ?: error("Array class $jsArrayName was not found in the context")
|
||||
}
|
||||
|
||||
@OptIn(FirIncompatiblePluginAPI::class)
|
||||
internal fun IrPluginContext.getArrayConstructorSymbol(
|
||||
irType: IrSimpleType,
|
||||
predicate: (IrConstructorSymbol) -> Boolean = { true }
|
||||
): IrConstructorSymbol {
|
||||
val jsArrayName = irType.getArrayClassFqName()
|
||||
return try {
|
||||
@Suppress("DEPRECATION") // caution: referenceConstructors(fqName) doesn't work with FIR
|
||||
referenceConstructors(jsArrayName).single(predicate)
|
||||
} catch (e: RuntimeException) {
|
||||
error("Array constructor $jsArrayName matching the predicate was not found in the context")
|
||||
|
||||
+41
@@ -5,9 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.fileParent
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||
import org.jetbrains.kotlin.ir.util.findAnnotation
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -21,6 +31,37 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
|
||||
abstract class AbstractIrGenerator(private val currentClass: IrClass) {
|
||||
private fun getClassListFromFileAnnotation(annotationFqName: FqName): List<IrClassSymbol> {
|
||||
val annotation = currentClass.fileParent.annotations.findAnnotation(annotationFqName) ?: return emptyList()
|
||||
val vararg = annotation.getValueArgument(0) as? IrVararg ?: return emptyList()
|
||||
return vararg.elements
|
||||
.mapNotNull { (it as? IrClassReference)?.symbol as? IrClassSymbol}
|
||||
}
|
||||
|
||||
val contextualKClassListInCurrentFile: Set<IrClassSymbol> by lazy {
|
||||
getClassListFromFileAnnotation(
|
||||
SerializationAnnotations.contextualFqName,
|
||||
).plus(
|
||||
getClassListFromFileAnnotation(
|
||||
SerializationAnnotations.contextualOnFileFqName,
|
||||
)
|
||||
).toSet()
|
||||
}
|
||||
|
||||
val additionalSerializersInScopeOfCurrentFile: Map<Pair<IrClassSymbol, Boolean>, IrClassSymbol> by lazy {
|
||||
getClassListFromFileAnnotation(SerializationAnnotations.additionalSerializersFqName,)
|
||||
.associateBy(
|
||||
{ serializerSymbol ->
|
||||
val kotlinType = (serializerSymbol.owner.superTypes.find(::isKSerializer) as? IrSimpleType)?.arguments?.firstOrNull()?.typeOrNull
|
||||
val classSymbol = kotlinType?.classOrNull
|
||||
?: throw AssertionError("Argument for ${SerializationAnnotations.additionalSerializersFqName} does not implement KSerializer or does not provide serializer for concrete type")
|
||||
classSymbol to kotlinType.isNullable()
|
||||
},
|
||||
{ it }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractSerialGenerator(val bindingContext: BindingContext?, val currentDeclaration: ClassDescriptor) {
|
||||
|
||||
|
||||
+18
-6
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.CompilationException
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -14,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
@@ -63,17 +63,29 @@ fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module
|
||||
return null
|
||||
}
|
||||
|
||||
fun AbstractIrGenerator.findAddOnSerializer(propertyType: IrType, ctx: SerializationPluginContext): IrClassSymbol? {
|
||||
val classSymbol = propertyType.classOrNull ?: return null
|
||||
additionalSerializersInScopeOfCurrentFile[classSymbol to propertyType.isNullable()]?.let { return it }
|
||||
if (classSymbol in contextualKClassListInCurrentFile)
|
||||
return ctx.getClassFromRuntime(SpecialBuiltins.contextSerializer)
|
||||
if (classSymbol.owner.annotations.hasAnnotation(SerializationAnnotations.polymorphicFqName))
|
||||
return ctx.getClassFromRuntime(SpecialBuiltins.polymorphicSerializer)
|
||||
if (propertyType.isNullable()) return findAddOnSerializer(propertyType.makeNotNull(), ctx)
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
fun KotlinType.isGeneratedSerializableObject() =
|
||||
toClassDescriptor?.run { kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs } == true
|
||||
|
||||
fun AbstractSerialGenerator.getIrSerialTypeInfo(property: IrSerializableProperty, ctx: SerializationPluginContext): IrSerialTypeInfo {
|
||||
fun AbstractIrGenerator.getIrSerialTypeInfo(property: IrSerializableProperty, ctx: SerializationPluginContext): IrSerialTypeInfo {
|
||||
fun SerializableInfo(serializer: IrClassSymbol?) =
|
||||
IrSerialTypeInfo(property, if (property.type.isNullable()) "Nullable" else "", serializer)
|
||||
|
||||
val T = property.type
|
||||
property.serializableWith?.let { return SerializableInfo(it.classOrNull!!) }
|
||||
// TODO findAddOnSerializer(T, property.module)?.let { return SerializableInfo(it) }
|
||||
T.overridenSerializer?.let { return SerializableInfo(it.classOrNull!!) }
|
||||
property.serializableWith(ctx)?.let { return SerializableInfo(it) }
|
||||
findAddOnSerializer(T, ctx)?.let { return SerializableInfo(it) }
|
||||
T.overridenSerializer?.let { return SerializableInfo(it) }
|
||||
return when {
|
||||
T.isTypeParameter() -> IrSerialTypeInfo(property, if (property.type.isMarkedNullable()) "Nullable" else "", null)
|
||||
T.isPrimitiveType() -> IrSerialTypeInfo(
|
||||
@@ -82,7 +94,7 @@ fun AbstractSerialGenerator.getIrSerialTypeInfo(property: IrSerializablePropert
|
||||
)
|
||||
T.isString() -> IrSerialTypeInfo(property, "String")
|
||||
T.isArray() -> {
|
||||
val serializer = property.serializableWith?.classOrNull ?: ctx.getClassFromRuntime(SpecialBuiltins.referenceArraySerializer)
|
||||
val serializer = property.serializableWith(ctx) ?: ctx.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer)
|
||||
SerializableInfo(serializer)
|
||||
}
|
||||
else -> {
|
||||
|
||||
+64
-58
@@ -5,10 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.common
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.CompilationException
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getStringConstArgument
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
@@ -20,30 +22,22 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.contextSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.objectSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
fun AbstractSerialGenerator.findTypeSerializerOrContextUnchecked(
|
||||
fun AbstractIrGenerator.findTypeSerializerOrContextUnchecked(
|
||||
context: SerializationPluginContext, kType: IrType
|
||||
): IrClassSymbol? {
|
||||
val annotations = kType.annotations
|
||||
if (kType.isTypeParameter()) return null
|
||||
annotations.serializableWith()?.let { return it.classOrNull }
|
||||
additionalSerializersInScopeOfCurrentFile[kType.classOrNull?.descriptor to kType.isMarkedNullable()]?.let {
|
||||
return context.referenceClass(
|
||||
ClassId.topLevel(it.fqNameSafe)
|
||||
)
|
||||
annotations.serializableWith()?.let { return it }
|
||||
additionalSerializersInScopeOfCurrentFile[kType.classOrNull!! to kType.isNullable()]?.let {
|
||||
return it
|
||||
}
|
||||
if (kType.isMarkedNullable()) return findTypeSerializerOrContextUnchecked(context, kType.makeNotNull())
|
||||
if (kType.toKotlinType() in contextualKClassListInCurrentFile) return context.referenceClass(contextSerializerId)
|
||||
if (kType.classOrNull in contextualKClassListInCurrentFile) return context.referenceClass(contextSerializerId)
|
||||
return analyzeSpecialSerializers(context, annotations) ?: findTypeSerializer(context, kType)
|
||||
}
|
||||
|
||||
@@ -59,22 +53,15 @@ fun analyzeSpecialSerializers(
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun AbstractSerialGenerator.findTypeSerializerOrContext(
|
||||
context: SerializationPluginContext, kType: IrType,
|
||||
sourceElement: PsiElement? = null
|
||||
fun AbstractIrGenerator.findTypeSerializerOrContext(
|
||||
context: SerializationPluginContext, kType: IrType
|
||||
): IrClassSymbol? {
|
||||
if (kType.isTypeParameter()) return null
|
||||
return findTypeSerializerOrContextUnchecked(context, kType) ?: throw CompilationException(
|
||||
"Serializer for element of type $kType has not been found.\n" +
|
||||
"To use context serializer as fallback, explicitly annotate element with @Contextual",
|
||||
null,
|
||||
sourceElement
|
||||
)
|
||||
return findTypeSerializerOrContextUnchecked(context, kType) ?: error("Serializer for element of type ${kType.render()} has not been found")
|
||||
}
|
||||
|
||||
fun findTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
||||
val userOverride = type.overridenSerializer
|
||||
if (userOverride != null) return userOverride.classOrNull
|
||||
type.overridenSerializer?.let { return it }
|
||||
if (type.isTypeParameter()) return null
|
||||
if (type.isArray()) return context.referenceClass(referenceArraySerializerId)
|
||||
if (type.isGeneratedSerializableObject()) return context.referenceClass(objectSerializerId)
|
||||
@@ -89,7 +76,7 @@ fun findTypeSerializer(context: SerializationPluginContext, type: IrType): IrCla
|
||||
|
||||
internal fun IrClass?.classSerializer(context: SerializationPluginContext): IrClassSymbol? = this?.let {
|
||||
// serializer annotation on class?
|
||||
serializableWith?.let { return it.classOrNull }
|
||||
serializableWith?.let { return it }
|
||||
// companion object serializer?
|
||||
if (hasCompanionObjectAsSerializer) return companionObject()?.symbol
|
||||
// can infer @Poly?
|
||||
@@ -104,6 +91,11 @@ internal fun IrClass?.classSerializer(context: SerializationPluginContext): IrCl
|
||||
return null
|
||||
}
|
||||
|
||||
private val IrClass.isSerialInfoAnnotation: Boolean
|
||||
get() = annotations.hasAnnotation(SerializationAnnotations.serialInfoFqName)
|
||||
|| annotations.hasAnnotation(SerializationAnnotations.inheritableSerialInfoFqName)
|
||||
|| annotations.hasAnnotation(SerializationAnnotations.metaSerializableAnnotationFqName)
|
||||
|
||||
internal val IrClass.shouldHaveGeneratedSerializer: Boolean
|
||||
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN))
|
||||
|| isEnumWithLegacyGeneratedSerializer()
|
||||
@@ -116,7 +108,13 @@ internal fun IrClass.polymorphicSerializerIfApplicableAutomatically(context: Ser
|
||||
isInternalSerializable && modality == Modality.SEALED -> SpecialBuiltins.sealedSerializer
|
||||
else -> null
|
||||
}
|
||||
return serializer?.let { context.getClassFromRuntimeOrNull(it, SerializationPackages.packageFqName, SerializationPackages.internalPackageFqName) }
|
||||
return serializer?.let {
|
||||
context.getClassFromRuntimeOrNull(
|
||||
it,
|
||||
SerializationPackages.packageFqName,
|
||||
SerializationPackages.internalPackageFqName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal val IrClass.isInternalSerializable: Boolean
|
||||
@@ -131,13 +129,14 @@ internal val IrClass.isStaticSerializable: Boolean get() = this.typeParameters.i
|
||||
|
||||
|
||||
internal val IrClass.hasCompanionObjectAsSerializer: Boolean
|
||||
get() = isInternallySerializableObject || companionObject()?.serializerForClass == this.defaultType
|
||||
get() = isInternallySerializableObject || companionObject()?.serializerForClass == this.symbol
|
||||
|
||||
internal val IrClass.isInternallySerializableObject: Boolean
|
||||
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs()
|
||||
|
||||
internal val IrClass.serializerForClass: IrType?
|
||||
get() = null // TODO("Serializer(forClass)")
|
||||
internal val IrClass.serializerForClass: IrClassSymbol?
|
||||
get() = (annotations.findAnnotation(SerializationAnnotations.serializerAnnotationFqName)
|
||||
?.getValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol
|
||||
|
||||
fun findEnumTypeSerializer(context: SerializationPluginContext, type: IrType): IrClassSymbol? {
|
||||
val classSymbol = type.classOrNull?.owner ?: return null
|
||||
@@ -149,10 +148,10 @@ fun findEnumTypeSerializer(context: SerializationPluginContext, type: IrType): I
|
||||
internal fun IrClass.isEnumWithLegacyGeneratedSerializer(): Boolean = isInternallySerializableEnum() && useGeneratedEnumSerializer
|
||||
|
||||
internal val IrClass.useGeneratedEnumSerializer: Boolean
|
||||
get() = true // todo ????
|
||||
get() = true // FIXME This would break if we try to use this new IR compiler with pre-1.4.1 serialization versions. I think we just need to raise min runtime version.
|
||||
|
||||
internal val IrClass.isSealedSerializableInterface: Boolean
|
||||
get() = kind == ClassKind.INTERFACE && modality == Modality.SEALED && hasSerializableOrMetaAnnotationWithoutArgs() // in previous version, it was just 'serializableOrMeta'
|
||||
get() = kind == ClassKind.INTERFACE && modality == Modality.SEALED && hasSerializableOrMetaAnnotation()
|
||||
|
||||
internal fun IrClass.isInternallySerializableEnum(): Boolean =
|
||||
kind == ClassKind.ENUM_CLASS && hasSerializableOrMetaAnnotationWithoutArgs()
|
||||
@@ -181,7 +180,7 @@ fun IrType.isGeneratedSerializableObject(): Boolean {
|
||||
internal val IrClass.isSerializableObject: Boolean
|
||||
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotation()
|
||||
|
||||
// todo: optimize & unify
|
||||
// todo: optimize & unify with hasSerializableOrMeta
|
||||
internal fun IrClass.hasSerializableOrMetaAnnotationWithoutArgs(): Boolean {
|
||||
val annot = getAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
||||
if (annot != null) {
|
||||
@@ -205,9 +204,10 @@ fun SerializationPluginContext.getClassFromRuntimeOrNull(className: String, vara
|
||||
}
|
||||
|
||||
fun SerializationPluginContext.getClassFromRuntime(className: String, vararg packages: FqName): IrClassSymbol {
|
||||
return getClassFromRuntimeOrNull(className, *packages) ?:
|
||||
error("Class $className wasn't found in ${packages.toList().ifEmpty { SerializationPackages.allPublicPackages }}. " +
|
||||
"Check that you have correct version of serialization runtime in classpath.")
|
||||
return getClassFromRuntimeOrNull(className, *packages) ?: error(
|
||||
"Class $className wasn't found in ${packages.toList().ifEmpty { SerializationPackages.allPublicPackages }}. " +
|
||||
"Check that you have correct version of serialization runtime in classpath."
|
||||
)
|
||||
}
|
||||
|
||||
fun SerializationPluginContext.getClassFromInternalSerializationPackage(className: String): IrClassSymbol =
|
||||
@@ -215,23 +215,22 @@ fun SerializationPluginContext.getClassFromInternalSerializationPackage(classNam
|
||||
?: error("Class $className wasn't found in ${SerializationPackages.internalPackageFqName}. Check that you have correct version of serialization runtime in classpath.")
|
||||
|
||||
|
||||
internal val IrType.overridenSerializer: IrSimpleType?
|
||||
internal val IrType.overridenSerializer: IrClassSymbol?
|
||||
get() {
|
||||
val desc = this.classOrNull ?: return null
|
||||
desc.owner.serializableWith?.let { return it }
|
||||
return null
|
||||
}
|
||||
|
||||
internal val IrClass.serializableWith: IrSimpleType?
|
||||
internal val IrClass.serializableWith: IrClassSymbol?
|
||||
get() = annotations.serializableWith()
|
||||
|
||||
|
||||
internal fun List<IrConstructorCall>.serializableWith(): IrSimpleType? {
|
||||
// XXX::class
|
||||
// val annotationArg =
|
||||
// firstOrNull { it.type.classFqName == SerializationAnnotations.serializerAnnotationFqName }?.getValueArgument(0) ?: return null
|
||||
// TODO("SerializableWith")
|
||||
return null
|
||||
// @Serializable(X::class) -> X
|
||||
internal fun List<IrConstructorCall>.serializableWith(): IrClassSymbol? {
|
||||
val annotation = findAnnotation(SerializationAnnotations.serializableAnnotationFqName) ?: return null
|
||||
val arg = annotation.getValueArgument(0) as? IrClassReference ?: return null
|
||||
return arg.symbol as? IrClassSymbol
|
||||
}
|
||||
|
||||
internal fun getSerializableClassByCompanion(companionClass: IrClass): IrClass? {
|
||||
@@ -252,12 +251,12 @@ fun IrClass.hasSerializableOrMetaAnnotation() = descriptor.hasSerializableOrMeta
|
||||
internal val IrType.genericIndex: Int?
|
||||
get() = (this.classifierOrNull as? IrTypeParameterSymbol)?.owner?.index
|
||||
|
||||
fun IrType.serialName(): String = this.classOrNull!!.owner.serialName()
|
||||
fun IrType.serialName(): String = this.classOrNull!!.owner.serialName()
|
||||
fun IrClass.serialName(): String {
|
||||
return descriptor.serialName() // TODO
|
||||
return annotations.serialNameValue ?: fqNameWhenAvailable?.asString() ?: error("${this.render()} does not have fqName")
|
||||
}
|
||||
|
||||
fun AbstractSerialGenerator.allSealedSerializableSubclassesFor(
|
||||
fun AbstractIrGenerator.allSealedSerializableSubclassesFor(
|
||||
irClass: IrClass,
|
||||
context: SerializationPluginContext
|
||||
): Pair<List<IrSimpleType>, List<IrClassSymbol>> {
|
||||
@@ -278,9 +277,7 @@ fun IrClass.findEnumValuesMethod() = this.functions.singleOrNull { f ->
|
||||
|
||||
internal fun IrClass.enumEntries(): List<IrEnumEntry> {
|
||||
check(this.kind == ClassKind.ENUM_CLASS)
|
||||
return declarations.filterIsInstance<IrEnumEntry>()
|
||||
// .filter { it.kind == ClassKind.ENUM_ENTRY }
|
||||
.toList()
|
||||
return declarations.filterIsInstance<IrEnumEntry>().toList()
|
||||
}
|
||||
|
||||
internal fun IrClass.isEnumWithSerialInfoAnnotation(): Boolean {
|
||||
@@ -290,14 +287,14 @@ internal fun IrClass.isEnumWithSerialInfoAnnotation(): Boolean {
|
||||
}
|
||||
|
||||
internal val List<IrConstructorCall>.hasAnySerialAnnotation: Boolean
|
||||
get() = false // TODO serialNameValue != null || any { it.annotationClass?.isSerialInfoAnnotation == true }
|
||||
get() = serialNameValue != null || any { it.annotationClass.isSerialInfoAnnotation == true }
|
||||
|
||||
internal val List<IrConstructorCall>.serialNameValue: String?
|
||||
get() = null // todo("List<IrConstructorCall>.serialNameValue") @SerialName
|
||||
get() = findAnnotation(SerializationAnnotations.serialNameAnnotationFqName)?.getStringConstArgument(0) // @SerialName("foo")
|
||||
|
||||
internal fun getSerializableClassDescriptorBySerializer(serializer: IrClass): IrClass? {
|
||||
val serializerForClass = serializer.serializerForClass
|
||||
if (serializerForClass != null) return serializerForClass.classOrNull?.owner
|
||||
if (serializerForClass != null) return serializerForClass.owner
|
||||
if (serializer.name !in setOf(
|
||||
SerialEntityNames.SERIALIZER_CLASS_NAME,
|
||||
SerialEntityNames.GENERATED_SERIALIZER_CLASS
|
||||
@@ -316,9 +313,14 @@ internal fun isKSerializer(type: IrType): Boolean {
|
||||
}
|
||||
|
||||
internal fun IrClass.findPluginGeneratedMethod(name: String): IrSimpleFunction? {
|
||||
return this.functions.find { it.name.asString() == name && it.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) }
|
||||
return this.functions.find {
|
||||
it.name.asString() == name && it.isFromPlugin()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun IrDeclaration.isFromPlugin(): Boolean =
|
||||
this.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) || (this.descriptor as? CallableMemberDescriptor)?.kind == CallableMemberDescriptor.Kind.SYNTHESIZED // old FE doesn't specify origin
|
||||
|
||||
internal fun IrConstructor.isSerializationCtor(): Boolean {
|
||||
/*kind == CallableMemberDescriptor.Kind.SYNTHESIZED does not work because DeserializedClassConstructorDescriptor loses its kind*/
|
||||
return valueParameters.lastOrNull()?.run {
|
||||
@@ -328,4 +330,8 @@ internal fun IrConstructor.isSerializationCtor(): Boolean {
|
||||
} == true
|
||||
}
|
||||
|
||||
internal fun IrExpression.isInitializePropertyFromParameter(): Boolean = this is IrGetValueImpl && this.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
internal fun IrExpression.isInitializePropertyFromParameter(): Boolean =
|
||||
this is IrGetValueImpl && this.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
|
||||
internal val IrConstructorCall.annotationClass
|
||||
get() = this.symbol.owner.constructedClass
|
||||
+26
-24
@@ -7,15 +7,16 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.backend.common.sourceElement
|
||||
import org.jetbrains.kotlin.backend.jvm.functionByName
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
@@ -25,19 +26,20 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.psi
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.replace
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.*
|
||||
@@ -71,9 +73,12 @@ interface IrBuilderExtension {
|
||||
}
|
||||
|
||||
fun <F: IrFunction> addFunctionBody(function: F, bodyGen: IrBlockBodyBuilder.(F) -> Unit) {
|
||||
function.body = DeclarationIrBuilder(compilerContext, function.symbol, function.startOffset, function.endOffset).irBlockBody(
|
||||
function.startOffset,
|
||||
function.endOffset
|
||||
val parentClass = function.parent
|
||||
val startOffset = function.startOffset.takeIf { it >= 0 } ?: parentClass.startOffset
|
||||
val endOffset = function.endOffset.takeIf { it >= 0 } ?: parentClass.endOffset
|
||||
function.body = DeclarationIrBuilder(compilerContext, function.symbol, startOffset, endOffset).irBlockBody(
|
||||
startOffset,
|
||||
endOffset
|
||||
) { bodyGen(function) }
|
||||
}
|
||||
|
||||
@@ -136,7 +141,7 @@ interface IrBuilderExtension {
|
||||
): IrProperty {
|
||||
val lazySafeModeClassDescriptor = compilerContext.referenceClass(ClassId.topLevel(LAZY_MODE_FQ))!!.owner
|
||||
val lazyFunctionSymbol = compilerContext.referenceFunctions(CallableId(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, Name.identifier("lazy"))).single {
|
||||
it.descriptor.valueParameters.size == 2 && it.descriptor.valueParameters[0].type == lazySafeModeClassDescriptor.defaultType
|
||||
it.owner.valueParameters.size == 2 && it.owner.valueParameters[0].type == lazySafeModeClassDescriptor.defaultType
|
||||
}
|
||||
val publicationEntryDescriptor = lazySafeModeClassDescriptor.enumEntries().single { it.name == LAZY_PUBLICATION_MODE_NAME }
|
||||
|
||||
@@ -814,7 +819,7 @@ interface IrBuilderExtension {
|
||||
): IrExpression? {
|
||||
val nullableSerClass = compilerContext.referenceProperties(SerialEntityNames.wrapIntoNullableCallableId).single()
|
||||
val serializer =
|
||||
property.serializableWith?.classOrNull
|
||||
property.serializableWith(compilerContext)
|
||||
?: if (!property.type.isTypeParameter()) generator.findTypeSerializerOrContext(
|
||||
compilerContext,
|
||||
property.type
|
||||
@@ -883,7 +888,7 @@ interface IrBuilderExtension {
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.serializerInstance(
|
||||
enclosingGenerator: AbstractSerialGenerator,
|
||||
enclosingGenerator: AbstractIrGenerator,
|
||||
serializerClassOriginal: ClassDescriptor?,
|
||||
module: ModuleDescriptor,
|
||||
kType: IrType,
|
||||
@@ -901,7 +906,7 @@ interface IrBuilderExtension {
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.serializerInstance(
|
||||
enclosingGenerator: AbstractSerialGenerator,
|
||||
enclosingGenerator: AbstractIrGenerator,
|
||||
serializerClassOriginal: IrClassSymbol?,
|
||||
pluginContext: SerializationPluginContext,
|
||||
kType: IrType,
|
||||
@@ -960,8 +965,7 @@ interface IrBuilderExtension {
|
||||
thisIrType.arguments.map {
|
||||
val argSer = enclosingGenerator.findTypeSerializerOrContext(
|
||||
compilerContext,
|
||||
it.typeOrNull!!, //todo: handle star projections here
|
||||
sourceElement = serializerClassOriginal.owner.sourceElement()?.psi
|
||||
it.typeOrNull!! //todo: handle star projections here?
|
||||
)
|
||||
instantiate(argSer, it.typeOrNull!!)!!
|
||||
})
|
||||
@@ -1076,8 +1080,7 @@ interface IrBuilderExtension {
|
||||
args = kType.arguments.map {
|
||||
val argSer = enclosingGenerator.findTypeSerializerOrContext(
|
||||
pluginContext,
|
||||
it.typeOrNull!!, // todo: stars
|
||||
sourceElement = serializerClassOriginal.owner.source.getPsi()
|
||||
it.typeOrNull!! // todo: stars?
|
||||
)
|
||||
instantiate(argSer, it.typeOrNull!!) ?: return null
|
||||
}
|
||||
@@ -1242,11 +1245,10 @@ interface IrBuilderExtension {
|
||||
}
|
||||
|
||||
fun IrClass.findWriteSelfMethod(): IrSimpleFunction? =
|
||||
declarations.filter { it is IrSimpleFunction && it.name == SerialEntityNames.WRITE_SELF_NAME && !it.isFakeOverride }
|
||||
.takeUnless(Collection<*>::isEmpty)?.single() as IrSimpleFunction?
|
||||
declarations.singleOrNull { it is IrSimpleFunction && it.name == SerialEntityNames.WRITE_SELF_NAME && !it.isFakeOverride } as IrSimpleFunction?
|
||||
|
||||
fun IrBlockBodyBuilder.serializeAllProperties(
|
||||
generator: AbstractSerialGenerator,
|
||||
generator: AbstractIrGenerator,
|
||||
serializableIrClass: IrClass,
|
||||
serializableProperties: List<IrSerializableProperty>,
|
||||
objectToSerialize: IrValueDeclaration,
|
||||
@@ -1339,7 +1341,7 @@ interface IrBuilderExtension {
|
||||
|
||||
|
||||
fun IrBlockBodyBuilder.formEncodeDecodePropertyCall(
|
||||
enclosingGenerator: AbstractSerialGenerator,
|
||||
enclosingGenerator: AbstractIrGenerator,
|
||||
encoder: IrExpression,
|
||||
property: IrSerializableProperty,
|
||||
whenHaveSerializer: (serializer: IrExpression, sti: IrSerialTypeInfo) -> FunctionWithArgs,
|
||||
|
||||
+29
-16
@@ -5,25 +5,23 @@
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irInt
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrErrorClassImpl.endOffset
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrErrorClassImpl.startOffset
|
||||
import org.jetbrains.kotlin.ir.types.toKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractIrGenerator
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerializableClassByCompanion
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isKSerializer
|
||||
@@ -34,9 +32,11 @@ class SerializableCompanionIrGenerator(
|
||||
val irClass: IrClass,
|
||||
val serializableIrClass: IrClass,
|
||||
override val compilerContext: SerializationPluginContext,
|
||||
) : SerializableCompanionCodegen(irClass.descriptor, null), IrBuilderExtension {
|
||||
) : AbstractIrGenerator(irClass), IrBuilderExtension {
|
||||
|
||||
override fun getSerializerGetterDescriptor(): FunctionDescriptor {
|
||||
private val serializableDescriptor = serializableIrClass.descriptor
|
||||
|
||||
private fun getSerializerGetterDescriptor(): FunctionDescriptor {
|
||||
return irClass.findDeclaration<IrSimpleFunction> {
|
||||
(it.valueParameters.size == serializableDescriptor.declaredTypeParameters.size
|
||||
&& it.valueParameters.all { p -> isKSerializer(p.type) }) && isKSerializer(it.returnType)
|
||||
@@ -46,6 +46,19 @@ class SerializableCompanionIrGenerator(
|
||||
)
|
||||
}
|
||||
|
||||
fun generate() {
|
||||
val serializerGetterDescriptor = getSerializerGetterDescriptor()
|
||||
|
||||
if (serializableDescriptor.isSerializableObject
|
||||
|| serializableDescriptor.isAbstractOrSealedSerializableClass()
|
||||
|| serializableDescriptor.isSerializableEnum()
|
||||
) {
|
||||
generateLazySerializerGetter(serializerGetterDescriptor)
|
||||
} else {
|
||||
generateSerializerGetter(serializerGetterDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun generate(
|
||||
irClass: IrClass,
|
||||
@@ -97,7 +110,7 @@ class SerializableCompanionIrGenerator(
|
||||
irSerializableClass.annotations += annotationCtorCall
|
||||
}
|
||||
|
||||
override fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
fun generateLazySerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
val serializer = requireNotNull(
|
||||
findTypeSerializer(
|
||||
compilerContext,
|
||||
@@ -105,14 +118,14 @@ class SerializableCompanionIrGenerator(
|
||||
)
|
||||
)
|
||||
|
||||
val kSerializerIrClass = serializer.owner
|
||||
val kSerializerIrClass = compilerContext.referenceClass(ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME))!!.owner
|
||||
val targetIrType =
|
||||
kSerializerIrClass.defaultType.substitute(mapOf(kSerializerIrClass.typeParameters[0].symbol to compilerContext.irBuiltIns.anyType))
|
||||
|
||||
val property = createLazyProperty(irClass, targetIrType, SerialEntityNames.CACHED_SERIALIZER_PROPERTY_NAME) {
|
||||
val expr = serializerInstance(
|
||||
this@SerializableCompanionIrGenerator,
|
||||
serializer, compilerContext, kSerializerIrClass.defaultType
|
||||
serializer, compilerContext, serializableIrClass.defaultType
|
||||
)
|
||||
patchSerializableClassWithMarkerAnnotation(kSerializerIrClass)
|
||||
+irReturn(requireNotNull(expr))
|
||||
@@ -124,7 +137,7 @@ class SerializableCompanionIrGenerator(
|
||||
generateSerializerFactoryIfNeeded(methodDescriptor)
|
||||
}
|
||||
|
||||
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
|
||||
irClass.contributeFunction(methodDescriptor) { getter ->
|
||||
val serializer = requireNotNull(
|
||||
findTypeSerializer(
|
||||
@@ -145,7 +158,7 @@ class SerializableCompanionIrGenerator(
|
||||
}
|
||||
|
||||
private fun generateSerializerFactoryIfNeeded(getterDescriptor: FunctionDescriptor) {
|
||||
if (!companionDescriptor.needSerializerFactory()) return
|
||||
if (!irClass.descriptor.needSerializerFactory()) return
|
||||
val serialFactoryDescriptor = irClass.findDeclaration<IrSimpleFunction> {
|
||||
it.valueParameters.size == 1
|
||||
&& it.valueParameters.first().isVararg
|
||||
|
||||
+7
-12
@@ -7,7 +7,8 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.codegen.CompilationException
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -24,7 +25,6 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isStaticSerializable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
@@ -37,9 +37,9 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SE
|
||||
class SerializableIrGenerator(
|
||||
val irClass: IrClass,
|
||||
override val compilerContext: SerializationPluginContext
|
||||
) : AbstractSerialGenerator(null, irClass.descriptor), IrBuilderExtension {
|
||||
) : AbstractIrGenerator(irClass), IrBuilderExtension {
|
||||
|
||||
protected val properties = bindingContext.serializablePropertiesForIrBackend(irClass)
|
||||
protected val properties = serializablePropertiesForIrBackend(irClass)
|
||||
|
||||
private val serialDescriptorClass = compilerContext.referenceClass(
|
||||
ClassId(
|
||||
@@ -272,7 +272,7 @@ class SerializableIrGenerator(
|
||||
): Int {
|
||||
check(superClass.isInternalSerializable)
|
||||
val superCtorRef = serializableSyntheticConstructor(superClass)!!
|
||||
val superProperties = bindingContext.serializablePropertiesForIrBackend(superClass).serializableProperties
|
||||
val superProperties = serializablePropertiesForIrBackend(superClass).serializableProperties
|
||||
val superSlots = superProperties.bitMaskSlotCount()
|
||||
val arguments = allValueParameters.subList(0, superSlots) +
|
||||
allValueParameters.subList(propertiesStart, propertiesStart + superProperties.size) +
|
||||
@@ -309,7 +309,7 @@ class SerializableIrGenerator(
|
||||
var ignoreIndexTo = -1
|
||||
val superClass = irClass.getSuperClassOrAny()
|
||||
if (superClass.descriptor.isInternalSerializable) {
|
||||
ignoreIndexTo = bindingContext.serializablePropertiesForIrBackend(superClass).serializableProperties.size
|
||||
ignoreIndexTo = serializablePropertiesForIrBackend(superClass).serializableProperties.size
|
||||
|
||||
// call super.writeSelf
|
||||
var superWriteSelfF = superClass.findWriteSelfMethod()
|
||||
@@ -374,12 +374,7 @@ class SerializableIrGenerator(
|
||||
private fun generateSyntheticMethods() {
|
||||
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
|
||||
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SAVE) }) {
|
||||
val func =
|
||||
irClass.functions.singleOrNull { function ->
|
||||
function.name == SerialEntityNames.WRITE_SELF_NAME &&
|
||||
function.modality == Modality.FINAL &&
|
||||
function.returnType.isUnit()
|
||||
} ?: return
|
||||
val func = irClass.findWriteSelfMethod() ?: return
|
||||
generateWriteSelfMethod(func)
|
||||
}
|
||||
}
|
||||
|
||||
+17
-12
@@ -5,18 +5,26 @@
|
||||
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.ir
|
||||
|
||||
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.backend.jvm.functionByName
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.codegen.CompilationException
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.deepCopyWithVariables
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.mapValueParametersIndexed
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
@@ -32,7 +40,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey
|
||||
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
|
||||
@@ -41,8 +48,6 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SA
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_DECODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_ENCODER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UNKNOWN_FIELD_EXC
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorBySerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.isEnumWithLegacyGeneratedSerializer
|
||||
|
||||
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER", true)
|
||||
|
||||
@@ -53,18 +58,18 @@ open class SerializerIrGenerator(
|
||||
final override val compilerContext: SerializationPluginContext,
|
||||
metadataPlugin: SerializationDescriptorSerializerPlugin?,
|
||||
private val serialInfoJvmGenerator: SerialInfoImplJvmIrGenerator,
|
||||
) : AbstractSerialGenerator(null, irClass.descriptor), IrBuilderExtension {
|
||||
) : AbstractIrGenerator(irClass), IrBuilderExtension {
|
||||
protected val serializableIrClass = getSerializableClassDescriptorBySerializer(irClass)!!
|
||||
|
||||
protected val serialName: String = serializableIrClass.serialName()
|
||||
protected val properties = bindingContext.serializablePropertiesForIrBackend(serializableIrClass, metadataPlugin)
|
||||
protected val properties = serializablePropertiesForIrBackend(serializableIrClass, metadataPlugin)
|
||||
protected val serializableProperties = properties.serializableProperties
|
||||
protected val isGeneratedSerializer = irClass.descriptor.typeConstructor.supertypes.any(::isGeneratedKSerializer) // TODO TODO
|
||||
|
||||
protected val generatedSerialDescPropertyDescriptor = getProperty(
|
||||
SerialEntityNames.SERIAL_DESC_FIELD,
|
||||
{ true }
|
||||
)?.takeIf { it.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey) }
|
||||
)?.takeIf { it.isFromPlugin() }
|
||||
|
||||
protected val anySerialDescProperty = getProperty(
|
||||
SerialEntityNames.SERIAL_DESC_FIELD,
|
||||
@@ -103,7 +108,7 @@ open class SerializerIrGenerator(
|
||||
|
||||
// how to (auto)create backing field and getter/setter?
|
||||
compilerContext.symbolTable.withReferenceScope(irClass) {
|
||||
prop = generateSimplePropertyWithBackingField(desc.descriptor, irClass) // TODO check if this works correctly with old FE
|
||||
prop = generateSimplePropertyWithBackingField(desc.descriptor, irClass)
|
||||
|
||||
// TODO: Do not use descriptors here
|
||||
localSerializersFieldsDescriptors = findLocalSerializersFieldDescriptors().map { prop ->
|
||||
@@ -600,7 +605,7 @@ open class SerializerIrGenerator(
|
||||
if (!prop && (save || load))
|
||||
generateSerialDesc()
|
||||
if (serializableIrClass.typeParameters.isNotEmpty()) {
|
||||
findSerializerConstructorForTypeArgumentsSerializers(irClass)?.let {
|
||||
findSerializerConstructorForTypeArgumentsSerializers(irClass)?.takeIf { it.owner.isFromPlugin() }?.let {
|
||||
generateGenericFieldsAndConstructor(it.owner)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-6
@@ -6,11 +6,16 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.extensions
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CompilationException
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.fileParent
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
@@ -56,12 +61,16 @@ private class SerializerClassLowering(
|
||||
private val serialInfoJvmGenerator = SerialInfoImplJvmIrGenerator(context, moduleFragment).also { context.serialInfoImplJvmIrGenerator = it }
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
SerializableIrGenerator.generate(irClass, context)
|
||||
SerializerIrGenerator.generate(irClass, context, context.metadataPlugin, serialInfoJvmGenerator)
|
||||
SerializableCompanionIrGenerator.generate(irClass, context)
|
||||
try {
|
||||
SerializableIrGenerator.generate(irClass, context)
|
||||
SerializerIrGenerator.generate(irClass, context, context.metadataPlugin, serialInfoJvmGenerator)
|
||||
SerializableCompanionIrGenerator.generate(irClass, context)
|
||||
|
||||
if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) {
|
||||
serialInfoJvmGenerator.generate(irClass)
|
||||
if (context.platform.isJvm() && KSerializerDescriptorResolver.isSerialInfoImpl(irClass.descriptor)) {
|
||||
serialInfoJvmGenerator.generate(irClass)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
throw CompilationException("kotlinx.serialization compiler plugin internal error: unable to transform declaration, see cause", irClass.fileParent, irClass, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProv
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import java.util.*
|
||||
|
||||
open class SerializationResolveExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : SyntheticResolveExtension {
|
||||
override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> = when {
|
||||
@@ -48,6 +47,16 @@ open class SerializationResolveExtension @JvmOverloads constructor(val metadataP
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
override fun getSyntheticPropertiesNames(thisDescriptor: ClassDescriptor): List<Name> {
|
||||
// typeSerial0, typeSerial1, ... for serializers of parameterized classes
|
||||
val count = thisDescriptor.declaredTypeParameters.size
|
||||
if (count < 1) return emptyList()
|
||||
val classDescriptor = getSerializableClassDescriptorBySerializer(thisDescriptor) ?: return emptyList()
|
||||
if (!isAllowedToHaveAutoGeneratedSerializerMethods(thisDescriptor, classDescriptor)) return emptyList()
|
||||
val propNames = (0 until count).map { "${SerialEntityNames.typeArgPrefix}$it" }.map { Name.identifier(it) }
|
||||
return propNames
|
||||
}
|
||||
|
||||
private fun hasCustomizedSerializeMethod(serializableClass: ClassDescriptor): Boolean {
|
||||
// We cannot check whether companion has @Serializer(MyClass::class) annotation due to recursive resolve problems
|
||||
// (apparently, resolve MyClass type asks for all function names, which leads us to this function again)
|
||||
|
||||
+35
-24
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.IMPL_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||
@@ -220,43 +219,55 @@ object KSerializerDescriptorResolver {
|
||||
}
|
||||
|
||||
private fun createSerializableClassPropertyDescriptor(
|
||||
companionDescriptor: ClassDescriptor,
|
||||
classDescriptor: ClassDescriptor
|
||||
): PropertyDescriptor =
|
||||
doCreateSerializerProperty(companionDescriptor, classDescriptor, SerialEntityNames.SERIAL_DESC_FIELD_NAME)
|
||||
thisDescriptor: ClassDescriptor,
|
||||
serializableClassDescriptor: ClassDescriptor
|
||||
): PropertyDescriptor {
|
||||
val typeParam = listOf(createProjection(serializableClassDescriptor.defaultType, Variance.INVARIANT, null))
|
||||
val propertyFromSerializer = thisDescriptor.getGeneratedSerializerDescriptor().getMemberScope(typeParam)
|
||||
.getContributedVariables(SerialEntityNames.SERIAL_DESC_FIELD_NAME, NoLookupLocation.FROM_BUILTINS).single()
|
||||
val result = doCreateSerializerProperty(
|
||||
thisDescriptor,
|
||||
SerialEntityNames.SERIAL_DESC_FIELD_NAME,
|
||||
propertyFromSerializer.type,
|
||||
propertyFromSerializer.typeParameters,
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
Modality.OPEN // TODO: it was historically OPEN, but I do not see the reasons not to change to FINAL
|
||||
)
|
||||
result.overriddenDescriptors = listOf(propertyFromSerializer)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun doCreateSerializerProperty(
|
||||
companionDescriptor: ClassDescriptor,
|
||||
classDescriptor: ClassDescriptor,
|
||||
name: Name
|
||||
thisDescriptor: ClassDescriptor,
|
||||
name: Name,
|
||||
type: KotlinType,
|
||||
typeParameters: List<TypeParameterDescriptor> = emptyList(),
|
||||
visibility: DescriptorVisibility = DescriptorVisibilities.PRIVATE,
|
||||
modality: Modality = Modality.FINAL,
|
||||
needBackingField: Boolean = false
|
||||
): PropertyDescriptor {
|
||||
val typeParam = listOf(createProjection(classDescriptor.defaultType, Variance.INVARIANT, null))
|
||||
val propertyFromSerializer = companionDescriptor.getGeneratedSerializerDescriptor().getMemberScope(typeParam)
|
||||
.getContributedVariables(name, NoLookupLocation.FROM_BUILTINS).single()
|
||||
|
||||
val propertyDescriptor = PropertyDescriptorImpl.create(
|
||||
companionDescriptor, Annotations.EMPTY, Modality.OPEN, DescriptorVisibilities.PUBLIC, false, name,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, companionDescriptor.source, false, false, false, false, false, false
|
||||
thisDescriptor, Annotations.EMPTY, modality, visibility, false, name,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, thisDescriptor.source, false, false, false, false, false, false
|
||||
)
|
||||
|
||||
val extensionReceiverParameter: ReceiverParameterDescriptor? = null // kludge to disambiguate call
|
||||
propertyDescriptor.setType(
|
||||
propertyFromSerializer.type,
|
||||
propertyFromSerializer.typeParameters,
|
||||
companionDescriptor.thisAsReceiverParameter,
|
||||
type,
|
||||
typeParameters,
|
||||
thisDescriptor.thisAsReceiverParameter,
|
||||
extensionReceiverParameter,
|
||||
emptyList()
|
||||
)
|
||||
|
||||
val propertyGetter = PropertyGetterDescriptorImpl(
|
||||
propertyDescriptor, Annotations.EMPTY, Modality.OPEN, DescriptorVisibilities.PUBLIC, false, false, false,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, null, companionDescriptor.source
|
||||
propertyDescriptor, Annotations.EMPTY, modality, visibility, false, false, false,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, null, thisDescriptor.source
|
||||
)
|
||||
propertyGetter.initialize(type)
|
||||
|
||||
propertyGetter.initialize(propertyFromSerializer.type)
|
||||
propertyDescriptor.initialize(propertyGetter, null)
|
||||
propertyDescriptor.overriddenDescriptors = listOf(propertyFromSerializer)
|
||||
|
||||
val backingField = if (needBackingField) FieldDescriptorImpl(Annotations.EMPTY, propertyDescriptor) else null
|
||||
propertyDescriptor.initialize(propertyGetter, null, backingField, null)
|
||||
return propertyDescriptor
|
||||
}
|
||||
|
||||
@@ -650,7 +661,7 @@ object KSerializerDescriptorResolver {
|
||||
serializerClass,
|
||||
listOf(TypeProjectionImpl(param.defaultType))
|
||||
)
|
||||
val desc = SimpleSyntheticPropertyDescriptor(serializerDescriptor, "$typeArgPrefix$index", pType)
|
||||
val desc = doCreateSerializerProperty(serializerDescriptor, Name.identifier("$typeArgPrefix$index"), pType, needBackingField = true)
|
||||
return listOf(desc)
|
||||
}
|
||||
}
|
||||
|
||||
+53
-50
@@ -165,7 +165,10 @@ internal val ISerializableProperties<*, *, *>.goldenMaskList: List<Int>
|
||||
internal fun List<ISerializableProperty<*, *>>.bitMaskSlotCount() = size / 32 + 1
|
||||
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
|
||||
|
||||
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor, serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null): SerializableProperties {
|
||||
internal fun BindingContext.serializablePropertiesFor(
|
||||
classDescriptor: ClassDescriptor,
|
||||
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
|
||||
): SerializableProperties {
|
||||
val props = this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
|
||||
serializationDescriptorSerializer?.putIfNeeded(classDescriptor, props)
|
||||
return props
|
||||
@@ -187,59 +190,59 @@ class IrSerializableProperties(
|
||||
) : ISerializableProperties<IrProperty, IrSimpleType, IrSerializableProperty> {
|
||||
}
|
||||
|
||||
internal fun BindingContext?.serializablePropertiesForIrBackend(
|
||||
internal fun serializablePropertiesForIrBackend(
|
||||
classDescriptor: IrClass,
|
||||
serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null
|
||||
): IrSerializableProperties {
|
||||
if (this != null) {
|
||||
// can work with old FE
|
||||
TODO("Support this for old FE")
|
||||
} else {
|
||||
val properties = classDescriptor.properties.toList()
|
||||
val primaryConstructorParams = classDescriptor.primaryConstructor?.valueParameters.orEmpty()
|
||||
val primaryParamsAsProps = properties.associateBy { it.name }.let { namesMap ->
|
||||
primaryConstructorParams.mapNotNull {
|
||||
if (it.name !in namesMap) null else namesMap.getValue(it.name) to it.hasDefaultValue()
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
fun isPropSerializable(it: IrProperty) =
|
||||
if (classDescriptor.isInternalSerializable) !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)
|
||||
else !DescriptorVisibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)) || primaryParamsAsProps.contains(
|
||||
it
|
||||
))
|
||||
|
||||
val (primaryCtorSerializableProps, bodySerializableProps) = properties
|
||||
.filter { !it.isFakeOverride && !it.isDelegated }
|
||||
.filter(::isPropSerializable)
|
||||
.map {
|
||||
val isConstructorParameterWithDefault = primaryParamsAsProps[it] ?: false
|
||||
IrSerializableProperty(
|
||||
it,
|
||||
isConstructorParameterWithDefault,
|
||||
it.backingField != null,
|
||||
it.backingField?.initializer.let { init -> init != null && !init.expression.isInitializePropertyFromParameter() } || isConstructorParameterWithDefault
|
||||
)
|
||||
}
|
||||
.filterNot { it.transient }
|
||||
.partition { primaryParamsAsProps.contains(it.descriptor) }
|
||||
|
||||
val serializableProps = run {
|
||||
val supers = classDescriptor.getParentClassNotAny()
|
||||
if (supers == null || !supers.isInternalSerializable)
|
||||
primaryCtorSerializableProps + bodySerializableProps
|
||||
else
|
||||
serializablePropertiesForIrBackend(
|
||||
supers,
|
||||
serializationDescriptorSerializer
|
||||
).serializableProperties + primaryCtorSerializableProps + bodySerializableProps
|
||||
} // todo: implement unsorting
|
||||
|
||||
val isExternallySerializable =
|
||||
classDescriptor.isInternallySerializableEnum() || primaryConstructorParams.size == primaryParamsAsProps.size
|
||||
|
||||
return IrSerializableProperties(serializableProps, isExternallySerializable, primaryCtorSerializableProps, bodySerializableProps)
|
||||
val properties = classDescriptor.properties.toList()
|
||||
val primaryConstructorParams = classDescriptor.primaryConstructor?.valueParameters.orEmpty()
|
||||
val primaryParamsAsProps = properties.associateBy { it.name }.let { namesMap ->
|
||||
primaryConstructorParams.mapNotNull {
|
||||
if (it.name !in namesMap) null else namesMap.getValue(it.name) to it.hasDefaultValue()
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
fun isPropSerializable(it: IrProperty) =
|
||||
if (classDescriptor.isInternalSerializable) !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)
|
||||
else !DescriptorVisibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName)) || primaryParamsAsProps.contains(
|
||||
it
|
||||
))
|
||||
|
||||
val (primaryCtorSerializableProps, bodySerializableProps) = properties
|
||||
.asSequence()
|
||||
.filter { !it.isFakeOverride && !it.isDelegated }
|
||||
.filter(::isPropSerializable)
|
||||
.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)
|
||||
IrSerializableProperty(
|
||||
it,
|
||||
isConstructorParameterWithDefault,
|
||||
it.backingField != null || isPropertyWithBackingFieldFromAnotherModule,
|
||||
it.backingField?.initializer.let { init -> init != null && !init.expression.isInitializePropertyFromParameter() } || isConstructorParameterWithDefault
|
||||
|| isPropertyFromAnotherModuleDeclaresDefaultValue
|
||||
)
|
||||
}
|
||||
.filterNot { it.transient }
|
||||
.partition { primaryParamsAsProps.contains(it.descriptor) }
|
||||
|
||||
val serializableProps = run {
|
||||
val supers = classDescriptor.getParentClassNotAny()
|
||||
if (supers == null || !supers.isInternalSerializable)
|
||||
primaryCtorSerializableProps + bodySerializableProps
|
||||
else
|
||||
serializablePropertiesForIrBackend(
|
||||
supers,
|
||||
serializationDescriptorSerializer
|
||||
).serializableProperties + primaryCtorSerializableProps + bodySerializableProps
|
||||
} // todo: implement unsorting
|
||||
|
||||
val isExternallySerializable =
|
||||
classDescriptor.isInternallySerializableEnum() || primaryConstructorParams.size == primaryParamsAsProps.size
|
||||
|
||||
return IrSerializableProperties(serializableProps, isExternallySerializable, primaryCtorSerializableProps, bodySerializableProps)
|
||||
}
|
||||
|
||||
fun IrClass.getParentClassNotAny(): IrClass? {
|
||||
|
||||
+4
-12
@@ -19,24 +19,17 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.overrides
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.module
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.asSimpleType
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.analyzeSpecialSerializers
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.genericIndex
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.overridenSerializer
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serialNameValue
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.serializableWith
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
|
||||
class SerializableProperty(
|
||||
override val descriptor: PropertyDescriptor,
|
||||
@@ -48,7 +41,7 @@ class SerializableProperty(
|
||||
override val type = descriptor.type
|
||||
override val genericIndex = type.genericIndex
|
||||
val module = descriptor.module
|
||||
override val serializableWith = descriptor.serializableWith ?: analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType
|
||||
val serializableWith = descriptor.serializableWith ?: analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType
|
||||
override val optional = !descriptor.annotations.serialRequired && declaresDefaultValue
|
||||
override val transient = descriptor.annotations.serialTransient || !hasBackingField
|
||||
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
|
||||
@@ -61,7 +54,6 @@ interface ISerializableProperty<D, T> {
|
||||
val name: String
|
||||
val type: T
|
||||
val genericIndex: Int?
|
||||
val serializableWith: T?
|
||||
val optional: Boolean
|
||||
val transient: Boolean
|
||||
}
|
||||
@@ -75,7 +67,7 @@ class IrSerializableProperty(
|
||||
override val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
||||
override val type = descriptor.getter!!.returnType as IrSimpleType
|
||||
override val genericIndex = type.genericIndex
|
||||
override val serializableWith = type.overridenSerializer /* ?:analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType */ // TODO
|
||||
fun serializableWith(ctx: SerializationPluginContext) = descriptor.annotations.serializableWith() ?: analyzeSpecialSerializers(ctx, descriptor.annotations)
|
||||
override val optional = !descriptor.annotations.hasAnnotation(SerializationAnnotations.requiredAnnotationFqName) && declaresDefaultValue
|
||||
override val transient = descriptor.annotations.hasAnnotation(SerializationAnnotations.serialTransientFqName) || !hasBackingField
|
||||
}
|
||||
+13
-2
@@ -6,10 +6,9 @@
|
||||
package org.jetbrains.kotlinx.serialization;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
@@ -25,12 +24,24 @@ public class SerializationIrBoxTestGenerated extends AbstractSerializationIrBoxT
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/boxIr"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationsOnFile.kt")
|
||||
public void testAnnotationsOnFile() throws Exception {
|
||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/boxIr/annotationsOnFile.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classSerializerAsObject.kt")
|
||||
public void testClassSerializerAsObject() throws Exception {
|
||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/boxIr/classSerializerAsObject.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("generics.kt")
|
||||
public void testGenerics() throws Exception {
|
||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/boxIr/generics.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("metaSerializable.kt")
|
||||
public void testMetaSerializable() throws Exception {
|
||||
|
||||
Vendored
+78
@@ -0,0 +1,78 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
|
||||
// WITH_STDLIB
|
||||
|
||||
// FILE: a.kt
|
||||
|
||||
package a
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.*
|
||||
|
||||
object MultiplyingIntSerializer : KSerializer<Int> {
|
||||
override val descriptor: SerialDescriptor
|
||||
get() = PrimitiveSerialDescriptor("MultiplyingInt", PrimitiveKind.INT)
|
||||
|
||||
override fun deserialize(decoder: Decoder): Int {
|
||||
return decoder.decodeInt() / 2
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Int) {
|
||||
encoder.encodeInt(value * 2)
|
||||
}
|
||||
}
|
||||
|
||||
data class Cont(val i: Int)
|
||||
|
||||
object ContSerializer: KSerializer<Cont> {
|
||||
override fun deserialize(decoder: Decoder): Cont {
|
||||
return Cont(decoder.decodeInt())
|
||||
}
|
||||
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ContSerializer", PrimitiveKind.INT)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Cont) {
|
||||
encoder.encodeInt(value.i)
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
@file:UseContextualSerialization(Cont::class)
|
||||
@file:UseSerializers(MultiplyingIntSerializer::class)
|
||||
|
||||
package a
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.modules.*
|
||||
|
||||
@Serializable
|
||||
class Holder(
|
||||
val i: Int,
|
||||
val c: Cont
|
||||
)
|
||||
|
||||
fun testOnFile(): String {
|
||||
val j = Json {
|
||||
serializersModule = SerializersModule {
|
||||
contextual(ContSerializer)
|
||||
}
|
||||
}
|
||||
val h = Holder(3, Cont(4))
|
||||
val str = j.encodeToString(
|
||||
Holder.serializer(),
|
||||
h
|
||||
)
|
||||
if ("""{"i":6,"c":4}""" != str) return str
|
||||
val decoded = j.decodeFromString(Holder.serializer(), str)
|
||||
if (decoded.i != h.i) return "i: ${decoded.i}"
|
||||
if (decoded.c.i != h.c.i) return "c.i: ${decoded.c.i}"
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return testOnFile()
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
|
||||
// WITH_STDLIB
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.*
|
||||
|
||||
@Serializable
|
||||
data class Foo<T>(val i: Int, val t: T? = null)
|
||||
|
||||
@Serializable
|
||||
class Holder(val f1: Foo<String>, val f2: Foo<Int>)
|
||||
|
||||
fun box(): String {
|
||||
val holder = Holder(Foo(1, "1"), Foo(2))
|
||||
val str = Json.encodeToString(Holder.serializer(), holder)
|
||||
if (str != """{"f1":{"i":1,"t":"1"},"f2":{"i":2}}""") return str
|
||||
val decoded = Json.decodeFromString(Holder.serializer(), str)
|
||||
if (decoded.f1.t != holder.f1.t) return "f1.t: ${decoded.f1.t}"
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user