Support for @UseSerializers annotation

This commit is contained in:
Leonid Startsev
2018-11-20 19:55:16 +03:00
parent f174ee863d
commit 58c145210c
5 changed files with 36 additions and 1 deletions
@@ -14,7 +14,10 @@ import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.supertypes
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
import org.jetbrains.kotlinx.serialization.compiler.resolve.isKSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
abstract class AbstractSerialGenerator(val bindingContext: BindingContext, val currentDeclaration: ClassDescriptor) {
@@ -34,4 +37,15 @@ abstract class AbstractSerialGenerator(val bindingContext: BindingContext, val c
currentDeclaration
).toSet()
}
val additionalSerializersInScopeOfCurrentFile: Map<KotlinType, ClassDescriptor> by lazy {
getKClassListFromFileAnnotation(SerializationAnnotations.additionalSerializersFqName, currentDeclaration)
.associateBy(
{
it.supertypes().find(::isKSerializer)?.arguments?.firstOrNull()?.type
?: throw AssertionError("Argument for ${SerializationAnnotations.additionalSerializersFqName} does not implement KSerializer")
},
{ it.toClassDescriptor!! }
)
}
}
@@ -49,14 +49,18 @@ open class SerialTypeInfo(
val unit: Boolean = false
)
fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType): ClassDescriptor? =
additionalSerializersInScopeOfCurrentFile[propertyType]
@Suppress("FunctionName", "LocalVariableName")
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
fun SerializableInfo(serializer: ClassDescriptor?) =
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
val T = property.type
T.overridenSerializer?.toClassDescriptor?.let { return SerializableInfo(it) }
property.serializableWith?.toClassDescriptor?.let { return SerializableInfo(it) }
T.overridenSerializer?.toClassDescriptor?.let { return SerializableInfo(it) }
findAddOnSerializer(T)?.let { return SerializableInfo(it) }
return when {
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
@@ -91,6 +95,7 @@ fun AbstractSerialGenerator.findTypeSerializerOrContext(
annotations: Annotations = kType.annotations,
sourceElement: PsiElement? = null
): ClassDescriptor? {
additionalSerializersInScopeOfCurrentFile[kType]?.let { return it }
if (kType.isTypeParameter()) return null
fun getContextualSerializer() =
if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName) || kType in contextualKClassListInCurrentFile)
@@ -31,6 +31,7 @@ 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.findAddOnSerializer
import org.jetbrains.kotlinx.serialization.compiler.backend.common.findTypeSerializerOrContext
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.DECODER_CLASS
@@ -109,6 +110,7 @@ fun InstructionAdapter.genKOutputMethodCall(
ownerVar,
classCodegen.state
)
StackValue.coerce(propertyType, sti.type, this)
invokeinterface(
kOutputType.internalName,
CallingConventions.encode + sti.elementMethodPrefix + (if (useSerializer) "Serializable" else "") + CallingConventions.elementPostfix,
@@ -309,6 +311,18 @@ class JVMSerialTypeInfo(
) : SerialTypeInfo(property, nn, serializer, unit)
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty, type: Type): JVMSerialTypeInfo {
fun SerializableInfo(serializer: ClassDescriptor?) =
JVMSerialTypeInfo(
property,
Type.getType("Ljava/lang/Object;"),
if (property.type.isMarkedNullable) "Nullable" else "",
serializer
)
property.serializableWith?.toClassDescriptor?.let { return SerializableInfo(it) }
property.type.overridenSerializer?.toClassDescriptor?.let { return SerializableInfo(it) }
findAddOnSerializer(property.type)?.let { return SerializableInfo(it) }
if (property.type.isTypeParameter()) return JVMSerialTypeInfo(
property,
Type.getType("Ljava/lang/Object;"),
@@ -385,6 +385,7 @@ class SerializerCodegenImpl(
genValidateProperty(index, ::bitMaskOff)
ificmpeq(readLabel)
load(propVar, propertyType)
StackValue.coerce(propertyType, sti.type, this)
produceCall(true)
goTo(endL)
visitLabel(readLabel)
@@ -22,6 +22,7 @@ object SerializationAnnotations {
internal val serialInfoFqName = FqName("kotlinx.serialization.SerialInfo")
internal val contextualFqName = FqName("kotlinx.serialization.ContextualSerialization")
internal val additionalSerializersFqName = FqName("kotlinx.serialization.UseSerializers")
}
object SerialEntityNames {