Implement inspection about no-arg constructor in non-serializable supertype

This commit is contained in:
Leonid Startsev
2019-05-30 16:43:27 +03:00
parent 8f77b55ada
commit dc79b99dd2
3 changed files with 21 additions and 7 deletions
@@ -16,13 +16,16 @@ import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
import static org.jetbrains.kotlin.diagnostics.Severity.WARNING; import static org.jetbrains.kotlin.diagnostics.Severity.WARNING;
public interface SerializationErrors { public interface SerializationErrors {
DiagnosticFactory0<KtAnnotationEntry> SERIALIZABLE_ANNOTATION_IGNORED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INLINE_CLASSES_NOT_SUPPORTED = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<PsiElement> INLINE_CLASSES_NOT_SUPPORTED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> SERIALIZABLE_ANNOTATION_IGNORED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> NON_SERIALIZABLE_PARENT_MUST_HAVE_NOARG_CTOR = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> PRIMARY_CONSTRUCTOR_PARAMETER_IS_NOT_A_PROPERTY = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtAnnotationEntry> PRIMARY_CONSTRUCTOR_PARAMETER_IS_NOT_A_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<KtAnnotationEntry, String> DUPLICATE_SERIAL_NAME = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtAnnotationEntry, String> DUPLICATE_SERIAL_NAME = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> SERIALIZER_NOT_FOUND = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<PsiElement> SERIALIZER_NOT_FOUND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, KotlinType> SERIALIZER_NULLABILITY_INCOMPATIBLE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, KotlinType> SERIALIZER_NULLABILITY_INCOMPATIBLE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> TRANSIENT_MISSING_INITIALIZER = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<PsiElement> TRANSIENT_MISSING_INITIALIZER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> TRANSIENT_IS_REDUNDANT = DiagnosticFactory0.create(WARNING); DiagnosticFactory0<PsiElement> TRANSIENT_IS_REDUNDANT = DiagnosticFactory0.create(WARNING);
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.hasBackingField import org.jetbrains.kotlin.resolve.hasBackingField
import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -52,6 +53,12 @@ class SerializationPluginDeclarationChecker : DeclarationChecker {
if (!descriptor.isInternalSerializable && !descriptor.hasCompanionObjectAsSerializer) { if (!descriptor.isInternalSerializable && !descriptor.hasCompanionObjectAsSerializer) {
trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.SERIALIZABLE_ANNOTATION_IGNORED) trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.SERIALIZABLE_ANNOTATION_IGNORED)
} }
// check that we can instantiate supertype
val superClass = descriptor.getSuperClassOrAny()
if (!superClass.isInternalSerializable && superClass.constructors.singleOrNull { it.valueParameters.size == 0 } == null) {
trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.NON_SERIALIZABLE_PARENT_MUST_HAVE_NOARG_CTOR)
}
} }
private fun buildSerializableProperties(descriptor: ClassDescriptor, trace: BindingTrace): SerializableProperties? { private fun buildSerializableProperties(descriptor: ClassDescriptor, trace: BindingTrace): SerializableProperties? {
@@ -14,18 +14,26 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
override fun getMap() = MAP override fun getMap() = MAP
init { init {
MAP.put(
SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED,
"Inline classes are not supported by serialization framework yet."
)
MAP.put( MAP.put(
SerializationErrors.SERIALIZABLE_ANNOTATION_IGNORED, SerializationErrors.SERIALIZABLE_ANNOTATION_IGNORED,
"@Serializable annotation would be ignored because it is impossible to serialize automatically interfaces or enums. " + "@Serializable annotation would be ignored because it is impossible to serialize automatically interfaces or enums. " +
"Provide serializer manually via e.g. companion object" "Provide serializer manually via e.g. companion object"
) )
MAP.put(
SerializationErrors.NON_SERIALIZABLE_PARENT_MUST_HAVE_NOARG_CTOR,
"Impossible to make this class serializable because its parent is not serializable and does not have exactly one constructor without arguments"
)
MAP.put( MAP.put(
SerializationErrors.PRIMARY_CONSTRUCTOR_PARAMETER_IS_NOT_A_PROPERTY, SerializationErrors.PRIMARY_CONSTRUCTOR_PARAMETER_IS_NOT_A_PROPERTY,
"This class is not serializable automatically because it has primary constructor parameters which are not properties." "This class is not serializable automatically because it has primary constructor parameters which are not properties."
) )
MAP.put( MAP.put(
SerializationErrors.DUPLICATE_SERIAL_NAME, SerializationErrors.DUPLICATE_SERIAL_NAME,
"Serializable class has duplicate serial name of property ''{0}'', either in it or its parents.", "Serializable class has duplicate serial name of property ''{0}'', either in it or its supertypes.",
Renderers.STRING Renderers.STRING
) )
MAP.put( MAP.put(
@@ -35,7 +43,7 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
) )
MAP.put( MAP.put(
SerializationErrors.SERIALIZER_NULLABILITY_INCOMPATIBLE, SerializationErrors.SERIALIZER_NULLABILITY_INCOMPATIBLE,
"This type is not-nullable and therefore can not be serialized with serializer for nullable type ''{0}''", "This type is non-nullable and therefore can not be serialized with serializer for nullable type ''{0}''",
Renderers.RENDER_TYPE Renderers.RENDER_TYPE
) )
MAP.put( MAP.put(
@@ -46,9 +54,5 @@ object SerializationPluginErrorsRendering : DefaultErrorMessages.Extension {
SerializationErrors.TRANSIENT_IS_REDUNDANT, SerializationErrors.TRANSIENT_IS_REDUNDANT,
"This property does not have backing field which makes it non-serializable and therefore @Transient is redundant" "This property does not have backing field which makes it non-serializable and therefore @Transient is redundant"
) )
MAP.put(
SerializationErrors.INLINE_CLASSES_NOT_SUPPORTED,
"Inline classes are not supported by serialization framework yet."
)
} }
} }