Prohibit Array<T> in @Serializable classes

because it's impossible to correctly create array reflectively without
knowing correct KClass.

Fixes https://github.com/Kotlin/kotlinx.serialization/issues/1243
This commit is contained in:
Leonid Startsev
2022-09-26 19:00:48 +02:00
committed by Space Team
parent 596949a501
commit 090aec6b3b
9 changed files with 65 additions and 4 deletions
@@ -32,6 +32,8 @@ public interface SerializationErrors {
DiagnosticFactory1<PsiElement, KotlinType> LOCAL_SERIALIZER_USAGE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> TRANSIENT_MISSING_INITIALIZER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> GENERIC_ARRAY_ELEMENT_NOT_SUPPORTED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> TRANSIENT_IS_REDUNDANT = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> JSON_FORMAT_REDUNDANT_DEFAULT = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<PsiElement> JSON_FORMAT_REDUNDANT = DiagnosticFactory0.create(WARNING);
@@ -69,7 +69,8 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
val entry = classDescriptor.findAnnotationDeclaration(SerializationAnnotations.serializerAnnotationFqName)
val inSameModule =
trace.bindingContext[BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, serializableDescriptor.fqNameUnsafe] != null
val diagnostic = if (inSameModule) SerializationErrors.EXTERNAL_CLASS_NOT_SERIALIZABLE else SerializationErrors.EXTERNAL_CLASS_IN_ANOTHER_MODULE
val diagnostic =
if (inSameModule) SerializationErrors.EXTERNAL_CLASS_NOT_SERIALIZABLE else SerializationErrors.EXTERNAL_CLASS_IN_ANOTHER_MODULE
trace.report(diagnostic.on(entry ?: declaration, classDescriptor.defaultType, serializableKType))
}
@@ -263,6 +264,7 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
}
}
private fun ClassDescriptor.isSerializableEnumWithMissingSerializer(): Boolean {
if (kind != ClassKind.ENUM_CLASS) return false
if (hasSerializableOrMetaAnnotation) return false
@@ -344,10 +346,23 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
generatorContextForAnalysis.checkTypeArguments(it.module, it.type, element, trace, propertyPsi)
} else {
generatorContextForAnalysis.checkType(it.module, it.type, ktType, trace, propertyPsi)
checkGenericArrayType(it.type, ktType, trace, propertyPsi)
}
}
}
private fun checkGenericArrayType(
type: KotlinType,
ktType: KtTypeReference?,
trace: BindingTrace,
fallbackElement: PsiElement
) {
if (KotlinBuiltIns.isArray(type) && type.arguments.first().type.genericIndex != null) {
// Array<T> is unsupported, since we can't get T::class from KSerializer<T>
trace.report(SerializationErrors.GENERIC_ARRAY_ELEMENT_NOT_SUPPORTED.on(ktType ?: fallbackElement))
}
}
private fun AbstractSerialGenerator.checkTypeArguments(
module: ModuleDescriptor,
type: KotlinType,
@@ -95,6 +95,10 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
SerializationErrors.TRANSIENT_IS_REDUNDANT,
"Property does not have backing field which makes it non-serializable and therefore @Transient is redundant"
)
MAP.put(
SerializationErrors.GENERIC_ARRAY_ELEMENT_NOT_SUPPORTED,
"Serialization of Arrays with generic type arguments is impossible because of unknown compile-time type."
)
MAP.put(
SerializationErrors.JSON_FORMAT_REDUNDANT_DEFAULT,
"Redundant creation of Json default format. Creating instances for each usage can be slow."