Support full pipeline for basic kotlinx.serialization case:
FIR frontend and IR backend plugins. Note: IR plugin is now broken for old FE, fixed in subsequent commits
This commit is contained in:
@@ -148,6 +148,7 @@ class Fir2IrPluginContext(private val components: Fir2IrComponents) : IrPluginCo
|
|||||||
error(ERROR_MESSAGE)
|
error(ERROR_MESSAGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use classId overload instead")
|
||||||
override fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol> {
|
override fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol> {
|
||||||
error(ERROR_MESSAGE)
|
error(ERROR_MESSAGE)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -54,6 +54,7 @@ interface IrPluginContext : IrGeneratorContext {
|
|||||||
@Deprecated("Use classId overload instead")
|
@Deprecated("Use classId overload instead")
|
||||||
fun referenceClass(fqName: FqName): IrClassSymbol?
|
fun referenceClass(fqName: FqName): IrClassSymbol?
|
||||||
fun referenceTypeAlias(fqName: FqName): IrTypeAliasSymbol?
|
fun referenceTypeAlias(fqName: FqName): IrTypeAliasSymbol?
|
||||||
|
@Deprecated("Use classId overload instead")
|
||||||
fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol>
|
fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol>
|
||||||
@Deprecated("Use callableId overload instead")
|
@Deprecated("Use callableId overload instead")
|
||||||
fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol>
|
fun referenceFunctions(fqName: FqName): Collection<IrSimpleFunctionSymbol>
|
||||||
|
|||||||
+2
@@ -121,6 +121,7 @@ open class IrPluginContextImpl constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use classId overload instead")
|
||||||
override fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol> {
|
override fun referenceConstructors(classFqn: FqName): Collection<IrConstructorSymbol> {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
val classSymbol = referenceClass(classFqn) ?: error("Cannot find class $classFqn")
|
val classSymbol = referenceClass(classFqn) ?: error("Cannot find class $classFqn")
|
||||||
@@ -157,6 +158,7 @@ open class IrPluginContextImpl constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun referenceConstructors(classId: ClassId): Collection<IrConstructorSymbol> {
|
override fun referenceConstructors(classId: ClassId): Collection<IrConstructorSymbol> {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
return referenceConstructors(classId.asSingleFqName())
|
return referenceConstructors(classId.asSingleFqName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -294,6 +294,7 @@ internal fun IrPluginContext.getArrayConstructorSymbol(
|
|||||||
): IrConstructorSymbol {
|
): IrConstructorSymbol {
|
||||||
val jsArrayName = irType.getArrayClassFqName()
|
val jsArrayName = irType.getArrayClassFqName()
|
||||||
return try {
|
return try {
|
||||||
|
@Suppress("DEPRECATION") // caution: referenceConstructors(fqName) doesn't work with FIR
|
||||||
referenceConstructors(jsArrayName).single(predicate)
|
referenceConstructors(jsArrayName).single(predicate)
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
error("Array constructor $jsArrayName matching the predicate was not found in the context")
|
error("Array constructor $jsArrayName matching the predicate was not found in the context")
|
||||||
|
|||||||
+6
-1
@@ -10,6 +10,9 @@ import org.jetbrains.kotlin.codegen.CompilationException
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
@@ -323,4 +326,6 @@ internal fun IrConstructor.isSerializationCtor(): Boolean {
|
|||||||
SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
||||||
)
|
)
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun IrExpression.isInitializePropertyFromParameter(): Boolean = this is IrGetValueImpl && this.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||||
+7
-7
@@ -742,12 +742,12 @@ interface IrBuilderExtension {
|
|||||||
fun IrBuilderWithScope.classReference(classSymbol: IrType): IrClassReference =
|
fun IrBuilderWithScope.classReference(classSymbol: IrType): IrClassReference =
|
||||||
createClassReference(classSymbol, startOffset, endOffset)
|
createClassReference(classSymbol, startOffset, endOffset)
|
||||||
|
|
||||||
private fun extractDefaultValuesFromConstructor(irClass: IrClass?): Map<ParameterDescriptor, IrExpression?> {
|
private fun extractDefaultValuesFromConstructor(irClass: IrClass?): Map<IrValueSymbol, IrExpression?> {
|
||||||
if (irClass == null) return emptyMap()
|
if (irClass == null) return emptyMap()
|
||||||
val original = irClass.constructors.singleOrNull { it.isPrimary }
|
val original = irClass.constructors.singleOrNull { it.isPrimary }
|
||||||
// default arguments of original constructor
|
// default arguments of original constructor
|
||||||
val defaultsMap: Map<ParameterDescriptor, IrExpression?> =
|
val defaultsMap: Map<IrValueSymbol, IrExpression?> =
|
||||||
original?.valueParameters?.associate { it.descriptor to it.defaultValue?.expression } ?: emptyMap()
|
original?.valueParameters?.associate { it.symbol to it.defaultValue?.expression } ?: emptyMap()
|
||||||
return defaultsMap + extractDefaultValuesFromConstructor(irClass.getSuperClassNotAny())
|
return defaultsMap + extractDefaultValuesFromConstructor(irClass.getSuperClassNotAny())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,9 +783,9 @@ interface IrBuilderExtension {
|
|||||||
return fun(initializer: IrExpressionBody): IrExpression {
|
return fun(initializer: IrExpressionBody): IrExpression {
|
||||||
val rawExpression = initializer.expression
|
val rawExpression = initializer.expression
|
||||||
val expression =
|
val expression =
|
||||||
if (rawExpression is IrGetValueImpl && rawExpression.origin == IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER) {
|
if (rawExpression.isInitializePropertyFromParameter()) {
|
||||||
// this is a primary constructor property, use corresponding default of value parameter
|
// this is a primary constructor property, use corresponding default of value parameter
|
||||||
defaultsMap.getValue(rawExpression.symbol.descriptor as ParameterDescriptor)!!
|
defaultsMap.getValue((rawExpression as IrGetValue).symbol)!!
|
||||||
} else {
|
} else {
|
||||||
rawExpression
|
rawExpression
|
||||||
}
|
}
|
||||||
@@ -1252,8 +1252,8 @@ interface IrBuilderExtension {
|
|||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun serializableSyntheticConstructor(forClass: IrClass): IrConstructorSymbol {
|
fun serializableSyntheticConstructor(forClass: IrClass): IrConstructorSymbol? { // todo: remove this W/A when FIR plugin will add proper ctor
|
||||||
return forClass.declarations.filterIsInstance<IrConstructor>().single { it.isSerializationCtor() }.symbol
|
return forClass.declarations.filterIsInstance<IrConstructor>().singleOrNull { it.isSerializationCtor() }?.symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrClass.getSuperClassOrAny(): IrClass = getSuperClassNotAny() ?: compilerContext.irBuiltIns.anyClass.owner
|
fun IrClass.getSuperClassOrAny(): IrClass = getSuperClassNotAny() ?: compilerContext.irBuiltIns.anyClass.owner
|
||||||
|
|||||||
+4
-5
@@ -105,8 +105,7 @@ class SerializableIrGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Missing field exception parts
|
// Missing field exception parts
|
||||||
val exceptionFqn = getSerializationPackageFqn(MISSING_FIELD_EXC)
|
val exceptionCtorRef = compilerContext.referenceConstructors(ClassId(SerializationPackages.packageFqName, Name.identifier(MISSING_FIELD_EXC)))
|
||||||
val exceptionCtorRef = compilerContext.referenceConstructors(exceptionFqn)
|
|
||||||
.single { it.owner.valueParameters.singleOrNull()?.type?.isString() == true }
|
.single { it.owner.valueParameters.singleOrNull()?.type?.isString() == true }
|
||||||
val exceptionType = exceptionCtorRef.owner.returnType
|
val exceptionType = exceptionCtorRef.owner.returnType
|
||||||
|
|
||||||
@@ -230,8 +229,8 @@ class SerializableIrGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression {
|
private fun IrBlockBodyBuilder.getInstantiateDescriptorExpr(): IrExpression {
|
||||||
val classConstructors = compilerContext.referenceConstructors(serialDescriptorImplClass.kotlinFqName) //todo: remove reference
|
val classConstructors = serialDescriptorImplClass.constructors //todo: remove reference
|
||||||
val serialClassDescImplCtor = classConstructors.single { it.owner.isPrimary }
|
val serialClassDescImplCtor = classConstructors.single { it.isPrimary }.symbol
|
||||||
return irInvoke(
|
return irInvoke(
|
||||||
null, serialClassDescImplCtor,
|
null, serialClassDescImplCtor,
|
||||||
irString(irClass.serialName()), irNull(), irInt(properties.serializableProperties.size)
|
irString(irClass.serialName()), irNull(), irInt(properties.serializableProperties.size)
|
||||||
@@ -282,7 +281,7 @@ class SerializableIrGenerator(
|
|||||||
propertiesStart: Int
|
propertiesStart: Int
|
||||||
): Int {
|
): Int {
|
||||||
check(superClass.isInternalSerializable)
|
check(superClass.isInternalSerializable)
|
||||||
val superCtorRef = serializableSyntheticConstructor(superClass)
|
val superCtorRef = serializableSyntheticConstructor(superClass)!!
|
||||||
val superProperties = bindingContext.serializablePropertiesFor(superClass.descriptor).serializableProperties
|
val superProperties = bindingContext.serializablePropertiesFor(superClass.descriptor).serializableProperties
|
||||||
val superSlots = superProperties.bitMaskSlotCount()
|
val superSlots = superProperties.bitMaskSlotCount()
|
||||||
val arguments = allValueParameters.subList(0, superSlots) +
|
val arguments = allValueParameters.subList(0, superSlots) +
|
||||||
|
|||||||
+8
-6
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
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.hasDefaultValue
|
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
|
||||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -34,6 +36,7 @@ import org.jetbrains.kotlinx.serialization.compiler.fir.SerializationPluginKey
|
|||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
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.DECODER_CLASS
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENCODER_CLASS
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.LOAD
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SAVE
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SAVE
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.STRUCTURE_DECODER_CLASS
|
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.STRUCTURE_ENCODER_CLASS
|
||||||
@@ -458,8 +461,7 @@ open class SerializerIrGenerator(
|
|||||||
|
|
||||||
// throw exception on unknown field
|
// throw exception on unknown field
|
||||||
|
|
||||||
val exceptionFqn = getSerializationPackageFqn(UNKNOWN_FIELD_EXC)
|
val excClassRef = compilerContext.referenceConstructors(ClassId(SerializationPackages.packageFqName, Name.identifier(UNKNOWN_FIELD_EXC)))
|
||||||
val excClassRef = compilerContext.referenceConstructors(exceptionFqn)
|
|
||||||
.single { it.owner.valueParameters.singleOrNull()?.type?.isInt() == true }
|
.single { it.owner.valueParameters.singleOrNull()?.type?.isInt() == true }
|
||||||
+elseBranch(
|
+elseBranch(
|
||||||
irThrow(
|
irThrow(
|
||||||
@@ -485,11 +487,11 @@ open class SerializerIrGenerator(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val typeArgs = (loadFunc.returnType as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
|
val typeArgs = (loadFunc.returnType as IrSimpleType).arguments.map { (it as IrTypeProjection).type }
|
||||||
if (serializableIrClass.isInternalSerializable) {
|
val deserCtor: IrConstructorSymbol? = serializableSyntheticConstructor(serializableIrClass)
|
||||||
|
if (serializableIrClass.isInternalSerializable && deserCtor != null) {
|
||||||
var args: List<IrExpression> = serializableProperties.map { serialPropertiesMap.getValue(it.descriptor).get() }
|
var args: List<IrExpression> = serializableProperties.map { serialPropertiesMap.getValue(it.descriptor).get() }
|
||||||
args = bitMasks.map { irGet(it) } + args + irNull()
|
args = bitMasks.map { irGet(it) } + args + irNull()
|
||||||
val ctor: IrConstructorSymbol = serializableSyntheticConstructor(serializableIrClass)
|
+irReturn(irInvoke(null, deserCtor, typeArgs, args))
|
||||||
+irReturn(irInvoke(null, ctor, typeArgs, args))
|
|
||||||
} else {
|
} else {
|
||||||
if (irClass.isLocal) {
|
if (irClass.isLocal) {
|
||||||
// if the serializer is local, then the serializable class too, since they must be in the same scope
|
// if the serializer is local, then the serializable class too, since they must be in the same scope
|
||||||
@@ -592,7 +594,7 @@ open class SerializerIrGenerator(
|
|||||||
if (prop)
|
if (prop)
|
||||||
generateSerialDesc()
|
generateSerialDesc()
|
||||||
val save = irClass.findPluginGeneratedMethod(SAVE)?.let { generateSave(it); true } ?: false
|
val save = irClass.findPluginGeneratedMethod(SAVE)?.let { generateSave(it); true } ?: false
|
||||||
val load = 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.CHILD_SERIALIZERS_GETTER.identifier)?.let { generateChildSerializersGetter(it) }
|
||||||
irClass.findPluginGeneratedMethod(SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER.identifier)?.let { generateTypeParamsSerializersGetter(it) }
|
irClass.findPluginGeneratedMethod(SerialEntityNames.TYPE_PARAMS_SERIALIZERS_GETTER.identifier)?.let { generateTypeParamsSerializersGetter(it) }
|
||||||
if (!prop && (save || load))
|
if (!prop && (save || load))
|
||||||
|
|||||||
+3
-1
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.getName
|
import org.jetbrains.kotlin.serialization.deserialization.getName
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.isInterface
|
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext.isInterface
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInitializePropertyFromParameter
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInternalSerializable
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInternalSerializable
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInternallySerializableEnum
|
import org.jetbrains.kotlinx.serialization.compiler.backend.common.isInternallySerializableEnum
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES
|
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES
|
||||||
@@ -227,9 +228,10 @@ internal fun BindingContext?.serializablePropertiesForIrBackend(
|
|||||||
it,
|
it,
|
||||||
isConstructorParameterWithDefault,
|
isConstructorParameterWithDefault,
|
||||||
it.backingField != null,
|
it.backingField != null,
|
||||||
it.backingField?.initializer != null || isConstructorParameterWithDefault
|
it.backingField?.initializer.let { init -> init != null && !init.expression.isInitializePropertyFromParameter() } || isConstructorParameterWithDefault
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.filterNot { it.transient }
|
||||||
.partition { primaryParamsAsProps.contains(it.descriptor) }
|
.partition { primaryParamsAsProps.contains(it.descriptor) }
|
||||||
|
|
||||||
val serializableProps = run {
|
val serializableProps = run {
|
||||||
|
|||||||
+8
-3
@@ -26,6 +26,8 @@ import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationExtensio
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractSerializationFirMembersTest: AbstractKotlinCompilerTest() {
|
abstract class AbstractSerializationFirMembersTest: AbstractKotlinCompilerTest() {
|
||||||
|
private val librariesList = listOf(getSerializationCoreLibraryJar()!!, getSerializationLibraryJar("kotlinx.serialization.json.Json")!!)
|
||||||
|
|
||||||
override fun TestConfigurationBuilder.configuration() {
|
override fun TestConfigurationBuilder.configuration() {
|
||||||
baseFirDiagnosticTestConfiguration()
|
baseFirDiagnosticTestConfiguration()
|
||||||
|
|
||||||
@@ -34,22 +36,25 @@ abstract class AbstractSerializationFirMembersTest: AbstractKotlinCompilerTest()
|
|||||||
+FirDiagnosticsDirectives.FIR_DUMP
|
+FirDiagnosticsDirectives.FIR_DUMP
|
||||||
}
|
}
|
||||||
|
|
||||||
configureForKotlinxSerialization(listOf(getSerializationCoreLibraryJar()!!)) {
|
configureForKotlinxSerialization(librariesList) {
|
||||||
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
|
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open class AbstractSerializationFirBlackBoxTest : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) {
|
open class AbstractSerializationFirBlackBoxTest : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) {
|
||||||
|
|
||||||
|
private val librariesList = listOf(getSerializationCoreLibraryJar()!!, getSerializationLibraryJar("kotlinx.serialization.json.Json")!!)
|
||||||
|
|
||||||
override fun TestConfigurationBuilder.configuration() {
|
override fun TestConfigurationBuilder.configuration() {
|
||||||
baseFirDiagnosticTestConfiguration()
|
baseFirDiagnosticTestConfiguration()
|
||||||
configureForKotlinxSerialization(listOf(getSerializationCoreLibraryJar()!!)) {
|
configureForKotlinxSerialization(librariesList) {
|
||||||
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
|
FirExtensionRegistrarAdapter.registerExtension(FirSerializationExtensionRegistrar())
|
||||||
}
|
}
|
||||||
useCustomRuntimeClasspathProviders({ ts ->
|
useCustomRuntimeClasspathProviders({ ts ->
|
||||||
object : RuntimeClasspathProvider(ts) {
|
object : RuntimeClasspathProvider(ts) {
|
||||||
override fun runtimeClassPaths(module: TestModule): List<File> {
|
override fun runtimeClassPaths(module: TestModule): List<File> {
|
||||||
return listOf(getSerializationCoreLibraryJar()!!)
|
return librariesList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+12
@@ -30,4 +30,16 @@ public class SerializationFirBlackBoxTestGenerated extends AbstractSerialization
|
|||||||
public void testClassWithCompanionObject() throws Exception {
|
public void testClassWithCompanionObject() throws Exception {
|
||||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/classWithCompanionObject.kt");
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/classWithCompanionObject.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("defaultProperties.kt")
|
||||||
|
public void testDefaultProperties() throws Exception {
|
||||||
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/defaultProperties.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleProperties.kt")
|
||||||
|
public void testMultipleProperties() throws Exception {
|
||||||
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/multipleProperties.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
@@ -29,4 +29,16 @@ public class SerializationFirMembersTestGenerated extends AbstractSerializationF
|
|||||||
public void testClassWithCompanionObject() throws Exception {
|
public void testClassWithCompanionObject() throws Exception {
|
||||||
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/classWithCompanionObject.kt");
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/classWithCompanionObject.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("defaultProperties.kt")
|
||||||
|
public void testDefaultProperties() throws Exception {
|
||||||
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/defaultProperties.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("multipleProperties.kt")
|
||||||
|
public void testMultipleProperties() throws Exception {
|
||||||
|
runTest("plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/multipleProperties.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-1
@@ -1,9 +1,12 @@
|
|||||||
FILE: classWithCompanionObject.kt
|
FILE: classWithCompanionObject.kt
|
||||||
@R|kotlinx/serialization/Serializable|() public final class SomeClass : R|kotlin/Any| {
|
@R|kotlinx/serialization/Serializable|() public final class SomeClass : R|kotlin/Any| {
|
||||||
public constructor(): R|SomeClass| {
|
public constructor(i: R|kotlin/Int|): R|SomeClass| {
|
||||||
super<R|kotlin/Any|>()
|
super<R|kotlin/Any|>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final val i: R|kotlin/Int| = R|<local>/i|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
public final companion object Companion : R|kotlin/Any| {
|
public final companion object Companion : R|kotlin/Any| {
|
||||||
public final fun serializer(): R|kotlinx/serialization/KSerializer<SomeClass>|
|
public final fun serializer(): R|kotlinx/serialization/KSerializer<SomeClass>|
|
||||||
|
|
||||||
@@ -27,5 +30,29 @@ FILE: classWithCompanionObject.kt
|
|||||||
|
|
||||||
}
|
}
|
||||||
public final fun box(): R|kotlin/String| {
|
public final fun box(): R|kotlin/String| {
|
||||||
|
lval targetString: R|kotlin/String| = String({"i":42})
|
||||||
|
lval serializer: R|kotlinx/serialization/KSerializer<SomeClass>| = Q|SomeClass.Companion|.R|/SomeClass.Companion.serializer|()
|
||||||
|
lval descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor| = R|<local>/serializer|.R|SubstitutionOverride<kotlinx/serialization/KSerializer.descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|>|
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/descriptor|.R|kotlin/Any.toString|(), String(SomeClass(i: kotlin.Int))) -> {
|
||||||
|
^box <strcat>(String(Incorrect SerialDescriptor.toString(): ), R|<local>/descriptor|)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lval instance: R|SomeClass| = R|/SomeClass.SomeClass|(Int(42))
|
||||||
|
lval string: R|kotlin/String| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.encodeToString|<R|SomeClass|>(R|<local>/serializer|, R|<local>/instance|)
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/string|, R|<local>/targetString|) -> {
|
||||||
|
^box <strcat>(String(Incorrect serialization result: expected ), R|<local>/targetString|, String(, got ), R|<local>/string|)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lval instance2: R|SomeClass| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.decodeFromString|<R|SomeClass|>(R|<local>/serializer|, R|<local>/string|)
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/instance2|.R|/SomeClass.i|, R|<local>/instance|.R|/SomeClass.i|) -> {
|
||||||
|
^box <strcat>(String(Incorrect deserialization result: expected ), R|<local>/instance|.R|/SomeClass.i|, String(, got ), R|<local>/instance2|.R|/SomeClass.i|)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
^box String(OK)
|
^box String(OK)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-3
@@ -1,11 +1,21 @@
|
|||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.json.*
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class SomeClass
|
class SomeClass(val i: Int)
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
// SomeClass.serializer()
|
val targetString = """{"i":42}"""
|
||||||
// SomeClass.Companion.serializer()
|
val serializer = SomeClass.Companion.serializer()
|
||||||
|
val descriptor = serializer.descriptor
|
||||||
|
if (descriptor.toString() != "SomeClass(i: kotlin.Int)") return "Incorrect SerialDescriptor.toString(): $descriptor"
|
||||||
|
val instance = SomeClass(42)
|
||||||
|
val string = Json.encodeToString(serializer, instance)
|
||||||
|
if (string != targetString) return "Incorrect serialization result: expected $targetString, got $string"
|
||||||
|
val instance2 = Json.decodeFromString(serializer, string)
|
||||||
|
if (instance2.i != instance.i) return "Incorrect deserialization result: expected ${instance.i}, got ${instance2.i}"
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
FILE: defaultProperties.kt
|
||||||
|
@R|kotlinx/serialization/Serializable|() public final data class SomeClass : R|kotlin/Any| {
|
||||||
|
public constructor(ctor: R|kotlin/Int| = Int(42), ctorDependent: R|kotlin/Int| = R|<local>/ctor|.R|kotlin/Int.plus|(Int(1))): R|SomeClass| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final val ctor: R|kotlin/Int| = R|<local>/ctor|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final val ctorDependent: R|kotlin/Int| = R|<local>/ctorDependent|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final var body: R|kotlin/String| = String()
|
||||||
|
public get(): R|kotlin/String|
|
||||||
|
public set(value: R|kotlin/String|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
public final var bodyDependent: R|kotlin/Int| = this@R|/SomeClass|.R|/SomeClass.ctor|.R|kotlin/Int.plus|(Int(2))
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
public final operator fun component1(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final operator fun component2(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final fun copy(ctor: R|kotlin/Int| = this@R|/SomeClass|.R|/SomeClass.ctor|, ctorDependent: R|kotlin/Int| = this@R|/SomeClass|.R|/SomeClass.ctorDependent|): R|SomeClass|
|
||||||
|
|
||||||
|
public final companion object Companion : R|kotlin/Any| {
|
||||||
|
public final fun serializer(): R|kotlinx/serialization/KSerializer<SomeClass>|
|
||||||
|
|
||||||
|
public constructor(): R|SomeClass.Companion|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final object $serializer : R|kotlinx/serialization/internal/GeneratedSerializer<SomeClass>| {
|
||||||
|
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|SomeClass|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|SomeClass|
|
||||||
|
|
||||||
|
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||||
|
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||||
|
|
||||||
|
public final fun childSerializers(): R|kotlin/Array<kotlinx/serialization/KSerializer<*>>|
|
||||||
|
|
||||||
|
public constructor(): R|SomeClass.$serializer|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun test(targetString: R|kotlin/String|): R|kotlin/String| {
|
||||||
|
lval json: R|kotlinx/serialization/json/Json| = R|kotlinx/serialization/json/Json|(<L> = Json@fun R|kotlinx/serialization/json/JsonBuilder|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||||
|
this@R|special/anonymous|.R|kotlinx/serialization/json/JsonBuilder.encodeDefaults| = Boolean(true)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
lval c: R|SomeClass| = R|/SomeClass.SomeClass|(Int(1)).R|kotlin/apply|<R|SomeClass|>(<L> = apply@fun R|SomeClass|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||||
|
this@R|special/anonymous|.R|/SomeClass.body| = String(x)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
lval s: R|kotlin/String| = R|<local>/json|.R|kotlinx/serialization/json/Json.encodeToString|<R|SomeClass|>(Q|SomeClass|.R|/SomeClass.Companion.serializer|(), R|<local>/c|)
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/s|, R|<local>/targetString|) -> {
|
||||||
|
^test R|<local>/s|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lval i2: R|SomeClass| = R|<local>/json|.R|kotlinx/serialization/json/Json.decodeFromString|<R|SomeClass|>(Q|SomeClass|.R|/SomeClass.Companion.serializer|(), String({}))
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/i2|.R|/SomeClass.ctor|, Int(42)) -> {
|
||||||
|
^test String(Incorrect default ctor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/i2|.R|/SomeClass.ctorDependent|, Int(43)) -> {
|
||||||
|
^test String(Incorrect default ctorDependent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/i2|.R|/SomeClass.body|, String()) -> {
|
||||||
|
^test String(Incorrect default body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/i2|.R|/SomeClass.bodyDependent|, Int(44)) -> {
|
||||||
|
^test String(Incorrect default bodyDependent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
^test String(OK)
|
||||||
|
}
|
||||||
|
public final fun box(): R|kotlin/String| {
|
||||||
|
^box R|/test|(String({"ctor":1,"ctorDependent":2,"body":"x","bodyDependent":3}))
|
||||||
|
}
|
||||||
Vendored
+28
@@ -0,0 +1,28 @@
|
|||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.json.*
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SomeClass(val ctor: Int = 42, val ctorDependent: Int = ctor + 1) {
|
||||||
|
var body: String = ""
|
||||||
|
|
||||||
|
var bodyDependent = ctor + 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(targetString: String): String {
|
||||||
|
val json = Json { encodeDefaults = true }
|
||||||
|
val c = SomeClass(1).apply { body = "x" }
|
||||||
|
val s = json.encodeToString(SomeClass.serializer(), c)
|
||||||
|
if (s != targetString) return s
|
||||||
|
val i2 = json.decodeFromString(SomeClass.serializer(), "{}")
|
||||||
|
if (i2.ctor != 42) return "Incorrect default ctor"
|
||||||
|
if (i2.ctorDependent != 43) return "Incorrect default ctorDependent"
|
||||||
|
if (i2.body != "") return "Incorrect default body"
|
||||||
|
if (i2.bodyDependent != 44) return "Incorrect default bodyDependent"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return test("""{"ctor":1,"ctorDependent":2,"body":"x","bodyDependent":3}""")
|
||||||
|
}
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
FILE: multipleProperties.kt
|
||||||
|
@R|kotlinx/serialization/Serializable|() public final class SomeClass : R|kotlin/Any| {
|
||||||
|
public constructor(ctor: R|kotlin/Int|): R|SomeClass| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final val ctor: R|kotlin/Int| = R|<local>/ctor|
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final var body: R|kotlin/String| = String()
|
||||||
|
public get(): R|kotlin/String|
|
||||||
|
public set(value: R|kotlin/String|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
public final val getter: R|kotlin/Int|
|
||||||
|
public get(): R|kotlin/Int| {
|
||||||
|
^ Int(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final companion object Companion : R|kotlin/Any| {
|
||||||
|
public final fun serializer(): R|kotlinx/serialization/KSerializer<SomeClass>|
|
||||||
|
|
||||||
|
public constructor(): R|SomeClass.Companion|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final object $serializer : R|kotlinx/serialization/internal/GeneratedSerializer<SomeClass>| {
|
||||||
|
public final fun serialize(encoder: R|kotlinx/serialization/encoding/Encoder|, value: R|SomeClass|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
public final fun deserialize(decoder: R|kotlinx/serialization/encoding/Decoder|): R|SomeClass|
|
||||||
|
|
||||||
|
public final val descriptor: R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||||
|
public get(): R|kotlinx/serialization/descriptors/SerialDescriptor|
|
||||||
|
|
||||||
|
public final fun childSerializers(): R|kotlin/Array<kotlinx/serialization/KSerializer<*>>|
|
||||||
|
|
||||||
|
public constructor(): R|SomeClass.$serializer|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun test(targetString: R|kotlin/String|): R|kotlin/String| {
|
||||||
|
lval c: R|SomeClass| = R|/SomeClass.SomeClass|(Int(1)).R|kotlin/apply|<R|SomeClass|>(<L> = apply@fun R|SomeClass|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||||
|
this@R|special/anonymous|.R|/SomeClass.body| = String(x)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
lval s: R|kotlin/String| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.encodeToString|<R|SomeClass|>(Q|SomeClass|.R|/SomeClass.Companion.serializer|(), R|<local>/c|)
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/s|, R|<local>/targetString|) -> {
|
||||||
|
^test R|<local>/s|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lval i: R|SomeClass| = Q|kotlinx/serialization/json/Json|.R|kotlinx/serialization/json/Json.decodeFromString|<R|SomeClass|>(Q|SomeClass|.R|/SomeClass.Companion.serializer|(), R|<local>/s|)
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/i|.R|/SomeClass.ctor|, R|<local>/c|.R|/SomeClass.ctor|) -> {
|
||||||
|
^test String(Incorrect ctor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
when () {
|
||||||
|
!=(R|<local>/i|.R|/SomeClass.body|, R|<local>/c|.R|/SomeClass.body|) -> {
|
||||||
|
^test String(Incorrect body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
^test String(OK)
|
||||||
|
}
|
||||||
|
public final fun box(): R|kotlin/String| {
|
||||||
|
^box R|/test|(String({"ctor":1,"body":"x"}))
|
||||||
|
}
|
||||||
plugins/kotlin-serialization/kotlin-serialization-compiler/testData/firMembers/multipleProperties.kt
Vendored
+26
@@ -0,0 +1,26 @@
|
|||||||
|
// WITH_STDLIB
|
||||||
|
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.json.*
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SomeClass(val ctor: Int) {
|
||||||
|
var body: String = ""
|
||||||
|
|
||||||
|
// Not serializable: no backing field
|
||||||
|
val getter: Int get() = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(targetString: String): String {
|
||||||
|
val c = SomeClass(1).apply { body = "x" }
|
||||||
|
val s = Json.encodeToString(SomeClass.serializer(), c)
|
||||||
|
if (s != targetString) return s
|
||||||
|
val i = Json.decodeFromString(SomeClass.serializer(), s)
|
||||||
|
if (i.ctor != c.ctor) return "Incorrect ctor"
|
||||||
|
if (i.body != c.body) return "Incorrect body"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return test("""{"ctor":1,"body":"x"}""")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user