[kxSerialization] Added diagnostic on useless Serializer annotation

Resolves Kotlin/kotlinx.serialization#2182

Merge-request: KT-MR-8718
Merged-by: Sergey Shanshin <Sergey.Shanshin@jetbrains.com>
This commit is contained in:
Sergey.Shanshin
2023-02-14 22:00:33 +00:00
committed by Space Team
parent 3124154aef
commit c9b8160f1e
10 changed files with 93 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);
DiagnosticFactory1<PsiElement, KotlinType> EXTERNAL_SERIALIZER_USELESS = DiagnosticFactory1.create(WARNING);
DiagnosticFactory2<PsiElement, KotlinType, KotlinType> EXTERNAL_CLASS_NOT_SERIALIZABLE = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, KotlinType, KotlinType> EXTERNAL_CLASS_IN_ANOTHER_MODULE = DiagnosticFactory2.create(ERROR);
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
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.name.FqName
import org.jetbrains.kotlin.name.JvmNames.TRANSIENT_ANNOTATION_FQ_NAME
@@ -30,7 +31,11 @@ import org.jetbrains.kotlin.util.slicedMap.WritableSlice
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
import org.jetbrains.kotlinx.serialization.compiler.backend.common.bodyPropertiesDescriptorsMap
import org.jetbrains.kotlinx.serialization.compiler.backend.common.primaryConstructorPropertiesDescriptorsMap
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SerializationErrors.EXTERNAL_SERIALIZER_USELESS
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.LOAD_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SAVE_NAME
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESC_FIELD_NAME
val SERIALIZABLE_PROPERTIES: WritableSlice<ClassDescriptor, SerializableProperties> = Slices.createSimpleSlice()
@@ -73,6 +78,31 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
val serializableDescriptor = serializableKType.toClassDescriptor ?: return
val props = SerializableProperties(serializableDescriptor, trace.bindingContext)
val descriptorOverridden = classDescriptor.unsubstitutedMemberScope
.getContributedVariables(SERIAL_DESC_FIELD_NAME, NoLookupLocation.FROM_BACKEND).singleOrNull {
it.kind != CallableMemberDescriptor.Kind.SYNTHESIZED
} != null
val serializeOverridden = classDescriptor.unsubstitutedMemberScope
.getContributedFunctions(SAVE_NAME, NoLookupLocation.FROM_BACKEND).singleOrNull {
it.valueParameters.size == 2
&& it.overriddenDescriptors.isNotEmpty()
&& it.kind != CallableMemberDescriptor.Kind.SYNTHESIZED
} != null
val deserializeOverridden = classDescriptor.unsubstitutedMemberScope
.getContributedFunctions(LOAD_NAME, NoLookupLocation.FROM_BACKEND).singleOrNull {
it.valueParameters.size == 1
&& it.overriddenDescriptors.isNotEmpty()
&& it.kind != CallableMemberDescriptor.Kind.SYNTHESIZED
} != null
if (descriptorOverridden && serializeOverridden && deserializeOverridden) {
val entry = classDescriptor.findAnnotationDeclaration(SerializationAnnotations.serializerAnnotationFqName)
trace.report(EXTERNAL_SERIALIZER_USELESS.on(entry ?: declaration, classDescriptor.defaultType))
return
}
if (!props.isExternallySerializable) {
val entry = classDescriptor.findAnnotationDeclaration(SerializationAnnotations.serializerAnnotationFqName)
val inSameModule =
@@ -165,6 +165,12 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
"@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.EXTERNAL_SERIALIZER_USELESS,
"@Serializer annotation has no effect on class ''{0}'', because all members of KSerializer are already overridden",
Renderers.RENDER_TYPE
)
MAP.put(
SerializationErrors.EXTERNAL_CLASS_NOT_SERIALIZABLE,
"Cannot generate external serializer ''{0}'': class ''{1}'' have constructor parameters which are not properties and therefore it is not serializable automatically",