Correctly handle @Repeatable @SerialInfo annotations on classes

that were affected by deduplication of inherited serial info annotations.

Prohibit combination of @InheritableSerialInfo and @Repeatable.

Fixes https://github.com/Kotlin/kotlinx.serialization/issues/2099
This commit is contained in:
Leonid Startsev
2023-03-17 16:57:31 +01:00
committed by Space Team
parent 8b12b3f18d
commit 6ee20574e1
13 changed files with 125 additions and 4 deletions
@@ -54,6 +54,8 @@ public interface SerializationErrors {
DiagnosticFactory2<PsiElement, KotlinType, KotlinType> INCONSISTENT_INHERITABLE_SERIALINFO = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<PsiElement> META_SERIALIZABLE_NOT_APPLICABLE = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> INHERITABLE_SERIALINFO_CANT_BE_REPEATABLE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, KotlinType> EXTERNAL_SERIALIZER_USELESS = DiagnosticFactory1.create(WARNING);
DiagnosticFactory2<PsiElement, KotlinType, KotlinType> EXTERNAL_CLASS_NOT_SERIALIZABLE = DiagnosticFactory2.create(ERROR);
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.JvmNames.TRANSIENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.psi.*
@@ -47,6 +48,7 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
if (descriptor !is ClassDescriptor) return
checkMetaSerializableApplicable(descriptor, context.trace)
checkInheritableSerialInfoNotRepeatable(descriptor, context.trace)
checkEnum(descriptor, declaration, context.trace)
checkExternalSerializer(descriptor, declaration, context.trace)
@@ -74,6 +76,14 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
trace.report(SerializationErrors.META_SERIALIZABLE_NOT_APPLICABLE.on(entry))
}
private fun checkInheritableSerialInfoNotRepeatable(descriptor: ClassDescriptor, trace: BindingTrace) {
if (descriptor.kind != ClassKind.ANNOTATION_CLASS) return
// both kotlin.Repeatable and java.lang.annotation.Repeatable
if (!(descriptor.isAnnotatedWithKotlinRepeatable() || descriptor.annotations.hasAnnotation(JvmAnnotationNames.REPEATABLE_ANNOTATION))) return
val inheritableAnno = descriptor.findAnnotationDeclaration(SerializationAnnotations.inheritableSerialInfoFqName) ?: return
trace.report(SerializationErrors.INHERITABLE_SERIALINFO_CANT_BE_REPEATABLE.on(inheritableAnno))
}
private fun checkExternalSerializer(classDescriptor: ClassDescriptor, declaration: KtDeclaration, trace: BindingTrace) {
val serializableKType = classDescriptor.serializerForClass ?: return
val serializableDescriptor = serializableKType.toClassDescriptor ?: return
@@ -164,6 +164,10 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
SerializationErrors.META_SERIALIZABLE_NOT_APPLICABLE,
"@MetaSerializable annotation should be used only on top-level annotation classes. Usage on nested annotation classes is deprecated and will yield errors in the future."
)
MAP.put(
SerializationErrors.INHERITABLE_SERIALINFO_CANT_BE_REPEATABLE,
"Repeatable serial info annotations can not be inheritable. Either remove @Repeatable or use a regular @SerialInfo annotation."
)
MAP.put(
SerializationErrors.EXTERNAL_SERIALIZER_USELESS,