Respect @ContextualSerialization on file

Add common ancestor to all serializable generators
This commit is contained in:
Leonid Startsev
2018-09-20 15:26:26 +03:00
committed by Leonid Startsev
parent 82fa152514
commit f0e81c6eb8
11 changed files with 76 additions and 31 deletions
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
abstract class AbstractSerialGenerator(val bindingContext: BindingContext, val currentDeclaration: ClassDescriptor) {
private fun getKClassListFromFileAnnotation(annotationFqName: FqName, declarationInFile: DeclarationDescriptor): List<KotlinType> {
val annotation = AnnotationsUtils
.getContainingFileAnnotations(bindingContext, declarationInFile)
.find { it.fqName == annotationFqName }
?: return emptyList()
@Suppress("UNCHECKED_CAST")
val typeList: List<KClassValue> = annotation.firstArgument()?.value as? List<KClassValue> ?: return emptyList()
return typeList.map { it.value }
}
val contextualKClassListInCurrentFile: Set<KotlinType> by lazy {
getKClassListFromFileAnnotation(
SerializationAnnotations.contextualFqName,
currentDeclaration
).toSet()
}
}
@@ -25,8 +25,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperti
abstract class SerializableCodegen(
protected val serializableDescriptor: ClassDescriptor,
private val bindingContext: BindingContext
) {
bindingContext: BindingContext
) : AbstractSerialGenerator(bindingContext, serializableDescriptor) {
protected val properties = SerializableProperties(serializableDescriptor, bindingContext)
fun generate() {
@@ -19,12 +19,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.psi2ir.findSingleFunction
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIALIZER_PROVIDER_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
abstract class SerializableCompanionCodegen(
protected val companionDescriptor: ClassDescriptor
) {
protected val companionDescriptor: ClassDescriptor,
bindingContext: BindingContext
) : AbstractSerialGenerator(bindingContext, companionDescriptor) {
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorByCompanion(companionDescriptor)!!
fun generate() {
@@ -20,8 +20,6 @@ import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
@@ -31,7 +29,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescripto
abstract class SerializerCodegen(
protected val serializerDescriptor: ClassDescriptor,
bindingContext: BindingContext
) {
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
// protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
@@ -49,7 +49,7 @@ open class SerialTypeInfo(
val unit: Boolean = false
)
fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
val T = property.type
val serializableWith = property.serializableWith?.toClassDescriptor
if (serializableWith != null) return SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializableWith)
@@ -81,7 +81,7 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
}
}
fun findTypeSerializerOrContext(
fun AbstractSerialGenerator.findTypeSerializerOrContext(
module: ModuleDescriptor,
kType: KotlinType,
annotations: Annotations = kType.annotations,
@@ -89,7 +89,7 @@ fun findTypeSerializerOrContext(
): ClassDescriptor? {
if (kType.isTypeParameter()) return null
fun getContextualSerializer() =
if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName))
if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName) || kType in contextualKClassListInCurrentFile)
module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
else
throw CompilationException(
@@ -20,7 +20,7 @@ class SerializableCompanionIrGenerator(
val irClass: IrClass,
override val compilerContext: BackendContext,
bindingContext: BindingContext
) : SerializableCompanionCodegen(irClass.descriptor), IrBuilderExtension {
) : SerializableCompanionCodegen(irClass.descriptor, bindingContext), IrBuilderExtension {
override val translator: TypeTranslator = compilerContext.createTypeTranslator(serializableDescriptor.module)
private val _table = SymbolTable()
override val BackendContext.localSymbolTable: SymbolTable
@@ -32,7 +32,8 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializableCompanionJsTranslator(
declaration: ClassDescriptor,
val translator: DeclarationBodyVisitor,
val context: TranslationContext): SerializableCompanionCodegen(declaration) {
val context: TranslationContext
): SerializableCompanionCodegen(declaration, context.bindingContext()) {
override fun generateSerializerGetter(methodDescriptor: FunctionDescriptor) {
val f = context.buildFunction(methodDescriptor) {jsFun, context ->
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlinx.serialization.compiler.backend.common.AbstractSerialGenerator
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerialTypeInfo
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
@@ -90,12 +91,15 @@ internal fun InstructionAdapter.genExceptionThrow(exceptionClass: String, messag
athrow()
}
fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen,
propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null) {
fun InstructionAdapter.genKOutputMethodCall(
property: SerializableProperty, classCodegen: ImplementationBodyCodegen, expressionCodegen: ExpressionCodegen,
propertyOwnerType: Type, ownerVar: Int, fromClassStartVar: Int? = null,
generator: AbstractSerialGenerator
) {
val propertyType = classCodegen.typeMapper.mapType(property.type)
val sti = getSerialTypeInfo(property, propertyType)
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti)
else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar)
val sti = generator.getSerialTypeInfo(property, propertyType)
val useSerializer = if (fromClassStartVar == null) stackValueSerializerInstanceFromSerializer(classCodegen, sti, generator)
else stackValueSerializerInstanceFromClass(classCodegen, sti, fromClassStartVar, generator)
if (!sti.unit) ImplementationBodyCodegen.genPropertyOnStack(
this,
expressionCodegen.context,
@@ -104,11 +108,13 @@ fun InstructionAdapter.genKOutputMethodCall(property: SerializableProperty, clas
ownerVar,
classCodegen.state
)
invokeinterface(kOutputType.internalName,
invokeinterface(
kOutputType.internalName,
CallingConventions.encode + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + CallingConventions.elementPostfix,
"(" + descType.descriptor + "I" +
(if (useSerializer) kSerialSaverType.descriptor else "") +
(if (sti.unit) "" else sti.type.descriptor) + ")V")
"(" + descType.descriptor + "I" +
(if (useSerializer) kSerialSaverType.descriptor else "") +
(if (sti.unit) "" else sti.type.descriptor) + ")V"
)
}
internal fun InstructionAdapter.buildInternalConstructorDesc(propsStartVar: Int, bitMaskBase: Int, codegen: ClassBodyCodegen, args: List<SerializableProperty>): String {
@@ -146,10 +152,11 @@ internal val contextSerializerId = ClassId(packageFqName, Name.identifier(Specia
internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(
codegen: ClassBodyCodegen,
sti: JVMSerialTypeInfo,
varIndexStart: Int
varIndexStart: Int,
serializerCodegen: AbstractSerialGenerator
): Boolean {
val serializer = sti.serializer
return stackValueSerializerInstance(
return serializerCodegen.stackValueSerializerInstance(
codegen,
sti.property.module,
sti.property.type,
@@ -161,8 +168,8 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromClass(
}
}
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo): Boolean {
return stackValueSerializerInstance(
internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codegen: ClassBodyCodegen, sti: JVMSerialTypeInfo, serializerCodegen: AbstractSerialGenerator): Boolean {
return serializerCodegen.stackValueSerializerInstance(
codegen, sti.property.module, sti.property.type,
sti.serializer, this, sti.property.genericIndex
) { idx ->
@@ -173,7 +180,7 @@ internal fun InstructionAdapter.stackValueSerializerInstanceFromSerializer(codeg
// returns false is cannot not use serializer
// use iv == null to check only (do not emit serializer onto stack)
internal fun stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: ClassBodyCodegen, module: ModuleDescriptor, kType: KotlinType, maybeSerializer: ClassDescriptor?,
iv: InstructionAdapter?, genericIndex: Int? = null, genericSerializerFieldGetter: (InstructionAdapter.(Int) -> Unit)? = null): Boolean {
if (genericIndex != null) {
// get field from serializer object
@@ -262,7 +269,7 @@ class JVMSerialTypeInfo(
unit: Boolean = false
) : SerialTypeInfo(property, nn, serializer, unit)
fun getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialTypeInfo {
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialTypeInfo {
if (property.type.isTypeParameter()) return JVMSerialTypeInfo(
property,
Type.getType("Ljava/lang/Object;"),
@@ -100,7 +100,7 @@ class SerializableCodegenImpl(
load(outputI, kOutputType)
load(serialDescI, descType)
iconst(i)
genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI)
genKOutputMethodCall(property, classCodegen, exprCodegen, thisAsmType, thisI, offsetI, generator = this@SerializableCodegenImpl)
}
areturn(Type.VOID_TYPE)
@@ -18,12 +18,13 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCompanionCodegen
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) :
SerializableCompanionCodegen(codegen.descriptor) {
SerializableCompanionCodegen(codegen.descriptor, codegen.bindingContext) {
companion object {
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
@@ -196,7 +196,7 @@ class SerializerCodegenImpl(
load(outputVar, kOutputType)
load(descVar, descType)
iconst(index)
genKOutputMethodCall(property, codegen, expressionCodegen, objType, objVar)
genKOutputMethodCall(property, codegen, expressionCodegen, objType, objVar, generator = this@SerializerCodegenImpl)
}
}
// output.writeEnd(classDesc)
@@ -303,7 +303,7 @@ class SerializerCodegenImpl(
iconst(labelNum)
val sti = getSerialTypeInfo(property, propertyType)
val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti)
val useSerializer = stackValueSerializerInstanceFromSerializer(codegen, sti, this@SerializerCodegenImpl)
val unknownSer = (!useSerializer && sti.elementMethodPrefix.isEmpty())
if (unknownSer) {
aconst(codegen.typeMapper.mapType(property.type))