Add synthetic companion with .serializer() getter even if default serializer is overridden. (kotlinx.serialization/228)

This commit is contained in:
Leonid Startsev
2018-11-26 18:38:43 +03:00
parent 1e440efc01
commit 7c942af13d
6 changed files with 21 additions and 12 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlinx.serialization.compiler.backend.common
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -34,10 +35,15 @@ abstract class SerializableCompanionCodegen(
val serializerGetterDescriptor = companionDescriptor.unsubstitutedMemberScope.getContributedFunctions(
SERIALIZER_PROVIDER_NAME,
NoLookupLocation.FROM_BACKEND
).first { func ->
func.valueParameters.size == serializableDescriptor.declaredTypeParameters.size &&
func.valueParameters.all { isKSerializer(it.type) }
}
).firstOrNull {
it.valueParameters.size == serializableDescriptor.declaredTypeParameters.size
&& it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
&& it.valueParameters.all { p -> isKSerializer(p.type) }
&& it.returnType != null && isKSerializer(it.returnType)
} ?: throw IllegalStateException(
"Can't find synthesized 'Companion.serializer()' function to generate, " +
"probably clash with user-defined function has occurred"
)
generateSerializerGetter(serializerGetterDescriptor)
}
@@ -13,7 +13,6 @@ 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.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.findSerializerConstructorForTypeArgumentsSerializers
class SerializableCompanionIrGenerator(
val irClass: IrClass,
@@ -33,7 +32,7 @@ class SerializableCompanionIrGenerator(
) {
val companionDescriptor = irClass.descriptor
val serializableClass = getSerializableClassDescriptorByCompanion(companionDescriptor) ?: return
if (serializableClass.isInternalSerializable)
if (serializableClass.shouldHaveGeneratedMethodsInCompanion)
SerializableCompanionIrGenerator(irClass, context, bindingContext).generate()
}
}
@@ -56,7 +56,7 @@ class SerializableCompanionJsTranslator(
companion object {
fun translate(declaration: KtPureClassOrObject, descriptor: ClassDescriptor, translator: DeclarationBodyVisitor, context: TranslationContext) {
val serializableClass = getSerializableClassDescriptorByCompanion(descriptor) ?: return
if (serializableClass.isInternalSerializable)
if (serializableClass.shouldHaveGeneratedMethodsInCompanion)
SerializableCompanionJsTranslator(descriptor, translator, context).generate()
}
}
@@ -18,10 +18,12 @@ 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.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.classSerializer
import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorByCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.shouldHaveGeneratedMethodsInCompanion
import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCodegen) :
SerializableCompanionCodegen(codegen.descriptor, codegen.bindingContext) {
@@ -29,7 +31,7 @@ class SerializableCompanionCodegenImpl(private val codegen: ImplementationBodyCo
companion object {
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
val serializableClass = getSerializableClassDescriptorByCompanion(codegen.descriptor) ?: return
if (serializableClass.isInternalSerializable)
if (serializableClass.shouldHaveGeneratedMethodsInCompanion)
SerializableCompanionCodegenImpl(codegen).generate()
}
}
@@ -61,7 +61,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
}
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? =
if (thisDescriptor.isInternalSerializable) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
if (thisDescriptor.shouldHaveGeneratedMethodsInCompanion) SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
else null
override fun addSyntheticSupertypes(thisDescriptor: ClassDescriptor, supertypes: MutableList<KotlinType>) {
@@ -97,6 +97,8 @@ val KotlinType?.toClassDescriptor: ClassDescriptor?
@JvmName("toClassDescriptor")
get() = this?.constructor?.declarationDescriptor as? ClassDescriptor
internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean
get() = this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)
val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking
get() {
@@ -159,7 +161,7 @@ val KotlinType.genericIndex: Int?
fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor): ClassDescriptor? {
if (!thisDescriptor.isCompanionObject) return null
val classDescriptor = (thisDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
if (!classDescriptor.isInternalSerializable) return null
if (!classDescriptor.shouldHaveGeneratedMethodsInCompanion) return null
return classDescriptor
}