Rebased on master, adopt to new constant values from deserialized
annotations Fix issue with generating redundant constructors for custom generic seralizers
This commit is contained in:
+2
-1
@@ -12,6 +12,7 @@ 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.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||
|
||||
@@ -24,7 +25,7 @@ abstract class AbstractSerialGenerator(val bindingContext: BindingContext, val c
|
||||
?: return emptyList()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val typeList: List<KClassValue> = annotation.firstArgument()?.value as? List<KClassValue> ?: return emptyList()
|
||||
return typeList.map { it.value }
|
||||
return typeList.map { it.getArgumentType(declarationInFile.module) }
|
||||
}
|
||||
|
||||
val contextualKClassListInCurrentFile: Set<KotlinType> by lazy {
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ abstract class SerializerCodegen(
|
||||
// if (save || load || prop)
|
||||
// generateSerialDesc()
|
||||
if (serializableDescriptor.declaredTypeParameters.isNotEmpty()) {
|
||||
findSerializerConstructorForTypeArgumentsSerializers(serializerDescriptor)?.let {
|
||||
findSerializerConstructorForTypeArgumentsSerializers(serializerDescriptor, onlyIfSynthetic = true)?.let {
|
||||
generateGenericFieldsAndConstructor(it)
|
||||
}
|
||||
}
|
||||
|
||||
+25
-14
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.constants.KClassValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
@@ -58,15 +59,15 @@ internal fun extractKSerializerArgumentFromImplementation(implementationClass: C
|
||||
return kSerializerSupertype.arguments.first().type
|
||||
}
|
||||
|
||||
internal val Annotations.serializableWith: KotlinType?
|
||||
get() = findAnnotationValue(SerializationAnnotations.serializableAnnotationFqName, "with")
|
||||
internal val DeclarationDescriptor.serializableWith: KotlinType?
|
||||
get() = annotations.findAnnotationKotlinTypeValue(SerializationAnnotations.serializableAnnotationFqName, module,"with")
|
||||
|
||||
internal val Annotations.serializerForClass: KotlinType?
|
||||
get() = findAnnotationValue(SerializationAnnotations.serializerAnnotationFqName, "forClass")
|
||||
internal val DeclarationDescriptor.serializerForClass: KotlinType?
|
||||
get() = annotations.findAnnotationKotlinTypeValue(SerializationAnnotations.serializerAnnotationFqName, module, "forClass")
|
||||
|
||||
val Annotations.serialNameValue: String?
|
||||
get() {
|
||||
val value = findAnnotationValue<String?>(SerializationAnnotations.serialNameAnnotationFqName, "value")
|
||||
val value = findAnnotationConstantValue<String?>(SerializationAnnotations.serialNameAnnotationFqName, "value")
|
||||
return value
|
||||
}
|
||||
|
||||
@@ -89,7 +90,7 @@ val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking
|
||||
// If provided descriptor is lazy, carefully look at psi in order not to trigger full resolve which may be recursive.
|
||||
// Otherwise, this descriptor is deserialized from another module and it is OK to check value right away.
|
||||
val lazyDesc = annotations.findAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
||||
as? LazyAnnotationDescriptor ?: return (annotations.serializableWith == null)
|
||||
as? LazyAnnotationDescriptor ?: return (serializableWith == null)
|
||||
val psi = lazyDesc.annotationEntry
|
||||
return psi.valueArguments.isEmpty()
|
||||
}
|
||||
@@ -98,7 +99,7 @@ val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking
|
||||
internal val ClassDescriptor?.classSerializer: KotlinType?
|
||||
get() = this?.let {
|
||||
// serializer annotation on class?
|
||||
annotations.serializableWith?.let { return it }
|
||||
serializableWith?.let { return it }
|
||||
// default serializable?
|
||||
if (isInternalSerializable) {
|
||||
// companion object serializer?
|
||||
@@ -112,7 +113,7 @@ internal val ClassDescriptor?.classSerializer: KotlinType?
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean
|
||||
get() = companionObjectDescriptor?.annotations?.serializerForClass == this.defaultType
|
||||
get() = companionObjectDescriptor?.serializerForClass == this.defaultType
|
||||
|
||||
internal fun checkSerializerNullability(classType: KotlinType, serializerType: KotlinType): KotlinType {
|
||||
val castedToKSerial = requireNotNull(
|
||||
@@ -126,7 +127,7 @@ internal fun checkSerializerNullability(classType: KotlinType, serializerType: K
|
||||
|
||||
// returns only user-overriden Serializer
|
||||
val KotlinType.overridenSerializer: KotlinType?
|
||||
get() = (this.toClassDescriptor?.annotations?.serializableWith)?.let { checkSerializerNullability(this, it) }
|
||||
get() = (this.toClassDescriptor?.serializableWith)?.let { checkSerializerNullability(this, it) }
|
||||
|
||||
// serializer that was declared for this specific type or annotation from a class declaration
|
||||
val KotlinType.typeSerializer: KotlinType?
|
||||
@@ -143,7 +144,7 @@ fun getSerializableClassDescriptorByCompanion(thisDescriptor: ClassDescriptor):
|
||||
}
|
||||
|
||||
fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? {
|
||||
val serializerForClass = serializerDescriptor.annotations.serializerForClass
|
||||
val serializerForClass = serializerDescriptor.serializerForClass
|
||||
if (serializerForClass != null) return serializerForClass.toClassDescriptor
|
||||
if (serializerDescriptor.name !in setOf(
|
||||
SerialEntityNames.SERIALIZER_CLASS_NAME,
|
||||
@@ -173,10 +174,20 @@ fun ClassDescriptor.checkLoadMethodResult(type: KotlinType): Boolean = getSerial
|
||||
|
||||
// ----------------
|
||||
|
||||
inline fun <reified R> Annotations.findAnnotationValue(annotationFqName: FqName, property: String): R? =
|
||||
findAnnotation(annotationFqName)?.let { annotation ->
|
||||
annotation.allValueArguments.entries.singleOrNull { it.key.asString() == property }?.value?.value
|
||||
} as? R
|
||||
inline fun <reified R> Annotations.findAnnotationConstantValue(annotationFqName: FqName, property: String): R? =
|
||||
findAnnotation(annotationFqName)?.let { annotation ->
|
||||
annotation.allValueArguments.entries.singleOrNull { it.key.asString() == property }?.value?.value
|
||||
} as? R
|
||||
|
||||
fun Annotations.findAnnotationKotlinTypeValue(
|
||||
annotationFqName: FqName,
|
||||
moduleForResolve: ModuleDescriptor,
|
||||
property: String
|
||||
): KotlinType? =
|
||||
findAnnotation(annotationFqName)?.let { annotation ->
|
||||
val maybeKClass = annotation.allValueArguments.entries.singleOrNull { it.key.asString() == property }?.value as? KClassValue
|
||||
maybeKClass?.getArgumentType(moduleForResolve)
|
||||
}
|
||||
|
||||
// Search utils
|
||||
|
||||
|
||||
+12
-3
@@ -137,7 +137,12 @@ object KSerializerDescriptorResolver {
|
||||
) {
|
||||
result.add(createSerializableClassPropertyDescriptor(thisDescriptor, classDescriptor))
|
||||
}
|
||||
result.addAll(createLocalSerializersFieldsDescriptors(classDescriptor, thisDescriptor))
|
||||
// don't add local serializer fields if typed constructor is not synthetic
|
||||
if (classDescriptor.declaredTypeParameters.isNotEmpty() &&
|
||||
findSerializerConstructorForTypeArgumentsSerializers(thisDescriptor, onlyIfSynthetic = true) != null
|
||||
) {
|
||||
result.addAll(createLocalSerializersFieldsDescriptors(classDescriptor, thisDescriptor))
|
||||
}
|
||||
}
|
||||
|
||||
fun generateCompanionObjectMethods(
|
||||
@@ -296,15 +301,19 @@ object KSerializerDescriptorResolver {
|
||||
}
|
||||
|
||||
// finds constructor (KSerializer<T0>, KSerializer<T1>...) on a KSerializer<T<T0, T1...>>
|
||||
fun findSerializerConstructorForTypeArgumentsSerializers(serializerDescriptor: ClassDescriptor): ClassConstructorDescriptor? {
|
||||
fun findSerializerConstructorForTypeArgumentsSerializers(
|
||||
serializerDescriptor: ClassDescriptor,
|
||||
onlyIfSynthetic: Boolean = false
|
||||
): ClassConstructorDescriptor? {
|
||||
val serializableImplementationTypeArguments = extractKSerializerArgumentFromImplementation(serializerDescriptor)?.arguments
|
||||
?: throw AssertionError("Serializer does not implement KSerializer??")
|
||||
|
||||
val typeParamsCount = serializableImplementationTypeArguments.size
|
||||
if (typeParamsCount == 0) return null //don't need it
|
||||
return serializerDescriptor.constructors.find { ctor ->
|
||||
val ctor = serializerDescriptor.constructors.find { ctor ->
|
||||
ctor.valueParameters.size == typeParamsCount && ctor.valueParameters.all { isKSerializer(it.type) }
|
||||
}
|
||||
return if (!onlyIfSynthetic) ctor else ctor?.takeIf { it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED }
|
||||
}
|
||||
|
||||
private fun createTypedSerializerConstructorDescriptor(
|
||||
|
||||
+4
-4
@@ -36,9 +36,9 @@ class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructor
|
||||
descriptor.annotationsWithArguments()
|
||||
|
||||
private fun extractSerializableWith(annotations: Annotations): KotlinType? {
|
||||
annotations.serializableWith?.let { return it }
|
||||
if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName))
|
||||
return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer).defaultType
|
||||
return null
|
||||
descriptor.serializableWith?.let { return it }
|
||||
return if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName))
|
||||
module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer).defaultType
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user