Disable kx.ser plugin inside descriptors serialization in the IDE

Since IDE does not perform any serialization of descriptors, and
metadata written to the 'serializationDescriptorSerializer'
deleted only on call to DescriptorSerializer,
enabling this extension in the IDE effectively causes memory leaks.

 #KT-39624 Fixed

Pass SerializationDescriptorSerializerPlugin to other extensions directly

instead of using static val in companion.
This commit is contained in:
Leonid Startsev
2020-10-15 22:42:06 +03:00
parent 4ec90b18bc
commit 8d999a2c13
16 changed files with 69 additions and 47 deletions
@@ -4,7 +4,6 @@
<syntheticResolveExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEResolveExtension"/> <syntheticResolveExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEResolveExtension"/>
<jsSyntheticTranslateExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEJsExtension"/> <jsSyntheticTranslateExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEJsExtension"/>
<irGenerationExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEIrExtension"/> <irGenerationExtension implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEIrExtension"/>
<DescriptorSerializerPlugin implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorPluginForKotlinxSerialization"/>
<storageComponentContainerContributor implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEContainerContributor"/> <storageComponentContainerContributor implementation="org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationIDEContainerContributor"/>
<quickFixContributor implementation="org.jetbrains.kotlinx.serialization.idea.quickfixes.SerializationQuickFixContributor"/> <quickFixContributor implementation="org.jetbrains.kotlinx.serialization.idea.quickfixes.SerializationQuickFixContributor"/>
</extensions> </extensions>
@@ -10,15 +10,17 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
abstract class SerializerCodegen( abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor, protected val serializerDescriptor: ClassDescriptor,
bindingContext: BindingContext bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) { ) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!! val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
protected val serialName: String = serializableDescriptor.serialName() protected val serialName: String = serializableDescriptor.serialName()
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor) protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor, metadataPlugin)
protected val serializableProperties = properties.serializableProperties protected val serializableProperties = properties.serializableProperties
private fun checkSerializability() { private fun checkSerializability() {
@@ -29,7 +29,7 @@ class SerializerForEnumsGenerator(
compilerContext: SerializationPluginContext, compilerContext: SerializationPluginContext,
bindingContext: BindingContext bindingContext: BindingContext
) : ) :
SerializerIrGenerator(irClass, compilerContext, bindingContext) { SerializerIrGenerator(irClass, compilerContext, bindingContext, null) {
override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc -> override fun generateSave(function: FunctionDescriptor) = irClass.contributeFunction(function) { saveFunc ->
fun irThis(): IrExpression = fun irThis(): IrExpression =
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext
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
@@ -44,15 +45,20 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.UN
// Is creating synthetic origin is a good idea or not? // Is creating synthetic origin is a good idea or not?
object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER") object SERIALIZABLE_PLUGIN_ORIGIN : IrDeclarationOriginImpl("SERIALIZER")
open class SerializerIrGenerator(val irClass: IrClass, final override val compilerContext: SerializationPluginContext, bindingContext: BindingContext) : open class SerializerIrGenerator(
SerializerCodegen(irClass.descriptor, bindingContext), IrBuilderExtension { val irClass: IrClass,
final override val compilerContext: SerializationPluginContext,
bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) :
SerializerCodegen(irClass.descriptor, bindingContext, metadataPlugin), IrBuilderExtension {
protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner protected val serializableIrClass = compilerContext.symbolTable.referenceClass(serializableDescriptor).owner
protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) } protected val irAnySerialDescProperty = anySerialDescProperty?.let { compilerContext.symbolTable.referenceProperty(it) }
protected open val serialDescImplClass: ClassDescriptor = serializerDescriptor protected open val serialDescImplClass: ClassDescriptor = serializerDescriptor
.getClassFromInternalSerializationPackage(SERIAL_DESCRIPTOR_CLASS_IMPL) .getClassFromInternalSerializationPackage(SERIAL_DESCRIPTOR_CLASS_IMPL)
override fun generateSerialDesc() { override fun generateSerialDesc() {
val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return val desc: PropertyDescriptor = generatedSerialDescPropertyDescriptor ?: return
@@ -493,13 +499,14 @@ open class SerializerIrGenerator(val irClass: IrClass, final override val compil
fun generate( fun generate(
irClass: IrClass, irClass: IrClass,
context: SerializationPluginContext, context: SerializationPluginContext,
bindingContext: BindingContext bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) { ) {
val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return val serializableDesc = getSerializableClassDescriptorBySerializer(irClass.symbol.descriptor) ?: return
if (serializableDesc.isSerializableEnum()) { if (serializableDesc.isSerializableEnum()) {
SerializerForEnumsGenerator(irClass, context, bindingContext).generate() SerializerForEnumsGenerator(irClass, context, bindingContext).generate()
} else { } else {
SerializerIrGenerator(irClass, context, bindingContext).generate() SerializerIrGenerator(irClass, context, bindingContext, metadataPlugin).generate()
} }
irClass.patchDeclarationParents(irClass.parent) irClass.patchDeclarationParents(irClass.parent)
} }
@@ -20,7 +20,7 @@ class SerializerForEnumsTranslator(
descriptor: ClassDescriptor, descriptor: ClassDescriptor,
translator: DeclarationBodyVisitor, translator: DeclarationBodyVisitor,
context: TranslationContext context: TranslationContext
) : SerializerJsTranslator(descriptor, translator, context) { ) : SerializerJsTranslator(descriptor, translator, context, null) {
override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx -> override fun generateSave(function: FunctionDescriptor) = generateFunction(function) { jsFun, ctx ->
val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS) val encoderClass = serializerDescriptor.getClassFromSerializationPackage(SerialEntityNames.ENCODER_CLASS)
val serialClassDescRef = JsNameRef(context.getNameForDescriptor(anySerialDescProperty!!), JsThisRef()) val serialClassDescRef = JsNameRef(context.getNameForDescriptor(anySerialDescProperty!!), JsThisRef())
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo import org.jetbrains.kotlinx.serialization.compiler.backend.common.getSerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
@@ -32,8 +33,9 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ty
open class SerializerJsTranslator( open class SerializerJsTranslator(
descriptor: ClassDescriptor, descriptor: ClassDescriptor,
val translator: DeclarationBodyVisitor, val translator: DeclarationBodyVisitor,
val context: TranslationContext val context: TranslationContext,
) : SerializerCodegen(descriptor, context.bindingContext()) { metadataPlugin: SerializationDescriptorSerializerPlugin?
) : SerializerCodegen(descriptor, context.bindingContext(), metadataPlugin) {
internal fun generateFunction(descriptor: FunctionDescriptor, bodyGen: JsBlockBuilder.(JsFunction, TranslationContext) -> Unit) { internal fun generateFunction(descriptor: FunctionDescriptor, bodyGen: JsBlockBuilder.(JsFunction, TranslationContext) -> Unit) {
val f = context.buildFunction(descriptor, bodyGen) val f = context.buildFunction(descriptor, bodyGen)
@@ -351,7 +353,11 @@ open class SerializerJsTranslator(
// deserialization constructor call // deserialization constructor call
// todo: external deserialization with primary constructor and setters calls after resolution of KT-11586 // todo: external deserialization with primary constructor and setters calls after resolution of KT-11586
val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(serializableDescriptor, context.bindingContext()) val constrDesc = KSerializerDescriptorResolver.createLoadConstructorDescriptor(
serializableDescriptor,
context.bindingContext(),
null
)
val constrRef = context.getInnerNameForDescriptor(constrDesc).makeRef() val constrRef = context.getInnerNameForDescriptor(constrDesc).makeRef()
val args: MutableList<JsExpression> = bitMasks.toMutableList() val args: MutableList<JsExpression> = bitMasks.toMutableList()
args += localProps args += localProps
@@ -363,13 +369,14 @@ open class SerializerJsTranslator(
fun translate( fun translate(
descriptor: ClassDescriptor, descriptor: ClassDescriptor,
translator: DeclarationBodyVisitor, translator: DeclarationBodyVisitor,
context: TranslationContext context: TranslationContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
) { ) {
val serializableDesc = getSerializableClassDescriptorBySerializer(descriptor) ?: return val serializableDesc = getSerializableClassDescriptorBySerializer(descriptor) ?: return
if (serializableDesc.isSerializableEnum()) { if (serializableDesc.isSerializableEnum()) {
SerializerForEnumsTranslator(descriptor, translator, context).generate() SerializerForEnumsTranslator(descriptor, translator, context).generate()
} else { } else {
SerializerJsTranslator(descriptor, translator, context).generate() SerializerJsTranslator(descriptor, translator, context, metadataPlugin).generate()
} }
} }
} }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.* import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
@@ -21,8 +22,9 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
open class SerializerCodegenImpl( open class SerializerCodegenImpl(
protected val codegen: ImplementationBodyCodegen, protected val codegen: ImplementationBodyCodegen,
serializableClass: ClassDescriptor serializableClass: ClassDescriptor,
) : SerializerCodegen(codegen.descriptor, codegen.bindingContext) { metadataPlugin: SerializationDescriptorSerializerPlugin?
) : SerializerCodegen(codegen.descriptor, codegen.bindingContext, metadataPlugin) {
private val serialDescField = "\$\$serialDesc" private val serialDescField = "\$\$serialDesc"
@@ -34,12 +36,12 @@ open class SerializerCodegenImpl(
private val staticDescriptor = serializableDescriptor.declaredTypeParameters.isEmpty() private val staticDescriptor = serializableDescriptor.declaredTypeParameters.isEmpty()
companion object { companion object {
fun generateSerializerExtensions(codegen: ImplementationBodyCodegen) { fun generateSerializerExtensions(codegen: ImplementationBodyCodegen, metadataPlugin: SerializationDescriptorSerializerPlugin?) {
val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return
val serializerCodegen = if (serializableClass.isSerializableEnum()) { val serializerCodegen = if (serializableClass.isSerializableEnum()) {
SerializerForEnumsCodegen(codegen, serializableClass) SerializerForEnumsCodegen(codegen, serializableClass)
} else { } else {
SerializerCodegenImpl(codegen, serializableClass) SerializerCodegenImpl(codegen, serializableClass, metadataPlugin)
} }
serializerCodegen.generate() serializerCodegen.generate()
} }
@@ -12,7 +12,7 @@ import org.jetbrains.org.objectweb.asm.Type
class SerializerForEnumsCodegen( class SerializerForEnumsCodegen(
codegen: ImplementationBodyCodegen, codegen: ImplementationBodyCodegen,
serializableClass: ClassDescriptor serializableClass: ClassDescriptor
) : SerializerCodegenImpl(codegen, serializableClass) { ) : SerializerCodegenImpl(codegen, serializableClass, null) {
override fun generateSave(function: FunctionDescriptor) = codegen.generateMethod(function) { _, _ -> override fun generateSave(function: FunctionDescriptor) = codegen.generateMethod(function) { _, _ ->
// fun save(output: KOutput, obj : T) // fun save(output: KOutput, obj : T)
val outputVar = 1 val outputVar = 1
@@ -23,11 +23,11 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCode
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCompanionCodegenImpl import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializableCompanionCodegenImpl
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.SerializerCodegenImpl
open class SerializationCodegenExtension : ExpressionCodegenExtension { open class SerializationCodegenExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : ExpressionCodegenExtension {
override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) { override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {
SerialInfoCodegenImpl.generateSerialInfoImplBody(codegen) SerialInfoCodegenImpl.generateSerialInfoImplBody(codegen)
SerializableCodegenImpl.generateSerializableExtensions(codegen) SerializableCodegenImpl.generateSerializableExtensions(codegen)
SerializerCodegenImpl.generateSerializerExtensions(codegen) SerializerCodegenImpl.generateSerializerExtensions(codegen, metadataPlugin)
SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen) SerializableCompanionCodegenImpl.generateSerializableExtensions(codegen)
} }
@@ -30,19 +30,22 @@ class SerializationComponentRegistrar : ComponentRegistrar {
} }
companion object { companion object {
internal val serializationDescriptorSerializer = SerializationDescriptorPluginForKotlinxSerialization()
fun registerExtensions(project: Project) { fun registerExtensions(project: Project) {
SyntheticResolveExtension.registerExtension(project, SerializationResolveExtension()) // This method is never called in the IDE, therefore this extension is not available there.
// Since IDE does not perform any serialization of descriptors, metadata written to the 'serializationDescriptorSerializer'
ExpressionCodegenExtension.registerExtension(project, SerializationCodegenExtension()) // is never deleted, effectively causing memory leaks.
JsSyntheticTranslateExtension.registerExtension(project, SerializationJsExtension()) // So we create SerializationDescriptorSerializerPlugin only outside of IDE.
IrGenerationExtension.registerExtension(project, SerializationLoweringExtension()) val serializationDescriptorSerializer = SerializationDescriptorSerializerPlugin()
StorageComponentContainerContributor.registerExtension(project, SerializationPluginComponentContainerContributor())
DescriptorSerializerPlugin.registerExtension(project, serializationDescriptorSerializer) DescriptorSerializerPlugin.registerExtension(project, serializationDescriptorSerializer)
registerProtoExtensions() registerProtoExtensions()
SyntheticResolveExtension.registerExtension(project, SerializationResolveExtension(serializationDescriptorSerializer))
ExpressionCodegenExtension.registerExtension(project, SerializationCodegenExtension(serializationDescriptorSerializer))
JsSyntheticTranslateExtension.registerExtension(project, SerializationJsExtension(serializationDescriptorSerializer))
IrGenerationExtension.registerExtension(project, SerializationLoweringExtension(serializationDescriptorSerializer))
StorageComponentContainerContributor.registerExtension(project, SerializationPluginComponentContainerContributor())
} }
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.serialization.SerializerExtension
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable
class SerializationDescriptorPluginForKotlinxSerialization : DescriptorSerializerPlugin { class SerializationDescriptorSerializerPlugin : DescriptorSerializerPlugin {
private val descriptorMetadataMap: MutableMap<ClassDescriptor, SerializableProperties> = hashMapOf() private val descriptorMetadataMap: MutableMap<ClassDescriptor, SerializableProperties> = hashMapOf()
private val ClassDescriptor.needSaveProgramOrder: Boolean private val ClassDescriptor.needSaveProgramOrder: Boolean
@@ -25,9 +25,9 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableCompa
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableJsTranslator import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializableJsTranslator
import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializerJsTranslator import org.jetbrains.kotlinx.serialization.compiler.backend.js.SerializerJsTranslator
open class SerializationJsExtension: JsSyntheticTranslateExtension { open class SerializationJsExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null): JsSyntheticTranslateExtension {
override fun generateClassSyntheticParts(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) { override fun generateClassSyntheticParts(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
SerializerJsTranslator.translate(descriptor, translator, context) SerializerJsTranslator.translate(descriptor, translator, context, metadataPlugin)
SerializableJsTranslator.translate(declaration, descriptor, context) SerializableJsTranslator.translate(declaration, descriptor, context)
SerializableCompanionJsTranslator.translate(descriptor, translator, context) SerializableCompanionJsTranslator.translate(descriptor, translator, context)
} }
@@ -40,22 +40,23 @@ fun ClassLoweringPass.runOnFileInOrder(irFile: IrFile) {
typealias SerializationPluginContext = IrPluginContext typealias SerializationPluginContext = IrPluginContext
private class SerializerClassLowering( private class SerializerClassLowering(
val context: SerializationPluginContext val context: SerializationPluginContext,
val metadataPlugin: SerializationDescriptorSerializerPlugin?
) : ) :
IrElementTransformerVoid(), ClassLoweringPass { IrElementTransformerVoid(), ClassLoweringPass {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
SerializableIrGenerator.generate(irClass, context, context.bindingContext) SerializableIrGenerator.generate(irClass, context, context.bindingContext)
SerializerIrGenerator.generate(irClass, context, context.bindingContext) SerializerIrGenerator.generate(irClass, context, context.bindingContext, metadataPlugin)
SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext) SerializableCompanionIrGenerator.generate(irClass, context, context.bindingContext)
} }
} }
open class SerializationLoweringExtension : IrGenerationExtension { open class SerializationLoweringExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : IrGenerationExtension {
override fun generate( override fun generate(
moduleFragment: IrModuleFragment, moduleFragment: IrModuleFragment,
pluginContext: IrPluginContext pluginContext: IrPluginContext
) { ) {
val serializerClassLowering = SerializerClassLowering(pluginContext) val serializerClassLowering = SerializerClassLowering(pluginContext, metadataPlugin)
for (file in moduleFragment.files) for (file in moduleFragment.files)
serializerClassLowering.runOnFileInOrder(file) serializerClassLowering.runOnFileInOrder(file)
} }
@@ -34,7 +34,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoFqName
import java.util.* import java.util.*
open class SerializationResolveExtension : SyntheticResolveExtension { open class SerializationResolveExtension @JvmOverloads constructor(val metadataPlugin: SerializationDescriptorSerializerPlugin? = null) : SyntheticResolveExtension {
override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> = when { override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> = when {
thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && thisDescriptor.platform?.isJvm() == true -> listOf(SerialEntityNames.IMPL_NAME) thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && thisDescriptor.platform?.isJvm() == true -> listOf(SerialEntityNames.IMPL_NAME)
(thisDescriptor.shouldHaveGeneratedSerializer) && !thisDescriptor.hasCompanionObjectAsSerializer -> (thisDescriptor.shouldHaveGeneratedSerializer) && !thisDescriptor.hasCompanionObjectAsSerializer ->
@@ -87,7 +87,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
if (thisDescriptor.isInternalSerializable) { if (thisDescriptor.isInternalSerializable) {
// do not add synthetic deserialization constructor if .deserialize method is customized // do not add synthetic deserialization constructor if .deserialize method is customized
if (thisDescriptor.hasCompanionObjectAsSerializer && SerializerCodegen.getSyntheticLoadMember(thisDescriptor.companionObjectDescriptor!!) == null) return if (thisDescriptor.hasCompanionObjectAsSerializer && SerializerCodegen.getSyntheticLoadMember(thisDescriptor.companionObjectDescriptor!!) == null) return
result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext)) result.add(KSerializerDescriptorResolver.createLoadConstructorDescriptor(thisDescriptor, bindingContext, metadataPlugin))
} }
} }
@@ -16,13 +16,11 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.konan.isNative
import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor import org.jetbrains.kotlin.psi.synthetics.SyntheticClassOrObjectDescriptor
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.descriptorUtil.platform
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
@@ -31,6 +29,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.createProjection import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SimpleSyntheticPropertyDescriptor
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.IMPL_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.IMPL_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_CLASS_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_CLASS_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.typeArgPrefix
@@ -288,7 +287,8 @@ object KSerializerDescriptorResolver {
fun createLoadConstructorDescriptor( fun createLoadConstructorDescriptor(
classDescriptor: ClassDescriptor, classDescriptor: ClassDescriptor,
bindingContext: BindingContext bindingContext: BindingContext,
metadataPlugin: SerializationDescriptorSerializerPlugin?
): ClassConstructorDescriptor { ): ClassConstructorDescriptor {
if (!classDescriptor.isInternalSerializable) throw IllegalArgumentException() if (!classDescriptor.isInternalSerializable) throw IllegalArgumentException()
@@ -302,7 +302,7 @@ object KSerializerDescriptorResolver {
val markerDesc = classDescriptor.getKSerializerConstructorMarker() val markerDesc = classDescriptor.getKSerializerConstructorMarker()
val markerType = markerDesc.toSimpleType(nullable = true) val markerType = markerDesc.toSimpleType(nullable = true)
val serializableProperties = bindingContext.serializablePropertiesFor(classDescriptor).serializableProperties val serializableProperties = bindingContext.serializablePropertiesFor(classDescriptor, metadataPlugin).serializableProperties
val parameterDescsAsProps = serializableProperties.map { it.descriptor } val parameterDescsAsProps = serializableProperties.map { it.descriptor }
val bitMaskSlotsCount = serializableProperties.bitMaskSlotCount() val bitMaskSlotsCount = serializableProperties.bitMaskSlotCount()
var i = 0 var i = 0
@@ -16,6 +16,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.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin
import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) { class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
@@ -88,9 +89,9 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
internal fun List<SerializableProperty>.bitMaskSlotCount() = size / 32 + 1 internal fun List<SerializableProperty>.bitMaskSlotCount() = size / 32 + 1
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32 internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties { internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor, serializationDescriptorSerializer: SerializationDescriptorSerializerPlugin? = null): SerializableProperties {
val props = this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this) val props = this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
SerializationComponentRegistrar.serializationDescriptorSerializer.putIfNeeded(classDescriptor, props) serializationDescriptorSerializer?.putIfNeeded(classDescriptor, props)
return props return props
} }