Respect @Serializable(with) on properties on JS too.

Don't generate constructor for passing generic serializers if user already defined proper one.
This commit is contained in:
Leonid Startsev
2018-05-25 18:32:26 +03:00
parent 365a183d01
commit 572e8873ca
2 changed files with 24 additions and 6 deletions
@@ -19,15 +19,13 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberToGenerate
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
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.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.createTypedSerializerConstructorDescriptor
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializableProperties
abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) {
protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext)
@@ -43,11 +41,30 @@ abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContex
val load = generateLoadIfNeeded()
if (save || load || prop)
generateSerialDesc()
if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) {
if (serializableDescriptor.declaredTypeParameters.isNotEmpty() && typedSerializerConstructorNotDeclared()) {
generateGenericFieldsAndConstructor(createTypedSerializerConstructorDescriptor(serializerDescriptor, serializableDescriptor))
}
}
// checks if user didn't declared constructor (KSerializer<T0>, KSerializer<T1>...) on a KSerializer<T<T0, T1...>>
private fun typedSerializerConstructorNotDeclared(): Boolean {
val kSerializerSupertype = serializerDescriptor.typeConstructor.supertypes
.find { isKSerializer(it) } ?: throw AssertionError("Serializer does not implement KSerializer??")
val serializableImplementationTypeArguments = kSerializerSupertype.arguments.first().type.arguments
val typeParamsCount = serializableImplementationTypeArguments.size
if (typeParamsCount == 0) return false //don't need it
val ctors = serializerDescriptor.constructors
val found =
ctors.any {
it.valueParameters.size == typeParamsCount && it.valueParameters.foldIndexed(false) { index, flag, parameterDescriptor ->
val type = parameterDescriptor.type
flag || (isKSerializer(type) && type.arguments.first() == serializableImplementationTypeArguments[index])
}
}
return !found
}
protected val serialDescPropertyDescriptor = getPropertyToGenerate(serializerDescriptor, KSerializerDescriptorResolver.SERIAL_DESC_FIELD,
serializerDescriptor::checkSerializableClassPropertyResult)
protected abstract fun generateSerialDesc()
@@ -47,6 +47,8 @@ open class SerialTypeInfo(
fun 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)
return when {
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
@@ -63,8 +65,7 @@ fun getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
}
T.toClassDescriptor?.kind == ClassKind.ENUM_CLASS -> {
val serializer =
property.serializableWith?.toClassDescriptor ?: property.module.findClassAcrossModuleDependencies(enumSerializerId)
val serializer = property.module.findClassAcrossModuleDependencies(enumSerializerId)
SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", serializer)
}
else -> {