[Parcelize] WriteWith Parceler type argument must be subtype of property
K2 checks that the entire Parceler of the WriteWith annotation is a subtype of the expected Parceler for the property, while K1 only checks that the type argument of the WriteWith Parceler is a subtype of the property type. This mismatch leads to inconsistencies between K1 and K2 diagnostic reporting. Switch K2 to K1 behavior so diagnostics are consistent. ^KT-60019 Fixed
This commit is contained in:
+12
-11
@@ -18,9 +18,9 @@ import org.jetbrains.kotlin.fir.declarations.toAnnotationClassLikeType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.getSuperTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DEPRECATED_RUNTIME_PACKAGE
|
||||
@@ -106,26 +106,27 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() {
|
||||
|
||||
// For `@WriteWith<P>` check that `P` is an object.
|
||||
val parcelerType = annotationCall.typeArguments.singleOrNull()?.toConeTypeProjection()?.type ?: return
|
||||
if (parcelerType.toRegularClassSymbol(context.session)?.classKind != ClassKind.OBJECT) {
|
||||
val parcelerTypeSymbol = parcelerType.toRegularClassSymbol(context.session)
|
||||
if (parcelerTypeSymbol?.classKind != ClassKind.OBJECT) {
|
||||
val reportElement = annotationCall.typeArguments.singleOrNull()?.source ?: annotationCall.source
|
||||
reporter.reportOn(reportElement, KtErrorsParcelize.PARCELER_SHOULD_BE_OBJECT, context)
|
||||
}
|
||||
|
||||
// For `@WriteWith<P> T` check that `P` is a subtype of `Parceler<T>`.
|
||||
// For `@WriteWith<P> T` where `P` is a subtype of `Parceler<E>`, check that T is a subtype of E.
|
||||
//
|
||||
// From the perspective of the `WriteWith` annotation call, `T` corresponds to the nearest enclosing annotation container
|
||||
// stripped of annotations.
|
||||
//
|
||||
// It's safe to assume that `Parceler` refers to `kotlinx.parcelize.Parceler` rather than `kotlinx.android.parcel.Parceler`,
|
||||
// since using the deprecated `WriteWith` annotation is an error.
|
||||
val targetType = (context.annotationContainers.lastOrNull() as? FirTypeRef)?.coneType?.withAttributes(ConeAttributes.Empty)
|
||||
?: return
|
||||
val expectedType = ConeClassLikeTypeImpl(
|
||||
ParcelizeNames.PARCELER_ID.toLookupTag(),
|
||||
arrayOf(targetType),
|
||||
isNullable = false
|
||||
)
|
||||
if (!parcelerType.isSubtypeOf(expectedType, context.session)) {
|
||||
val targetType = (context.annotationContainers.lastOrNull() as? FirTypeRef)?.coneType
|
||||
?.withAttributes(ConeAttributes.Empty) ?: return
|
||||
val parcelerSuperType = parcelerTypeSymbol?.getSuperTypes(context.session)
|
||||
?.firstOrNull { it.classId == ParcelizeNames.PARCELER_ID } ?: return
|
||||
val expectedType = parcelerSuperType.typeArguments.singleOrNull()?.type
|
||||
?.withAttributes(ConeAttributes.Empty) ?: return
|
||||
|
||||
if (!targetType.isSubtypeOf(expectedType, context.session)) {
|
||||
val reportElement = annotationCall.typeArguments.singleOrNull()?.source ?: annotationCall.source
|
||||
reporter.reportOn(reportElement, KtErrorsParcelize.PARCELER_TYPE_INCOMPATIBLE, parcelerType, targetType, context)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user