Added support of external serializers to the FIR
Co-authored-by: Leonid Startsev <leonid.startsev@jetbrains.com> Merge-request: KT-MR-7334 Merged-by: Sergey Shanshin <Sergey.Shanshin@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
817afcd4af
commit
5a1c2c56bd
@@ -52,6 +52,8 @@ class Fir2IrPluginContext(
|
||||
override val typeTranslator: TypeTranslator
|
||||
get() = error(ERROR_MESSAGE)
|
||||
|
||||
override val afterK2: Boolean = true
|
||||
|
||||
override val languageVersionSettings: LanguageVersionSettings
|
||||
get() = components.session.languageVersionSettings
|
||||
|
||||
|
||||
+5
@@ -34,6 +34,11 @@ annotation class FirIncompatiblePluginAPI(val hint: String = "")
|
||||
interface IrPluginContext : IrGeneratorContext {
|
||||
val languageVersionSettings: LanguageVersionSettings
|
||||
|
||||
/**
|
||||
* Indicates that the plugin works after FIR. Effectively it means that all descriptor-based API may contain incorrect and/or incomplete information, and declarations marked with `@FirIncompatibleApi` will throw runtime exceptions.
|
||||
*/
|
||||
val afterK2: Boolean
|
||||
|
||||
@ObsoleteDescriptorBasedAPI
|
||||
val moduleDescriptor: ModuleDescriptor
|
||||
|
||||
|
||||
+2
@@ -42,6 +42,8 @@ open class IrPluginContextImpl constructor(
|
||||
override val symbols: BuiltinSymbolsBase = BuiltinSymbolsBase(irBuiltIns, st)
|
||||
) : IrPluginContext {
|
||||
|
||||
override val afterK2: Boolean = false
|
||||
|
||||
override val platform: TargetPlatform? = module.platform
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
|
||||
+8
-6
@@ -15,12 +15,9 @@ import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.companionObject
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.bitMaskSlotCount
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.hasCompanionObjectAsSerializer
|
||||
|
||||
/**
|
||||
* Generates only specific declarations, but NOT their bodies.
|
||||
@@ -43,7 +40,12 @@ class IrPreGenerator(
|
||||
private fun preGenerateWriteSelfMethodIfNeeded() {
|
||||
if (!irClass.isInternalSerializable) return
|
||||
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
|
||||
if (!irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SerialEntityNames.SAVE) }) return
|
||||
if (!irClass.shouldHaveSpecificSyntheticMethods {
|
||||
serializerDescriptor.findPluginGeneratedMethod(
|
||||
SerialEntityNames.SAVE,
|
||||
compilerContext.afterK2
|
||||
)
|
||||
}) return
|
||||
if (irClass.findWriteSelfMethod() != null) return
|
||||
val method = irClass.addFunction {
|
||||
name = SerialEntityNames.WRITE_SELF_NAME
|
||||
@@ -95,7 +97,7 @@ class IrPreGenerator(
|
||||
if (!irClass.isInternalSerializable) return
|
||||
// do not add synthetic deserialization constructor if .deserialize method is customized
|
||||
if (irClass.hasCompanionObjectAsSerializer && irClass.companionObject()
|
||||
?.findPluginGeneratedMethod(SerialEntityNames.LOAD) == null
|
||||
?.findPluginGeneratedMethod(SerialEntityNames.LOAD, compilerContext.afterK2) == null
|
||||
) return
|
||||
if (irClass.isValue) return
|
||||
if (irClass.findSerializableSyntheticConstructor() != null) return
|
||||
@@ -133,4 +135,4 @@ class IrPreGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+10
-5
@@ -57,9 +57,9 @@ internal val IrClass.isInternallySerializableObject: Boolean
|
||||
get() = kind == ClassKind.OBJECT && hasSerializableOrMetaAnnotationWithoutArgs()
|
||||
|
||||
|
||||
internal fun IrClass.findPluginGeneratedMethod(name: String): IrSimpleFunction? {
|
||||
internal fun IrClass.findPluginGeneratedMethod(name: String, afterK2: Boolean): IrSimpleFunction? {
|
||||
return this.functions.find {
|
||||
it.name.asString() == name && it.isFromPlugin()
|
||||
it.name.asString() == name && it.isFromPlugin(afterK2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +147,13 @@ fun IrClass.getSuperClassNotAny(): IrClass? {
|
||||
}
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
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 IrDeclaration.isFromPlugin(afterK2: Boolean): Boolean =
|
||||
if (afterK2) {
|
||||
this.origin == IrDeclarationOrigin.GeneratedByPlugin(SerializationPluginKey)
|
||||
} else {
|
||||
// old FE doesn't specify custom origin
|
||||
(this.descriptor as? CallableMemberDescriptor)?.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
}
|
||||
|
||||
internal fun IrConstructor.isSerializationCtor(): Boolean {
|
||||
/*kind == CallableMemberDescriptor.Kind.SYNTHESIZED does not work because DeserializedClassConstructorDescriptor loses its kind*/
|
||||
@@ -248,4 +253,4 @@ fun IrSimpleType.argumentTypesOrUpperBounds(): List<IrType> {
|
||||
}
|
||||
|
||||
internal inline fun IrClass.shouldHaveSpecificSyntheticMethods(functionPresenceChecker: () -> IrSimpleFunction?) =
|
||||
!isValue && (isAbstractOrSealedSerializableClass || functionPresenceChecker() != null)
|
||||
!isValue && (isAbstractOrSealedSerializableClass || functionPresenceChecker() != null)
|
||||
|
||||
+1
-1
@@ -157,7 +157,7 @@ class SerializableCompanionIrGenerator(
|
||||
it.valueParameters.size == 1
|
||||
&& it.valueParameters.first().isVararg
|
||||
&& it.returnType.isKSerializer()
|
||||
&& it.isFromPlugin()
|
||||
&& it.isFromPlugin(compilerContext.afterK2)
|
||||
}?.let { return it }
|
||||
val kSerializerStarType = compilerContext.getClassFromRuntime(SerialEntityNames.KSERIALIZER_CLASS).starProjectedType
|
||||
val f = irClass.addFunction(
|
||||
|
||||
+2
-2
@@ -359,7 +359,7 @@ class SerializableIrGenerator(
|
||||
|
||||
private fun generateSyntheticInternalConstructor() {
|
||||
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
|
||||
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(LOAD) }) {
|
||||
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(LOAD, compilerContext.afterK2) }) {
|
||||
val constrDesc = irClass.constructors.find(IrConstructor::isSerializationCtor) ?: return
|
||||
generateInternalConstructor(constrDesc)
|
||||
}
|
||||
@@ -367,7 +367,7 @@ class SerializableIrGenerator(
|
||||
|
||||
private fun generateSyntheticMethods() {
|
||||
val serializerDescriptor = irClass.classSerializer(compilerContext)?.owner ?: return
|
||||
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SAVE) }) {
|
||||
if (irClass.shouldHaveSpecificSyntheticMethods { serializerDescriptor.findPluginGeneratedMethod(SAVE, compilerContext.afterK2) }) {
|
||||
val func = irClass.findWriteSelfMethod() ?: return
|
||||
func.origin = SERIALIZATION_PLUGIN_ORIGIN
|
||||
generateWriteSelfMethod(func)
|
||||
|
||||
+8
-7
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
|
||||
@@ -63,7 +62,7 @@ open class SerializerIrGenerator(
|
||||
protected val generatedSerialDescPropertyDescriptor = getProperty(
|
||||
SerialEntityNames.SERIAL_DESC_FIELD,
|
||||
{ true }
|
||||
)?.takeIf { it.isFromPlugin() }
|
||||
)?.takeIf { it.isFromPlugin(compilerContext.afterK2) }
|
||||
|
||||
protected val anySerialDescProperty = getProperty(
|
||||
SerialEntityNames.SERIAL_DESC_FIELD,
|
||||
@@ -592,15 +591,17 @@ open class SerializerIrGenerator(
|
||||
val prop = generatedSerialDescPropertyDescriptor?.let { generateSerializableClassProperty(it); true } ?: false
|
||||
if (prop)
|
||||
generateSerialDesc()
|
||||
val save = irClass.findPluginGeneratedMethod(SAVE)?.let { generateSave(it); true } ?: false
|
||||
val load = irClass.findPluginGeneratedMethod(LOAD)?.let { generateLoad(it); true } ?: false
|
||||
irClass.findPluginGeneratedMethod(SerialEntityNames.CHILD_SERIALIZERS_GETTER.identifier)?.let { generateChildSerializersGetter(it) }
|
||||
irClass.findPluginGeneratedMethod(SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER.identifier)
|
||||
val withFir = compilerContext.afterK2
|
||||
val save = irClass.findPluginGeneratedMethod(SAVE, withFir)?.let { generateSave(it); true } ?: false
|
||||
val load = irClass.findPluginGeneratedMethod(LOAD, withFir)?.let { generateLoad(it); true } ?: false
|
||||
irClass.findPluginGeneratedMethod(SerialEntityNames.CHILD_SERIALIZERS_GETTER.identifier, withFir)
|
||||
?.let { generateChildSerializersGetter(it) }
|
||||
irClass.findPluginGeneratedMethod(SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER.identifier, withFir)
|
||||
?.let { generateTypeParamsSerializersGetter(it) }
|
||||
if (!prop && (save || load))
|
||||
generateSerialDesc()
|
||||
if (serializableIrClass.typeParameters.isNotEmpty()) {
|
||||
findSerializerConstructorForTypeArgumentsSerializers(irClass)?.takeIf { it.owner.isFromPlugin() }?.let {
|
||||
findSerializerConstructorForTypeArgumentsSerializers(irClass)?.takeIf { it.owner.isFromPlugin(withFir) }?.let {
|
||||
generateGenericFieldsAndConstructor(it.owner)
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.CompilationException
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrIntrinsicExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl
|
||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.fileParent
|
||||
|
||||
+2
@@ -198,12 +198,14 @@ object SerializationDependencies {
|
||||
}
|
||||
|
||||
object SerializersClassIds {
|
||||
val kSerializerId = ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME)
|
||||
val enumSerializerId = ClassId(SerializationPackages.internalPackageFqName, Name.identifier(SpecialBuiltins.enumSerializer))
|
||||
val polymorphicSerializerId = ClassId(SerializationPackages.packageFqName, Name.identifier(SpecialBuiltins.polymorphicSerializer))
|
||||
val referenceArraySerializerId = ClassId(SerializationPackages.internalPackageFqName, Name.identifier(SpecialBuiltins.referenceArraySerializer))
|
||||
val objectSerializerId = ClassId(SerializationPackages.internalPackageFqName, Name.identifier(SpecialBuiltins.objectSerializer))
|
||||
val sealedSerializerId = ClassId(SerializationPackages.packageFqName, Name.identifier(SpecialBuiltins.sealedSerializer))
|
||||
val contextSerializerId = ClassId(SerializationPackages.packageFqName, Name.identifier(SpecialBuiltins.contextSerializer))
|
||||
val generatedSerializerId = ClassId(SerializationPackages.internalPackageFqName, SerialEntityNames.GENERATED_SERIALIZER_CLASS)
|
||||
}
|
||||
|
||||
fun findStandardKotlinTypeSerializerName(typeName: String?): String? {
|
||||
|
||||
+47
-29
@@ -39,9 +39,8 @@ import org.jetbrains.kotlin.platform.konan.isNative
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_FACTORY_INTERFACE_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||
|
||||
val generatedSerializerClassId = ClassId(SerializationPackages.internalPackageFqName, SerialEntityNames.GENERATED_SERIALIZER_CLASS)
|
||||
val kSerializerClassId = ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME)
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.generatedSerializerId
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializersClassIds.kSerializerId
|
||||
|
||||
class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
|
||||
@@ -62,7 +61,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
with(session) {
|
||||
if (classSymbol.shouldHaveGeneratedMethodsInCompanion && !classSymbol.isSerializableObject)
|
||||
result += SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
|
||||
if (classSymbol.shouldHaveGeneratedSerializer(!runtimeHasEnumSerializerFactory) /* TODO && !classSymbol.hasCompanionObjectAsSerializer*/)
|
||||
if (classSymbol.shouldHaveGeneratedSerializer && !classSymbol.hasCompanionObjectAsSerializer)
|
||||
result += SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||
}
|
||||
|
||||
@@ -85,31 +84,24 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
val classId = classSymbol.classId
|
||||
val result = mutableSetOf<Name>()
|
||||
when (classId.shortClassName) {
|
||||
SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT -> {
|
||||
val origin = classSymbol.origin as? FirDeclarationOrigin.Plugin
|
||||
if (origin?.key == SerializationPluginKey) {
|
||||
result += SpecialNames.INIT
|
||||
result += SerialEntityNames.SERIALIZER_PROVIDER_NAME
|
||||
} else {
|
||||
// TODO: handle user-written companions & named companions
|
||||
}
|
||||
|
||||
val origin = classSymbol.origin as? FirDeclarationOrigin.Plugin
|
||||
|
||||
when {
|
||||
classSymbol.isCompanion && origin?.key == SerializationPluginKey -> {
|
||||
result += SpecialNames.INIT
|
||||
result += SerialEntityNames.SERIALIZER_PROVIDER_NAME
|
||||
}
|
||||
SerialEntityNames.SERIALIZER_CLASS_NAME -> {
|
||||
|
||||
classId.shortClassName == SerialEntityNames.SERIALIZER_CLASS_NAME -> {
|
||||
// TODO: check classSymbol for already added functions
|
||||
// TODO: support user-defined serializers?
|
||||
result += setOf(
|
||||
SpecialNames.INIT,
|
||||
SerialEntityNames.SAVE_NAME,
|
||||
SerialEntityNames.LOAD_NAME,
|
||||
SerialEntityNames.SERIAL_DESC_FIELD_NAME
|
||||
)
|
||||
if (classSymbol.resolvedSuperTypes.any {
|
||||
it.classId == ClassId(
|
||||
SerializationPackages.internalPackageFqName,
|
||||
SerialEntityNames.GENERATED_SERIALIZER_CLASS
|
||||
)
|
||||
}) {
|
||||
if (classSymbol.resolvedSuperTypes.any { it.classId == generatedSerializerId }) {
|
||||
result += SerialEntityNames.CHILD_SERIALIZERS_GETTER
|
||||
|
||||
if (classSymbol.typeParameterSymbols.isNotEmpty()) {
|
||||
@@ -118,7 +110,28 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
}
|
||||
}
|
||||
|
||||
else -> if (with(session) { classSymbol.isSerializableObject }) result += SerialEntityNames.SERIALIZER_PROVIDER_NAME
|
||||
classSymbol.isExternalSerializer -> {
|
||||
if (classSymbol.declarationSymbols.filterIsInstance<FirPropertySymbol>()
|
||||
.none { it.name == SerialEntityNames.SERIAL_DESC_FIELD_NAME }
|
||||
) {
|
||||
result += SerialEntityNames.SERIAL_DESC_FIELD_NAME
|
||||
}
|
||||
|
||||
if (classSymbol.isCompanion) result += SerialEntityNames.SERIALIZER_PROVIDER_NAME
|
||||
|
||||
if (classSymbol.declarationSymbols.filterIsInstance<FirNamedFunctionSymbol>()
|
||||
.none { it.name == SerialEntityNames.SAVE_NAME }
|
||||
) {
|
||||
result += SerialEntityNames.SAVE_NAME // TODO how check parameters?!
|
||||
}
|
||||
if (classSymbol.declarationSymbols.filterIsInstance<FirNamedFunctionSymbol>()
|
||||
.none { it.name == SerialEntityNames.LOAD_NAME }
|
||||
) {
|
||||
result += SerialEntityNames.LOAD_NAME // TODO how check parameters?!
|
||||
}
|
||||
}
|
||||
|
||||
with(session) { classSymbol.isSerializableObject } -> result += SerialEntityNames.SERIALIZER_PROVIDER_NAME
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -135,7 +148,6 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
return targets.singleOrNull() ?: error("Multiple overrides found for ${callableId.callableName}")
|
||||
}
|
||||
|
||||
// TODO: support @Serializer(for)
|
||||
@OptIn(SymbolInternals::class)
|
||||
override fun generateFunctions(callableId: CallableId, context: MemberGenerationContext?): List<FirNamedFunctionSymbol> {
|
||||
val owner = context?.owner ?: return emptyList()
|
||||
@@ -150,7 +162,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
serializableClass ?: return emptyList()
|
||||
return listOf(generateSerializerGetterInCompanion(owner, serializableClass, callableId))
|
||||
}
|
||||
if (owner.name != SerialEntityNames.SERIALIZER_CLASS_NAME) return emptyList()
|
||||
if (!owner.isSerializer) return emptyList()
|
||||
if (callableId.callableName !in setOf(
|
||||
SpecialNames.INIT,
|
||||
SerialEntityNames.SAVE_NAME,
|
||||
@@ -193,14 +205,14 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
valueParameters.addAll(List(serializableClassSymbol.typeParameterSymbols.size) { i ->
|
||||
newSimpleValueParameter(
|
||||
session,
|
||||
kSerializerClassId.constructClassLikeType(arrayOf(parametersAsArguments[i]), false).toFirResolvedTypeRef(),
|
||||
kSerializerId.constructClassLikeType(arrayOf(parametersAsArguments[i]), false).toFirResolvedTypeRef(),
|
||||
Name.identifier("${SerialEntityNames.typeArgPrefix}$i")
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = kSerializerClassId.constructClassLikeType(
|
||||
type = kSerializerId.constructClassLikeType(
|
||||
arrayOf(serializableClassSymbol.constructType(parametersAsArguments, false)),
|
||||
isNullable = false
|
||||
)
|
||||
@@ -212,7 +224,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
@OptIn(SymbolInternals::class)
|
||||
override fun generateProperties(callableId: CallableId, context: MemberGenerationContext?): List<FirPropertySymbol> {
|
||||
val owner = context?.owner ?: return emptyList()
|
||||
if (owner.name != SerialEntityNames.SERIALIZER_CLASS_NAME) return emptyList()
|
||||
if (!owner.isSerializer) return emptyList()
|
||||
if (callableId.callableName != SerialEntityNames.SERIAL_DESC_FIELD_NAME) return emptyList()
|
||||
|
||||
val target = getFromSupertype(callableId, owner) { it.getProperties(callableId.callableName).filterIsInstance<FirPropertySymbol>() }
|
||||
@@ -265,7 +277,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
valueParameters.addAll(owner.typeParameterSymbols.mapIndexed { i, typeParam ->
|
||||
newSimpleValueParameter(
|
||||
session,
|
||||
kSerializerClassId.constructClassLikeType(arrayOf(typeParam.toConeType()), false).toFirResolvedTypeRef(),
|
||||
kSerializerId.constructClassLikeType(arrayOf(typeParam.toConeType()), false).toFirResolvedTypeRef(),
|
||||
Name.identifier("${SerialEntityNames.typeArgPrefix}$i")
|
||||
)
|
||||
})
|
||||
@@ -302,7 +314,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
})
|
||||
|
||||
val parametersAsArguments = typeParameters.map { it.toConeType() }.toTypedArray<ConeTypeProjection>()
|
||||
superTypeRefs += generatedSerializerClassId.constructClassLikeType(
|
||||
superTypeRefs += generatedSerializerId.constructClassLikeType(
|
||||
arrayOf(
|
||||
owner.constructType(
|
||||
parametersAsArguments,
|
||||
@@ -345,6 +357,12 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
register(FirSerializationPredicates.annotatedWithSerializableOrMeta, FirSerializationPredicates.hasMetaAnnotation)
|
||||
}
|
||||
|
||||
private val FirClassSymbol<*>.isSerializer: Boolean
|
||||
get() = name == SerialEntityNames.SERIALIZER_CLASS_NAME || isExternalSerializer
|
||||
|
||||
private val FirClassSymbol<*>.isExternalSerializer: Boolean
|
||||
get() = session.predicateBasedProvider.matches(FirSerializationPredicates.serializerFor, this)
|
||||
|
||||
context(FirSession)
|
||||
@Suppress("IncorrectFormatting") // KTIJ-22227
|
||||
private val FirClassSymbol<*>.companionNeedsSerializerFactory: Boolean
|
||||
|
||||
+35
-2
@@ -7,12 +7,21 @@ package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
|
||||
import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.buildUserTypeFromQualifierParts
|
||||
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.fir.types.constructClassLikeType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationPredicates.serializerFor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||
@@ -36,9 +45,33 @@ class SerializationFirSupertypesExtension(session: FirSession) : FirSupertypeGen
|
||||
val generatedSerializerClassId = ClassId(SerializationPackages.internalPackageFqName, SerialEntityNames.GENERATED_SERIALIZER_CLASS)
|
||||
if (resolvedSupertypes.any { it.type.classId == kSerializerClassId || it.type.classId == generatedSerializerClassId }) return emptyList()
|
||||
|
||||
|
||||
return if (session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration)) {
|
||||
TODO("Support @Serializer(for=...) supertype generation")
|
||||
val getClassArgument = classLikeDeclaration.serializerFor ?: return emptyList()
|
||||
val serializerConeType = resolveConeTypeFromArgument(getClassArgument)
|
||||
|
||||
listOf(
|
||||
buildResolvedTypeRef {
|
||||
type = kSerializerClassId.constructClassLikeType(arrayOf(serializerConeType), isNullable = false)
|
||||
}
|
||||
)
|
||||
} else emptyList()
|
||||
}
|
||||
|
||||
// Function helps to resolve class call from annotation argument to `ConeKotlinType`
|
||||
context(TypeResolveServiceContainer)
|
||||
@Suppress("IncorrectFormatting") // KTIJ-22227
|
||||
private fun resolveConeTypeFromArgument(getClassCall: FirGetClassCall): ConeKotlinType {
|
||||
val typeToResolve = buildUserTypeFromQualifierParts(isMarkedNullable = false) {
|
||||
fun visitQualifiers(expression: FirExpression) {
|
||||
if (expression !is FirPropertyAccessExpression) return
|
||||
expression.explicitReceiver?.let { visitQualifiers(it) }
|
||||
expression.qualifierName?.let { part(it) }
|
||||
}
|
||||
visitQualifiers(getClassCall.argument)
|
||||
}
|
||||
return typeResolver.resolveUserType(typeToResolve).type
|
||||
}
|
||||
|
||||
private val FirPropertyAccessExpression.qualifierName: Name?
|
||||
get() = (calleeReference as? FirSimpleNamedReference)?.name
|
||||
}
|
||||
|
||||
+17
-2
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.arguments
|
||||
@@ -85,6 +86,10 @@ internal val FirBasedSymbol<*>.serializableWith: ConeKotlinType?
|
||||
internal val List<FirAnnotation>.serializableWith: ConeKotlinType?
|
||||
get() = serializableAnnotation()?.getKClassArgument(AnnotationParameterNames.WITH)
|
||||
|
||||
fun FirAnnotation.getGetKClassArgument(name: Name): FirGetClassCall? {
|
||||
return findArgumentByName(name) as? FirGetClassCall
|
||||
}
|
||||
|
||||
internal val FirClassSymbol<*>.serializerAnnotation: FirAnnotation?
|
||||
get() = getAnnotationByClassId(SerializationAnnotations.serializerAnnotationClassId)
|
||||
|
||||
@@ -94,6 +99,15 @@ internal val FirClassSymbol<*>.serializerForClass: ConeKotlinType?
|
||||
.getAnnotationByClassId(SerializationAnnotations.serializerAnnotationClassId)
|
||||
?.getKClassArgument(AnnotationParameterNames.FOR_CLASS)
|
||||
|
||||
internal val FirClassSymbol<*>.serializerFor: FirGetClassCall?
|
||||
get() = resolvedAnnotationsWithArguments
|
||||
.getAnnotationByClassId(SerializationAnnotations.serializerAnnotationClassId)
|
||||
?.getGetKClassArgument(AnnotationParameterNames.FOR_CLASS)
|
||||
|
||||
internal val FirClassLikeDeclaration.serializerFor: FirGetClassCall?
|
||||
get() = getAnnotationByClassId(SerializationAnnotations.serializerAnnotationClassId)
|
||||
?.getGetKClassArgument(AnnotationParameterNames.FOR_CLASS)
|
||||
|
||||
context(FirSession)
|
||||
@Suppress("IncorrectFormatting") // KTIJ-22227
|
||||
internal val FirClassSymbol<*>.isInternallySerializableObject: Boolean
|
||||
@@ -172,7 +186,8 @@ val FirClassSymbol<*>.hasCompanionObjectAsSerializer: Boolean
|
||||
context(FirSession)
|
||||
@Suppress("IncorrectFormatting") // KTIJ-22227
|
||||
val FirClassSymbol<*>.hasCustomSerializerOnCompanion: Boolean
|
||||
get() = (this as? FirRegularClassSymbol)?.companionObjectSymbol?.serializerForClass != null
|
||||
// TODO It was accepted that the annotation on the companion can take only the current class as an argument. Before the release of FIR, we need to add a new annotation and check gere for its presence
|
||||
get() = (this as? FirRegularClassSymbol)?.companionObjectSymbol?.serializerFor != null
|
||||
|
||||
context(FirSession)
|
||||
val FirClassSymbol<*>.isEnumWithLegacyGeneratedSerializer: Boolean
|
||||
@@ -180,7 +195,7 @@ val FirClassSymbol<*>.isEnumWithLegacyGeneratedSerializer: Boolean
|
||||
|
||||
context(FirSession)
|
||||
val FirClassSymbol<*>.shouldHaveGeneratedSerializer: Boolean
|
||||
get() = (isInternalSerializable && (modality == Modality.FINAL || modality == Modality.OPEN)) || isEnumWithLegacyGeneratedSerializer
|
||||
get() = (isInternalSerializable && isFinalOrOpen()) || isEnumWithLegacyGeneratedSerializer
|
||||
|
||||
context(FirSession)
|
||||
@Suppress("IncorrectFormatting") // KTIJ-22227
|
||||
|
||||
+1
-5
@@ -7,9 +7,7 @@ package org.jetbrains.kotlinx.serialization.compiler.fir.checkers
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.descriptors.isEnumClass
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isInlineClass
|
||||
@@ -20,7 +18,6 @@ import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.*
|
||||
@@ -33,7 +30,6 @@ import org.jetbrains.kotlinx.serialization.compiler.fir.services.dependencySeria
|
||||
import org.jetbrains.kotlinx.serialization.compiler.fir.services.findTypeSerializerOrContextUnchecked
|
||||
import org.jetbrains.kotlinx.serialization.compiler.fir.services.serializablePropertiesProvider
|
||||
import org.jetbrains.kotlinx.serialization.compiler.fir.services.versionReader
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||
|
||||
object FirSerializationPluginClassChecker : FirClassChecker() {
|
||||
private val JAVA_SERIALIZABLE_ID = ClassId.topLevel(FqName("java.io.Serializable"))
|
||||
@@ -64,7 +60,7 @@ object FirSerializationPluginClassChecker : FirClassChecker() {
|
||||
private fun checkExternalSerializer(classSymbol: FirClassSymbol<*>, reporter: DiagnosticReporter) {
|
||||
val serializableKType = classSymbol.serializerForClass ?: return
|
||||
val serializableClassSymbol = serializableKType.toRegularClassSymbol(session) ?: return
|
||||
val properties = session.serializablePropertiesProvider.getSerializablePropertiesForClass(classSymbol)
|
||||
val properties = session.serializablePropertiesProvider.getSerializablePropertiesForClass(serializableClassSymbol)
|
||||
if (!properties.isExternallySerializable) {
|
||||
val source = classSymbol.serializerAnnotation?.source ?: classSymbol.source
|
||||
val error = if (serializableClassSymbol.moduleData == session.moduleData) {
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
An operation is not implemented: Support @Serializer(for=...) supertype generation
|
||||
kotlin.NotImplementedError: An operation is not implemented: Support @Serializer(for=...) supertype generation
|
||||
at org.jetbrains.kotlinx.serialization.compiler.fir.SerializationFirSupertypesExtension.computeAdditionalSupertypes(SerializationFirSupertypesExtension.kt:39)
|
||||
@@ -1,9 +0,0 @@
|
||||
// SKIP_TXT
|
||||
|
||||
// FILE: test.kt
|
||||
import kotlinx.serialization.*
|
||||
|
||||
class Foo(i: Int, val j: Int)
|
||||
|
||||
@Serializer(forClass = Foo::class)
|
||||
object ExternalSerializer
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// SKIP_TXT
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// This test enshures that analysis ends up without compiler exceptions
|
||||
|
||||
import kotlinx.serialization.*
|
||||
|
||||
@Serializable
|
||||
class Digest() {
|
||||
@Serializer(forClass = Digest::class)
|
||||
companion <!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object<!> : KSerializer<Digest> {}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// This test enshures that analysis ends up without compiler exceptions
|
||||
|
||||
import kotlinx.serialization.*
|
||||
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
// WITH_STDLIB
|
||||
// SKIP_TXT
|
||||
|
||||
import kotlinx.serialization.*
|
||||
|
||||
class Bar
|
||||
@Serializer(forClass = Bar::class)
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object BarSerializer<!>: KSerializer<Bar>
|
||||
|
||||
class Baz
|
||||
@Serializer(forClass = Baz::class)
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object BazSerializer<!>: KSerializer<Baz>
|
||||
|
||||
@Serializable
|
||||
class Foo1(@Polymorphic val i: Baz)
|
||||
|
||||
@Serializable
|
||||
class Foo2(val li: MutableList<@Serializable(with = BazSerializer::class) Baz>)
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
// SKIP_TXT
|
||||
|
||||
|
||||
+3
-3
@@ -5,13 +5,13 @@ import kotlinx.serialization.*
|
||||
|
||||
class Bar
|
||||
@Serializer(forClass = Bar::class)
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object BarSerializer<!>: KSerializer<Bar>
|
||||
object BarSerializer: KSerializer<Bar>
|
||||
|
||||
class Baz
|
||||
@Serializer(forClass = Baz::class)
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object BazSerializer<!>: KSerializer<Baz>
|
||||
object BazSerializer: KSerializer<Baz>
|
||||
@Serializer(forClass = Baz::class)
|
||||
<!ABSTRACT_MEMBER_NOT_IMPLEMENTED!>object NullableBazSerializer<!>: KSerializer<Baz?>
|
||||
object NullableBazSerializer: KSerializer<Baz?>
|
||||
|
||||
<!SERIALIZER_TYPE_INCOMPATIBLE!>@Serializable(with = BazSerializer::class)<!>
|
||||
class Biz(val i: Int)
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
FILE: externalSerializers.kt
|
||||
package com.example
|
||||
|
||||
public final class Data : R|kotlin/Any| {
|
||||
public constructor(j: R|kotlin/Int|): R|com/example/Data| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val j: R|kotlin/Int| = R|<local>/j|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/Data|)) public final object ObjectSerializer : R|kotlin/Any|, R|kotlinx/serialization/KSerializer<com/example/Data>| {
|
||||
private constructor(): R|com/example/ObjectSerializer| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/Data|): R|kotlin/Unit|
|
||||
|
||||
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/Data|
|
||||
|
||||
}
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/Data|)) public final class ClassSerializer : R|kotlin/Any|, R|kotlinx/serialization/KSerializer<com/example/Data>| {
|
||||
public constructor(): R|com/example/ClassSerializer| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/Data|): R|kotlin/Unit|
|
||||
|
||||
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/Data|
|
||||
|
||||
}
|
||||
public final fun box(): R|kotlin/String| {
|
||||
lval encodedForClass: R|kotlin/String| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.encodeToString|<R|com/example/Data|>(R|com/example/ClassSerializer.ClassSerializer|(), R|com/example/Data.Data|(Int(1)))
|
||||
when () {
|
||||
!=(R|<local>/encodedForClass|, String({"j":1})) -> {
|
||||
^box R|<local>/encodedForClass|
|
||||
}
|
||||
}
|
||||
|
||||
lval encodedForObject: R|kotlin/String| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.encodeToString|<R|com/example/Data|>(Q|com/example/ObjectSerializer|, R|com/example/Data.Data|(Int(2)))
|
||||
when () {
|
||||
!=(R|<local>/encodedForObject|, String({"j":2})) -> {
|
||||
^box R|<local>/encodedForObject|
|
||||
}
|
||||
}
|
||||
|
||||
^box String(OK)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
package com.example
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.encoding.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
|
||||
|
||||
class Data(val j: Int)
|
||||
|
||||
@Serializer(forClass = Data::class)
|
||||
object ObjectSerializer
|
||||
|
||||
@Serializer(forClass = Data::class)
|
||||
class ClassSerializer
|
||||
|
||||
fun box(): String {
|
||||
val encodedForClass = Json.encodeToString(ClassSerializer(), Data(1))
|
||||
if (encodedForClass != """{"j":1}""") return encodedForClass
|
||||
|
||||
val encodedForObject = Json.encodeToString(ObjectSerializer, Data(2))
|
||||
if (encodedForObject != """{"j":2}""") return encodedForObject
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
FILE: serializerViaCompanion.kt
|
||||
package com.example
|
||||
|
||||
@R|kotlinx/serialization/Serializable|() public final data class WithCompanion : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|com/example/WithCompanion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/WithCompanion|)) public final companion object Companion : R|kotlin/Any|, R|kotlinx/serialization/KSerializer<com/example/WithCompanion>| {
|
||||
private constructor(): R|com/example/WithCompanion.Companion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/WithCompanion|): R|kotlin/Unit|
|
||||
|
||||
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/WithCompanion|
|
||||
|
||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<com/example/WithCompanion>|
|
||||
|
||||
}
|
||||
|
||||
public final operator fun component1(): R|kotlin/Int|
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|com/example/WithCompanion|.R|com/example/WithCompanion.i|): R|com/example/WithCompanion|
|
||||
|
||||
}
|
||||
@R|kotlinx/serialization/Serializable|() public final data class WithNamedCompanion : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|com/example/WithNamedCompanion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/WithNamedCompanion|)) public final companion object Named : R|kotlin/Any|, R|kotlinx/serialization/KSerializer<com/example/WithNamedCompanion>| {
|
||||
private constructor(): R|com/example/WithNamedCompanion.Named| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/WithNamedCompanion|): R|kotlin/Unit|
|
||||
|
||||
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/WithNamedCompanion|
|
||||
|
||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<com/example/WithNamedCompanion>|
|
||||
|
||||
}
|
||||
|
||||
public final operator fun component1(): R|kotlin/Int|
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|com/example/WithNamedCompanion|.R|com/example/WithNamedCompanion.i|): R|com/example/WithNamedCompanion|
|
||||
|
||||
}
|
||||
@R|kotlinx/serialization/Serializable|() public final data class WithExplicitType : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|com/example/WithExplicitType| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/WithExplicitType|)) public final companion object Companion : R|kotlinx/serialization/KSerializer<com/example/WithExplicitType>| {
|
||||
private constructor(): R|com/example/WithExplicitType.Companion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/WithExplicitType|): R|kotlin/Unit|
|
||||
|
||||
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/WithExplicitType|
|
||||
|
||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<com/example/WithExplicitType>|
|
||||
|
||||
}
|
||||
|
||||
public final operator fun component1(): R|kotlin/Int|
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|com/example/WithExplicitType|.R|com/example/WithExplicitType.i|): R|com/example/WithExplicitType|
|
||||
|
||||
}
|
||||
@R|kotlinx/serialization/Serializable|() public final data class PartiallyOverridden : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|com/example/PartiallyOverridden| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/PartiallyOverridden|)) public final companion object Companion : R|kotlinx/serialization/KSerializer<com/example/PartiallyOverridden>| {
|
||||
private constructor(): R|com/example/PartiallyOverridden.Companion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final override val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor| = R|kotlinx/serialization/descriptors/buildClassSerialDescriptor|(String(Partially-Overridden), <L> = buildClassSerialDescriptor@fun R|kotlinx/serialization/descriptors/ClassSerialDescriptorBuilder|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||
this@R|special/anonymous|.R|kotlinx/serialization/descriptors/ClassSerialDescriptorBuilder.element|(String(i), R|kotlinx/serialization/descriptors/PrimitiveSerialDescriptor|(String(i), Q|kotlinx/serialization/descriptors/PrimitiveKind.INT|))
|
||||
}
|
||||
)
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final override fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/PartiallyOverridden|): R|kotlin/Unit| {
|
||||
lval compositeOutput: R|kotlinx/serialization/encoding/CompositeEncoder| = R|<local>/encoder|.R|kotlinx/serialization/encoding/Encoder.beginStructure|(Q|com/example/PartiallyOverridden|.R|com/example/PartiallyOverridden.Companion.descriptor|)
|
||||
R|<local>/compositeOutput|.R|kotlinx/serialization/encoding/CompositeEncoder.encodeIntElement|(Q|com/example/PartiallyOverridden|.R|com/example/PartiallyOverridden.Companion.descriptor|, Int(0), R|<local>/value|.R|com/example/PartiallyOverridden.i|.R|kotlin/Int.plus|(Int(10)))
|
||||
R|<local>/compositeOutput|.R|kotlinx/serialization/encoding/CompositeEncoder.endStructure|(Q|com/example/PartiallyOverridden|.R|com/example/PartiallyOverridden.Companion.descriptor|)
|
||||
}
|
||||
|
||||
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/PartiallyOverridden|
|
||||
|
||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<com/example/PartiallyOverridden>|
|
||||
|
||||
}
|
||||
|
||||
public final operator fun component1(): R|kotlin/Int|
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|com/example/PartiallyOverridden|.R|com/example/PartiallyOverridden.i|): R|com/example/PartiallyOverridden|
|
||||
|
||||
}
|
||||
@R|kotlinx/serialization/Serializable|() public final data class PartiallyWithoutType : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|com/example/PartiallyWithoutType| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/PartiallyWithoutType|)) public final companion object Companion : R|kotlin/Any|, R|kotlinx/serialization/KSerializer<com/example/PartiallyWithoutType>| {
|
||||
private constructor(): R|com/example/PartiallyWithoutType.Companion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final override fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/PartiallyWithoutType| {
|
||||
lval dec: R|kotlinx/serialization/encoding/CompositeDecoder| = R|<local>/decoder|.R|kotlinx/serialization/encoding/Decoder.beginStructure|(this@R|com/example/PartiallyWithoutType.Companion|.R|com/example/PartiallyWithoutType.Companion.descriptor|)
|
||||
lvar iv: R|kotlin/Int?| = Null(null)
|
||||
loop@while(Boolean(true)) {
|
||||
when (lval i: R|kotlin/Int| = R|<local>/dec|.R|kotlinx/serialization/encoding/CompositeDecoder.decodeElementIndex|(this@R|com/example/PartiallyWithoutType.Companion|.R|com/example/PartiallyWithoutType.Companion.descriptor|)) {
|
||||
==($subj$, Q|kotlinx/serialization/encoding/CompositeDecoder|.R|kotlinx/serialization/encoding/CompositeDecoder.Companion.DECODE_DONE|) -> {
|
||||
break@@@[Boolean(true)]
|
||||
}
|
||||
==($subj$, Int(0)) -> {
|
||||
R|<local>/iv| = R|<local>/dec|.R|kotlinx/serialization/encoding/CompositeDecoder.decodeIntElement|(this@R|com/example/PartiallyWithoutType.Companion|.R|com/example/PartiallyWithoutType.Companion.descriptor|, R|<local>/i|)
|
||||
}
|
||||
else -> {
|
||||
throw R|kotlinx/serialization/SerializationException.SerializationException|(<strcat>(String(Unknown index ), R|<local>/i|))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
R|<local>/dec|.R|kotlinx/serialization/encoding/CompositeDecoder.endStructure|(this@R|com/example/PartiallyWithoutType.Companion|.R|com/example/PartiallyWithoutType.Companion.descriptor|)
|
||||
^deserialize R|com/example/PartiallyWithoutType.PartiallyWithoutType|(R|<local>/iv|!!.R|kotlin/Int.plus|(Int(10)))
|
||||
}
|
||||
|
||||
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/PartiallyWithoutType|): R|kotlin/Unit|
|
||||
|
||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<com/example/PartiallyWithoutType>|
|
||||
|
||||
}
|
||||
|
||||
public final operator fun component1(): R|kotlin/Int|
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|com/example/PartiallyWithoutType|.R|com/example/PartiallyWithoutType.i|): R|com/example/PartiallyWithoutType|
|
||||
|
||||
}
|
||||
@R|kotlinx/serialization/Serializable|() public final data class FullyOverridden : R|kotlin/Any| {
|
||||
public constructor(i: R|kotlin/Int|): R|com/example/FullyOverridden| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||
public get(): R|kotlin/Int|
|
||||
|
||||
@R|kotlinx/serialization/Serializer|(forClass = <getClass>(Q|com/example/FullyOverridden|)) public final companion object Companion : R|kotlinx/serialization/KSerializer<com/example/FullyOverridden>| {
|
||||
private constructor(): R|com/example/FullyOverridden.Companion| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final override val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor| = R|kotlinx/serialization/descriptors/PrimitiveSerialDescriptor|(String(FullyOverridden), Q|kotlinx/serialization/descriptors/PrimitiveKind.STRING|)
|
||||
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||
|
||||
public final override fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|com/example/FullyOverridden|): R|kotlin/Unit| {
|
||||
R|<local>/encoder|.R|kotlinx/serialization/encoding/Encoder.encodeString|(<strcat>(String(i=), R|<local>/value|.R|com/example/FullyOverridden.i|))
|
||||
}
|
||||
|
||||
public final override fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|com/example/FullyOverridden| {
|
||||
lval i: R|kotlin/Int| = R|<local>/decoder|.R|kotlinx/serialization/encoding/Decoder.decodeString|().R|kotlin/text/substringAfter|(Char(=)).R|kotlin/text/toInt|()
|
||||
^deserialize R|com/example/FullyOverridden.FullyOverridden|(R|<local>/i|)
|
||||
}
|
||||
|
||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<com/example/FullyOverridden>|
|
||||
|
||||
}
|
||||
|
||||
public final operator fun component1(): R|kotlin/Int|
|
||||
|
||||
public final fun copy(i: R|kotlin/Int| = this@R|com/example/FullyOverridden|.R|com/example/FullyOverridden.i|): R|com/example/FullyOverridden|
|
||||
|
||||
}
|
||||
public final fun box(): R|kotlin/String| {
|
||||
R|com/example/encodeAndDecode|<R|com/example/WithCompanion|>(Q|com/example/WithCompanion|.R|com/example/WithCompanion.Companion.serializer|(), R|com/example/WithCompanion.WithCompanion|(Int(1)), String({"i":1}))?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^box R|<local>/it|
|
||||
}
|
||||
) }
|
||||
R|com/example/encodeAndDecode|<R|com/example/WithNamedCompanion|>(Q|com/example/WithNamedCompanion|.R|com/example/WithNamedCompanion.Named.serializer|(), R|com/example/WithNamedCompanion.WithNamedCompanion|(Int(2)), String({"i":2}))?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^box R|<local>/it|
|
||||
}
|
||||
) }
|
||||
R|com/example/encodeAndDecode|<R|com/example/WithExplicitType|>(Q|com/example/WithExplicitType|.R|com/example/WithExplicitType.Companion.serializer|(), R|com/example/WithExplicitType.WithExplicitType|(Int(3)), String({"i":3}))?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^box R|<local>/it|
|
||||
}
|
||||
) }
|
||||
R|com/example/encodeAndDecode|<R|com/example/FullyOverridden|>(Q|com/example/FullyOverridden|.R|com/example/FullyOverridden.Companion.serializer|(), R|com/example/FullyOverridden.FullyOverridden|(Int(4)), String("i=4"))?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^box R|<local>/it|
|
||||
}
|
||||
) }
|
||||
R|com/example/encodeAndDecode|<R|com/example/PartiallyOverridden|>(Q|com/example/PartiallyOverridden|.R|com/example/PartiallyOverridden.Companion.serializer|(), R|com/example/PartiallyOverridden.PartiallyOverridden|(Int(5)), String({"i":15}), R|com/example/PartiallyOverridden.PartiallyOverridden|(Int(15)))?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^box R|<local>/it|
|
||||
}
|
||||
) }
|
||||
when () {
|
||||
!=(Q|com/example/PartiallyOverridden|.R|com/example/PartiallyOverridden.Companion.serializer|().R|SubstitutionOverride<kotlinx/serialization/KSerializer.descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|>|.R|kotlinx/serialization/descriptors/SerialDescriptor.serialName|, String(Partially-Overridden)) -> {
|
||||
^box Q|com/example/PartiallyOverridden|.R|com/example/PartiallyOverridden.Companion.serializer|().R|SubstitutionOverride<kotlinx/serialization/KSerializer.descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|>|.R|kotlinx/serialization/descriptors/SerialDescriptor.serialName|
|
||||
}
|
||||
}
|
||||
|
||||
R|com/example/encodeAndDecode|<R|com/example/PartiallyWithoutType|>(Q|com/example/PartiallyWithoutType|.R|com/example/PartiallyWithoutType.Companion.serializer|(), R|com/example/PartiallyWithoutType.PartiallyWithoutType|(Int(6)), String({"i":6}), R|com/example/PartiallyWithoutType.PartiallyWithoutType|(Int(16)))?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^box R|<local>/it|
|
||||
}
|
||||
) }
|
||||
when () {
|
||||
!=(Q|com/example/PartiallyWithoutType|.R|com/example/PartiallyWithoutType.Companion.serializer|().R|SubstitutionOverride<kotlinx/serialization/KSerializer.descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|>|.R|kotlinx/serialization/descriptors/SerialDescriptor.serialName|, <getClass>(Q|com/example/PartiallyWithoutType|).R|SubstitutionOverride<kotlin/reflect/KClass.qualifiedName: R|kotlin/String?|>|) -> {
|
||||
^box Q|com/example/PartiallyWithoutType|.R|com/example/PartiallyWithoutType.Companion.serializer|().R|SubstitutionOverride<kotlinx/serialization/KSerializer.descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|>|.R|kotlinx/serialization/descriptors/SerialDescriptor.serialName|
|
||||
}
|
||||
}
|
||||
|
||||
^box String(OK)
|
||||
}
|
||||
private final fun <T> encodeAndDecode(serializer: R|kotlinx/serialization/KSerializer<T>|, value: R|T|, expectedEncoded: R|kotlin/String|, expectedDecoded: R|T?| = Null(null)): R|kotlin/String?| {
|
||||
lval encoded: R|kotlin/String| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.encodeToString|<R|T|>(R|<local>/serializer|, R|<local>/value|)
|
||||
when () {
|
||||
!=(R|<local>/encoded|, R|<local>/expectedEncoded|) -> {
|
||||
^encodeAndDecode R|<local>/encoded|
|
||||
}
|
||||
}
|
||||
|
||||
lval decoded: R|T| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.decodeFromString|<R|T|>(R|<local>/serializer|, R|<local>/encoded|)
|
||||
when () {
|
||||
!=(R|<local>/decoded|, R|<local>/expectedDecoded| ?: R|<local>/value|) -> {
|
||||
^encodeAndDecode <strcat>(String(DECODED=), R|<local>/decoded|.R|kotlin/toString|())
|
||||
}
|
||||
}
|
||||
|
||||
^encodeAndDecode Null(null)
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
package com.example
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.encoding.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
|
||||
|
||||
@Serializable
|
||||
data class WithCompanion(val i: Int) {
|
||||
@Serializer(forClass = WithCompanion::class)
|
||||
companion object
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class WithNamedCompanion(val i: Int) {
|
||||
@Serializer(forClass = WithNamedCompanion::class)
|
||||
companion object Named
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class WithExplicitType(val i: Int) {
|
||||
@Serializer(forClass = WithExplicitType::class)
|
||||
companion object : KSerializer<WithExplicitType>
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class PartiallyOverridden(val i: Int) {
|
||||
@Serializer(forClass = PartiallyOverridden::class)
|
||||
companion object : KSerializer<PartiallyOverridden> {
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Partially-Overridden") {
|
||||
element("i", PrimitiveSerialDescriptor("i", PrimitiveKind.INT))
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: PartiallyOverridden) {
|
||||
val compositeOutput = encoder.beginStructure(PartiallyOverridden.descriptor)
|
||||
compositeOutput.encodeIntElement(PartiallyOverridden.descriptor, 0, value.i + 10)
|
||||
compositeOutput.endStructure(PartiallyOverridden.descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class PartiallyWithoutType(val i: Int) {
|
||||
@Serializer(forClass = PartiallyWithoutType::class)
|
||||
companion object {
|
||||
|
||||
override fun deserialize(decoder: Decoder): PartiallyWithoutType {
|
||||
val dec: CompositeDecoder = decoder.beginStructure(descriptor)
|
||||
var iv: Int? = null
|
||||
loop@ while (true) {
|
||||
when (val i = dec.decodeElementIndex(descriptor)) {
|
||||
CompositeDecoder.DECODE_DONE -> break@loop
|
||||
0 -> iv = dec.decodeIntElement(descriptor, i)
|
||||
else -> throw SerializationException("Unknown index $i")
|
||||
}
|
||||
}
|
||||
dec.endStructure(descriptor)
|
||||
return PartiallyWithoutType(iv!! + 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class FullyOverridden(val i: Int) {
|
||||
@Serializer(forClass = FullyOverridden::class)
|
||||
companion object : KSerializer<FullyOverridden> {
|
||||
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("FullyOverridden", PrimitiveKind.STRING)
|
||||
|
||||
override fun serialize(encoder: Encoder, value: FullyOverridden) {
|
||||
encoder.encodeString("i=${value.i}")
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): FullyOverridden {
|
||||
val i = decoder.decodeString().substringAfter('=').toInt()
|
||||
return FullyOverridden(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun box(): String {
|
||||
encodeAndDecode(WithCompanion.serializer(), WithCompanion(1), """{"i":1}""")?.let { return it }
|
||||
|
||||
encodeAndDecode(WithNamedCompanion.serializer(), WithNamedCompanion(2), """{"i":2}""")?.let { return it }
|
||||
|
||||
encodeAndDecode(WithExplicitType.serializer(), WithExplicitType(3), """{"i":3}""")?.let { return it }
|
||||
|
||||
encodeAndDecode(FullyOverridden.serializer(), FullyOverridden(4), "\"i=4\"")?.let { return it }
|
||||
|
||||
encodeAndDecode(PartiallyOverridden.serializer(), PartiallyOverridden(5), """{"i":15}""", PartiallyOverridden(15))?.let { return it }
|
||||
if (PartiallyOverridden.serializer().descriptor.serialName != "Partially-Overridden") return PartiallyOverridden.serializer().descriptor.serialName
|
||||
|
||||
encodeAndDecode(PartiallyWithoutType.serializer(), PartiallyWithoutType(6), """{"i":6}""", PartiallyWithoutType(16))?.let { return it }
|
||||
if (PartiallyWithoutType.serializer().descriptor.serialName != PartiallyWithoutType::class.qualifiedName) return PartiallyWithoutType.serializer().descriptor.serialName
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
|
||||
private fun <T> encodeAndDecode(serializer: KSerializer<T>, value: T, expectedEncoded: String, expectedDecoded: T? = null): String? {
|
||||
val encoded = Json.encodeToString(serializer, value)
|
||||
if (encoded != expectedEncoded) return encoded
|
||||
|
||||
val decoded = Json.decodeFromString(serializer, encoded)
|
||||
if (decoded != (expectedDecoded ?: value)) return "DECODED=${decoded.toString()}"
|
||||
return null
|
||||
}
|
||||
+12
@@ -151,6 +151,12 @@ public class SerializationFirBlackBoxTestGenerated extends AbstractSerialization
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/enums.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("externalSerializers.kt")
|
||||
public void testExternalSerializers() throws Exception {
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/externalSerializers.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
@@ -186,5 +192,11 @@ public class SerializationFirBlackBoxTestGenerated extends AbstractSerialization
|
||||
public void testSerializableWith() throws Exception {
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/serializableWith.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("serializerViaCompanion.kt")
|
||||
public void testSerializerViaCompanion() throws Exception {
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/serializerViaCompanion.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -174,6 +174,12 @@ public class SerializationFirDiagnosticTestGenerated extends AbstractSerializati
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/enums.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("externalSerializers.kt")
|
||||
public void testExternalSerializers() throws Exception {
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/externalSerializers.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
@@ -209,5 +215,11 @@ public class SerializationFirDiagnosticTestGenerated extends AbstractSerializati
|
||||
public void testSerializableWith() throws Exception {
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/serializableWith.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("serializerViaCompanion.kt")
|
||||
public void testSerializerViaCompanion() throws Exception {
|
||||
runTest("plugins/kotlinx-serialization/testData/firMembers/serializerViaCompanion.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user