Parcelize: Add missing FIR diagnostics
This commit is contained in:
+86
-13
@@ -5,16 +5,24 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
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.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.FirAnnotationCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.classId
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
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.DEPRECATED_RUNTIME_PACKAGE
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_CLASS_IDS
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_CLASS_IDS
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_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
|
val resolvedAnnotationSymbol = annotationType.lookupTag.toFirRegularClassSymbol(context.session) ?: return
|
||||||
when (val annotationClassId = resolvedAnnotationSymbol.classId) {
|
when (val annotationClassId = resolvedAnnotationSymbol.classId) {
|
||||||
in TYPE_PARCELER_CLASS_IDS -> {
|
in TYPE_PARCELER_CLASS_IDS -> {
|
||||||
checkTypeParcelerUsage(expression, context, reporter)
|
if (checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)) {
|
||||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)
|
checkTypeParcelerUsage(expression, context, reporter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
in WRITE_WITH_CLASS_IDS -> {
|
in WRITE_WITH_CLASS_IDS -> {
|
||||||
checkWriteWithUsage(expression, context, reporter)
|
if (checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)) {
|
||||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = true)
|
checkWriteWithUsage(expression, context, reporter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
in IGNORED_ON_PARCEL_CLASS_IDS -> {
|
in IGNORED_ON_PARCEL_CLASS_IDS -> {
|
||||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false)
|
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false)
|
||||||
@@ -50,20 +60,83 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() {
|
|||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
isForbidden: Boolean
|
isForbidden: Boolean
|
||||||
) {
|
): Boolean {
|
||||||
if (annotationClassId.packageFqName == DEPRECATED_RUNTIME_PACKAGE) {
|
if (annotationClassId.packageFqName == DEPRECATED_RUNTIME_PACKAGE) {
|
||||||
val factory = if (isForbidden) KtErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION else KtErrorsParcelize.DEPRECATED_ANNOTATION
|
val factory = if (isForbidden) KtErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION else KtErrorsParcelize.DEPRECATED_ANNOTATION
|
||||||
reporter.reportOn(annotationCall.source, factory, context)
|
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 checkWriteWithUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
private fun checkTypeParcelerUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
checkIfTheContainingClassIsParcelize(annotationCall, context, reporter)
|
||||||
// TODO: this check checks type arguments of annotation which are not supported in FIR
|
|
||||||
|
// 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 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>`.
|
||||||
|
//
|
||||||
|
// 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 checkIfTheContainingClassIsParcelize(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
private fun checkWriteWithUsage(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
val enclosingClass = context.findClosestClassOrObject() ?: return
|
||||||
// TODO: this check checks type arguments of annotation which are not supported in FIR
|
|
||||||
|
if (!enclosingClass.symbol.isParcelize(context.session)) {
|
||||||
|
val reportElement = annotationCall.calleeReference.source ?: annotationCall.source
|
||||||
|
reporter.reportOn(reportElement, KtErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE, enclosingClass.symbol, context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+87
-11
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
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.annotations.AnnotationUseSiteTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.isEnumClass
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
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.hasBackingField
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
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.resolve.lookupSuperTypes
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.classId
|
import org.jetbrains.kotlin.parcelize.BuiltinParcelableTypes
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
||||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
|
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.IGNORED_ON_PARCEL_CLASS_IDS
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_ID
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_ID
|
||||||
@@ -55,7 +58,6 @@ object FirParcelizePropertyChecker : FirPropertyChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
|
||||||
private fun checkParcelableClassProperty(
|
private fun checkParcelableClassProperty(
|
||||||
property: FirProperty,
|
property: FirProperty,
|
||||||
containingClassSymbol: FirRegularClassSymbol,
|
containingClassSymbol: FirRegularClassSymbol,
|
||||||
@@ -63,18 +65,92 @@ object FirParcelizePropertyChecker : FirPropertyChecker() {
|
|||||||
reporter: DiagnosticReporter
|
reporter: DiagnosticReporter
|
||||||
) {
|
) {
|
||||||
val type = property.returnTypeRef.coneType
|
val type = property.returnTypeRef.coneType
|
||||||
if (type is ConeErrorType || containingClassSymbol.hasCustomParceler(context.session)) return
|
if (type is ConeErrorType || containingClassSymbol.hasCustomParceler(context.session) || property.hasIgnoredOnParcel()) {
|
||||||
/*
|
return
|
||||||
* TODO: abstract code from ParcelSerializer or IrParcelSerializerFactory to avoid duplication
|
}
|
||||||
* of allowed types checking
|
|
||||||
*/
|
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<FirAnnotation>, session: FirSession): Set<ConeKotlinType> =
|
||||||
|
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<ConeKotlinType>, 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 {
|
private fun FirProperty.hasIgnoredOnParcel(): Boolean {
|
||||||
return annotations.hasIgnoredOnParcel() || (getter?.annotations?.hasIgnoredOnParcel() ?: false)
|
return annotations.hasIgnoredOnParcel() || (getter?.annotations?.hasIgnoredOnParcel() ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun List<FirAnnotation>.hasIgnoredOnParcel(): Boolean {
|
private fun List<FirAnnotation>.hasIgnoredOnParcel(): Boolean {
|
||||||
return this.any {
|
return this.any {
|
||||||
if (it.annotationTypeRef.coneType.classId !in IGNORED_ON_PARCEL_CLASS_IDS) return@any false
|
if (it.annotationTypeRef.coneType.classId !in IGNORED_ON_PARCEL_CLASS_IDS) return@any false
|
||||||
|
|||||||
+1
-1
@@ -19,8 +19,8 @@ package org.jetbrains.kotlin.parcelize.fir.diagnostics
|
|||||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
|
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
|
||||||
import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderer
|
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_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.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.CREATOR_DEFINITION_IS_NOT_ALLOWED
|
||||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.DEPRECATED_ANNOTATION
|
import org.jetbrains.kotlin.parcelize.fir.diagnostics.KtErrorsParcelize.DEPRECATED_ANNOTATION
|
||||||
|
|||||||
+4
-2
@@ -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.INNER_MODIFIER
|
||||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.NAME_IDENTIFIER
|
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.NAME_IDENTIFIER
|
||||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.OVERRIDE_MODIFIER
|
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.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
|
||||||
@@ -43,8 +45,8 @@ object KtErrorsParcelize {
|
|||||||
val PARCELER_SHOULD_BE_OBJECT by error0<PsiElement>()
|
val PARCELER_SHOULD_BE_OBJECT by error0<PsiElement>()
|
||||||
val PARCELER_TYPE_INCOMPATIBLE by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
val PARCELER_TYPE_INCOMPATIBLE by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||||
val DUPLICATING_TYPE_PARCELERS by error0<PsiElement>()
|
val DUPLICATING_TYPE_PARCELERS by error0<PsiElement>()
|
||||||
val REDUNDANT_TYPE_PARCELER by warning1<PsiElement, KtClassOrObject>()
|
val REDUNDANT_TYPE_PARCELER by warning1<PsiElement, FirClassSymbol<*>>()
|
||||||
val CLASS_SHOULD_BE_PARCELIZE by error1<PsiElement, KtClassOrObject>()
|
val CLASS_SHOULD_BE_PARCELIZE by error1<PsiElement, FirClassSymbol<*>>()
|
||||||
val FORBIDDEN_DEPRECATED_ANNOTATION by error0<PsiElement>()
|
val FORBIDDEN_DEPRECATED_ANNOTATION by error0<PsiElement>()
|
||||||
val DEPRECATED_ANNOTATION by warning0<PsiElement>()
|
val DEPRECATED_ANNOTATION by warning0<PsiElement>()
|
||||||
val DEPRECATED_PARCELER by error0<PsiElement>()
|
val DEPRECATED_PARCELER by error0<PsiElement>()
|
||||||
|
|||||||
+9
-9
@@ -19,27 +19,27 @@ class StringClassParceler : Parceler<String> {
|
|||||||
override fun String.write(parcel: Parcel, flags: Int) = TODO()
|
override fun String.write(parcel: Parcel, flags: Int) = TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
@TypeParceler<String, StringParceler>
|
@<!CLASS_SHOULD_BE_PARCELIZE!>TypeParceler<!><String, StringParceler>
|
||||||
class MissingParcelizeAnnotation(val a: @WriteWith<StringParceler> String)
|
class MissingParcelizeAnnotation(val a: @<!CLASS_SHOULD_BE_PARCELIZE!>WriteWith<!><StringParceler> String)
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@TypeParceler<String, StringClassParceler>
|
@TypeParceler<String, StringClassParceler>
|
||||||
class ShouldBeClass(val a: @WriteWith<StringClassParceler> String) : Parcelable
|
class ShouldBeClass(val a: @WriteWith<<!PARCELER_SHOULD_BE_OBJECT!>StringClassParceler<!>> String) : Parcelable
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class Test(
|
class Test(
|
||||||
val a: @WriteWith<StringParceler> Int,
|
val a: @WriteWith<<!PARCELER_TYPE_INCOMPATIBLE!>StringParceler<!>> Int,
|
||||||
val b: @WriteWith<StringParceler> String,
|
val b: @WriteWith<StringParceler> String,
|
||||||
val c: @WriteWith<StringParceler> CharSequence,
|
val c: @WriteWith<<!PARCELER_TYPE_INCOMPATIBLE!>StringParceler<!>> CharSequence,
|
||||||
val d: @WriteWith<CharSequenceParceler> String,
|
val d: @WriteWith<<!PARCELER_TYPE_INCOMPATIBLE!>CharSequenceParceler<!>> String,
|
||||||
val e: @WriteWith<CharSequenceParceler> CharSequence
|
val e: @WriteWith<CharSequenceParceler> CharSequence
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@TypeParceler<String, StringParceler>
|
@TypeParceler<String, StringParceler>
|
||||||
class Test2(@TypeParceler<String, StringParceler> val a: String) : Parcelable
|
class Test2(@<!REDUNDANT_TYPE_PARCELER!>TypeParceler<!><String, StringParceler> val a: String) : Parcelable
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@TypeParceler<String, StringParceler>
|
@TypeParceler<<!DUPLICATING_TYPE_PARCELERS!>String<!>, StringParceler>
|
||||||
@TypeParceler<String, CharSequenceParceler>
|
@TypeParceler<<!DUPLICATING_TYPE_PARCELERS!>String<!>, CharSequenceParceler>
|
||||||
class Test3(val a: String) : Parcelable
|
class Test3(val a: String) : Parcelable
|
||||||
|
|||||||
@@ -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<Foo> {
|
|
||||||
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
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
package test
|
package test
|
||||||
|
|
||||||
import kotlinx.parcelize.*
|
import kotlinx.parcelize.*
|
||||||
|
|||||||
-17
@@ -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<Any, String>,
|
|
||||||
val e: @RawValue Any?,
|
|
||||||
val f: @RawValue Map<String, Any>,
|
|
||||||
val g: Map<String, @RawValue Any>,
|
|
||||||
val h: Map<@RawValue Any, List<@RawValue Any>>
|
|
||||||
) : Parcelable
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
package test
|
package test
|
||||||
|
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|||||||
Reference in New Issue
Block a user