From 58e51919bd61079dc5d43d4eccbd1356b1df4cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Mon, 25 Jul 2022 20:24:52 +0200 Subject: [PATCH] Parcelize: Add missing FIR diagnostics --- .../FirParcelizeAnnotationChecker.kt | 99 ++++++++++++++++--- .../FirParcelizePropertyChecker.kt | 98 +++++++++++++++--- .../KtDefaultErrorMessagesParcelize.kt | 2 +- .../fir/diagnostics/KtErrorsParcelize.kt | 6 +- .../diagnostics/customParcelers.fir.kt | 18 ++-- .../testData/diagnostics/kt20062.fir.kt | 20 ---- .../testData/diagnostics/kt20062.kt | 1 + .../diagnostics/unsupportedType.fir.kt | 17 ---- .../testData/diagnostics/unsupportedType.kt | 1 + 9 files changed, 189 insertions(+), 73 deletions(-) delete mode 100644 plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.fir.kt delete mode 100644 plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.fir.kt diff --git a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizeAnnotationChecker.kt b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizeAnnotationChecker.kt index becdf89393d..db8eff03468 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizeAnnotationChecker.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizeAnnotationChecker.kt @@ -5,16 +5,24 @@ package org.jetbrains.kotlin.parcelize.fir.diagnostics +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker +import org.jetbrains.kotlin.fir.analysis.checkers.findClosestClassOrObject +import org.jetbrains.kotlin.fir.correspondingProperty +import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.expressions.classId import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol -import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl +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 import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_CLASS_IDS import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_CLASS_IDS @@ -28,12 +36,14 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() { val resolvedAnnotationSymbol = annotationType.lookupTag.toFirRegularClassSymbol(context.session) ?: return when (val annotationClassId = resolvedAnnotationSymbol.classId) { in TYPE_PARCELER_CLASS_IDS -> { - checkTypeParcelerUsage(expression, context, reporter) - checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true) + if (checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)) { + checkTypeParcelerUsage(expression, context, reporter) + } } in WRITE_WITH_CLASS_IDS -> { - checkWriteWithUsage(expression, context, reporter) - checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true) + if (checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)) { + checkWriteWithUsage(expression, context, reporter) + } } in IGNORED_ON_PARCEL_CLASS_IDS -> { checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false) @@ -50,20 +60,83 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() { context: CheckerContext, reporter: DiagnosticReporter, isForbidden: Boolean - ) { + ): Boolean { if (annotationClassId.packageFqName == DEPRECATED_RUNTIME_PACKAGE) { val factory = if (isForbidden) KtErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION else KtErrorsParcelize.DEPRECATED_ANNOTATION reporter.reportOn(annotationCall.source, factory, context) + return false + } + return true + } + + private fun checkTypeParcelerUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) { + val thisMappedType = annotationCall.typeArguments.takeIf { it.size == 2 }?.first()?.toConeTypeProjection()?.type + ?: return + + val annotationContainer = context.annotationContainers.lastOrNull() + val duplicatingAnnotationCount = annotationContainer + ?.annotations + ?.filter { it.classId in TYPE_PARCELER_CLASS_IDS } + ?.mapNotNull { it.typeArguments.takeIf { it.size == 2 }?.first()?.toConeTypeProjection()?.type } + ?.count { it == thisMappedType } + + if (duplicatingAnnotationCount != null && duplicatingAnnotationCount > 1) { + val reportElement = annotationCall.typeArguments.firstOrNull()?.source ?: annotationCall.source + reporter.reportOn(reportElement, KtErrorsParcelize.DUPLICATING_TYPE_PARCELERS, context) + return + } + + checkIfTheContainingClassIsParcelize(annotationCall, context, reporter) + + // If we are looking at a parameter of the primary constructor of a class, check that the + // enclosing class doesn't have the same TypeParceler annotation. + if (annotationContainer is FirValueParameter && annotationContainer.correspondingProperty?.fromPrimaryConstructor == true) { + val enclosingClass = context.findClosestClassOrObject() ?: return + + val annotationType = annotationCall.typeRef.coneType + if (enclosingClass.annotations.any { it.typeRef.coneType == annotationType }) { + val reportElement = annotationCall.calleeReference.source ?: annotationCall.source + reporter.reportOn(reportElement, KtErrorsParcelize.REDUNDANT_TYPE_PARCELER, enclosingClass.symbol, context) + } } } - @Suppress("UNUSED_PARAMETER") - private fun checkTypeParcelerUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) { - // TODO: this check checks type arguments of annotation which are not supported in FIR + private fun checkWriteWithUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) { + checkIfTheContainingClassIsParcelize(annotationCall, context, reporter) + + // For `@WriteWith

` check that `P` is an object. + val parcelerType = annotationCall.typeArguments.singleOrNull()?.toConeTypeProjection()?.type ?: return + if (parcelerType.toRegularClassSymbol(context.session)?.classKind != ClassKind.OBJECT) { + val reportElement = annotationCall.typeArguments.singleOrNull()?.source ?: annotationCall.source + reporter.reportOn(reportElement, KtErrorsParcelize.PARCELER_SHOULD_BE_OBJECT, context) + } + + // For `@WriteWith

T` check that `P` is a subtype of `Parceler`. + // + // 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( + ConeClassLikeLookupTagImpl(ParcelizeNames.PARCELER_ID), + arrayOf(targetType), + isNullable = false + ) + if (!parcelerType.isSubtypeOf(expectedType, context.session)) { + val reportElement = annotationCall.typeArguments.singleOrNull()?.source ?: annotationCall.source + reporter.reportOn(reportElement, KtErrorsParcelize.PARCELER_TYPE_INCOMPATIBLE, parcelerType, targetType, context) + } } - @Suppress("UNUSED_PARAMETER") - private fun checkWriteWithUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) { - // TODO: this check checks type arguments of annotation which are not supported in FIR + private fun checkIfTheContainingClassIsParcelize(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) { + val enclosingClass = context.findClosestClassOrObject() ?: return + + if (!enclosingClass.symbol.isParcelize(context.session)) { + val reportElement = annotationCall.calleeReference.source ?: annotationCall.source + reporter.reportOn(reportElement, KtErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE, enclosingClass.symbol, context) + } } } diff --git a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt index ebffc4fdf7d..30af1fb50f9 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/FirParcelizePropertyChecker.kt @@ -5,7 +5,9 @@ package org.jetbrains.kotlin.parcelize.fir.diagnostics +import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.descriptors.isEnumClass import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.FirSession @@ -18,12 +20,13 @@ import org.jetbrains.kotlin.fir.declarations.utils.fromPrimaryConstructor import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField import org.jetbrains.kotlin.fir.declarations.utils.isCompanion import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.resolve.fqName +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.types.ConeErrorType -import org.jetbrains.kotlin.fir.types.classId -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.toRegularClassSymbol +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.parcelize.BuiltinParcelableTypes +import org.jetbrains.kotlin.parcelize.ParcelizeNames import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_CLASS_IDS import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_ID @@ -55,7 +58,6 @@ object FirParcelizePropertyChecker : FirPropertyChecker() { } } - @Suppress("UNUSED_PARAMETER") private fun checkParcelableClassProperty( property: FirProperty, containingClassSymbol: FirRegularClassSymbol, @@ -63,18 +65,92 @@ object FirParcelizePropertyChecker : FirPropertyChecker() { reporter: DiagnosticReporter ) { val type = property.returnTypeRef.coneType - if (type is ConeErrorType || containingClassSymbol.hasCustomParceler(context.session)) return - /* - * TODO: abstract code from ParcelSerializer or IrParcelSerializerFactory to avoid duplication - * of allowed types checking - */ + if (type is ConeErrorType || containingClassSymbol.hasCustomParceler(context.session) || property.hasIgnoredOnParcel()) { + return + } + + val session = context.session + val customParcelerTypes = getCustomParcelerTypes(property.annotations + containingClassSymbol.annotations, session) + if (!checkParcelableType(type, customParcelerTypes, session)) { + reporter.reportOn(property.returnTypeRef.source, KtErrorsParcelize.PARCELABLE_TYPE_NOT_SUPPORTED, context) + } + } + + private fun getCustomParcelerTypes(annotations: List, session: FirSession): Set = + annotations.mapNotNullTo(mutableSetOf()) { annotation -> + if (annotation.fqName(session) in ParcelizeNames.TYPE_PARCELER_FQ_NAMES && annotation.typeArguments.size == 2) { + annotation.typeArguments[0].toConeTypeProjection().type + } else { + null + } + } + + private fun checkParcelableType(type: ConeKotlinType, customParcelerTypes: Set, session: FirSession): Boolean { + if (type.hasParcelerAnnotation(session) || type in customParcelerTypes) { + return true + } + + val upperBound = type.getErasedUpperBound(session) + val symbol = upperBound?.toRegularClassSymbol(session) + ?: return false + + if (symbol.classKind.isSingleton || symbol.classKind.isEnumClass) { + return true + } + + val fqName = symbol.classId.asFqNameString() + if (fqName in BuiltinParcelableTypes.PARCELABLE_BASE_TYPE_FQNAMES) { + return true + } + + if (fqName in BuiltinParcelableTypes.PARCELABLE_CONTAINER_FQNAMES) { + return upperBound.typeArguments.all { projection -> + projection.type?.let { checkParcelableType(it, customParcelerTypes, session) } ?: false + } + } + + return with(session.typeContext) { + type.anySuperTypeConstructor { + it is ConeKotlinType && + (it.classId?.asFqNameString() in BuiltinParcelableTypes.PARCELABLE_SUPERTYPE_FQNAMES || + it.isBuiltinFunctionalType(session)) + } + } + } + + private fun ConeKotlinType.getErasedUpperBound(session: FirSession): ConeClassLikeType? = + when (this) { + is ConeClassLikeType -> + fullyExpandedType(session) + + is ConeTypeParameterType -> { + val bounds = lookupTag.typeParameterSymbol.resolvedBounds + val representativeBound = bounds.firstOrNull { + val kind = it.coneType.toRegularClassSymbol(session)?.classKind + ?: return@firstOrNull false + kind != ClassKind.INTERFACE && kind != ClassKind.ANNOTATION_CLASS + } ?: bounds.first() + representativeBound.coneType.getErasedUpperBound(session) + } + + else -> + null + } + + private fun ConeKotlinType.hasParcelerAnnotation(session: FirSession): Boolean { + for (annotation in customAnnotations) { + val fqName = annotation.fqName(session) + if (fqName in ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES || fqName in ParcelizeNames.WRITE_WITH_FQ_NAMES) { + return true + } + } + return false } private fun FirProperty.hasIgnoredOnParcel(): Boolean { return annotations.hasIgnoredOnParcel() || (getter?.annotations?.hasIgnoredOnParcel() ?: false) } - private fun List.hasIgnoredOnParcel(): Boolean { return this.any { if (it.annotationTypeRef.coneType.classId !in IGNORED_ON_PARCEL_CLASS_IDS) return@any false diff --git a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtDefaultErrorMessagesParcelize.kt b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtDefaultErrorMessagesParcelize.kt index 1cbdb321eb5..4fe91029615 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtDefaultErrorMessagesParcelize.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtDefaultErrorMessagesParcelize.kt @@ -19,8 +19,8 @@ package org.jetbrains.kotlin.parcelize.fir.diagnostics import org.jetbrains.kotlin.diagnostics.KtDiagnostic import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderer -import org.jetbrains.kotlin.diagnostics.rendering.Renderers.RENDER_CLASS_OR_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.DEPRECATED_ANNOTATION diff --git a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtErrorsParcelize.kt b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtErrorsParcelize.kt index 25ba24eb0d2..e3b875c9960 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtErrorsParcelize.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.k2/src/org/jetbrains/kotlin/parcelize/fir/diagnostics/KtErrorsParcelize.kt @@ -22,6 +22,8 @@ import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.DELEG import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.INNER_MODIFIER import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.NAME_IDENTIFIER import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.OVERRIDE_MODIFIER +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.psi.KtClassOrObject @@ -43,8 +45,8 @@ object KtErrorsParcelize { val PARCELER_SHOULD_BE_OBJECT by error0() val PARCELER_TYPE_INCOMPATIBLE by error2() val DUPLICATING_TYPE_PARCELERS by error0() - val REDUNDANT_TYPE_PARCELER by warning1() - val CLASS_SHOULD_BE_PARCELIZE by error1() + val REDUNDANT_TYPE_PARCELER by warning1>() + val CLASS_SHOULD_BE_PARCELIZE by error1>() val FORBIDDEN_DEPRECATED_ANNOTATION by error0() val DEPRECATED_ANNOTATION by warning0() val DEPRECATED_PARCELER by error0() diff --git a/plugins/parcelize/parcelize-compiler/testData/diagnostics/customParcelers.fir.kt b/plugins/parcelize/parcelize-compiler/testData/diagnostics/customParcelers.fir.kt index 0e856f4efa3..bca096f35d5 100644 --- a/plugins/parcelize/parcelize-compiler/testData/diagnostics/customParcelers.fir.kt +++ b/plugins/parcelize/parcelize-compiler/testData/diagnostics/customParcelers.fir.kt @@ -19,27 +19,27 @@ class StringClassParceler : Parceler { override fun String.write(parcel: Parcel, flags: Int) = TODO() } -@TypeParceler -class MissingParcelizeAnnotation(val a: @WriteWith String) +@TypeParceler +class MissingParcelizeAnnotation(val a: @WriteWith String) @Parcelize @TypeParceler -class ShouldBeClass(val a: @WriteWith String) : Parcelable +class ShouldBeClass(val a: @WriteWith<StringClassParceler> String) : Parcelable @Parcelize class Test( - val a: @WriteWith Int, + val a: @WriteWith<StringParceler> Int, val b: @WriteWith String, - val c: @WriteWith CharSequence, - val d: @WriteWith String, + val c: @WriteWith<StringParceler> CharSequence, + val d: @WriteWith<CharSequenceParceler> String, val e: @WriteWith CharSequence ) : Parcelable @Parcelize @TypeParceler -class Test2(@TypeParceler val a: String) : Parcelable +class Test2(@TypeParceler val a: String) : Parcelable @Parcelize -@TypeParceler -@TypeParceler +@TypeParceler<String, StringParceler> +@TypeParceler<String, CharSequenceParceler> class Test3(val a: String) : Parcelable diff --git a/plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.fir.kt b/plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.fir.kt deleted file mode 100644 index 939b87f978b..00000000000 --- a/plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.fir.kt +++ /dev/null @@ -1,20 +0,0 @@ -package test - -import kotlinx.parcelize.* -import android.os.* - -class Box(val value: String) - -@Parcelize -class Foo(val box: Box): Parcelable { - companion object : Parceler { - override fun create(parcel: Parcel) = Foo(Box(parcel.readString())) - - override fun Foo.write(parcel: Parcel, flags: Int) { - parcel.writeString(box.value) - } - } -} - -@Parcelize -class Foo2(val box: Box): Parcelable diff --git a/plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.kt b/plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.kt index 36f692501ed..198d8cba6e4 100644 --- a/plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.kt +++ b/plugins/parcelize/parcelize-compiler/testData/diagnostics/kt20062.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL package test import kotlinx.parcelize.* diff --git a/plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.fir.kt b/plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.fir.kt deleted file mode 100644 index e1d1b2cc392..00000000000 --- a/plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.fir.kt +++ /dev/null @@ -1,17 +0,0 @@ -package test - -import kotlinx.parcelize.Parcelize -import kotlinx.parcelize.RawValue -import android.os.Parcelable - -@Parcelize -class User( - val a: String, - val b: Any, - val c: Any?, - val d: Map, - val e: @RawValue Any?, - val f: @RawValue Map, - val g: Map, - val h: Map<@RawValue Any, List<@RawValue Any>> -) : Parcelable diff --git a/plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.kt b/plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.kt index 74956c162a1..56b5288b25a 100644 --- a/plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.kt +++ b/plugins/parcelize/parcelize-compiler/testData/diagnostics/unsupportedType.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL package test import kotlinx.parcelize.Parcelize