diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeAnnotationChecker.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeAnnotationChecker.kt index a48a9ce8152..d1102a469ca 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeAnnotationChecker.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeAnnotationChecker.kt @@ -18,9 +18,6 @@ package org.jetbrains.kotlin.parcelize import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil -import kotlinx.parcelize.IgnoredOnParcel -import kotlinx.parcelize.TypeParceler -import kotlinx.parcelize.WriteWith import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind @@ -40,10 +37,22 @@ import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations import org.jetbrains.kotlin.types.typeUtil.supertypes class ParcelizeAnnotationChecker : CallChecker { + @Suppress("DEPRECATION") companion object { - val TYPE_PARCELER_FQNAME = FqName(TypeParceler::class.java.name) - val WRITE_WITH_FQNAME = FqName(WriteWith::class.java.name) - val IGNORED_ON_PARCEL_FQNAME = FqName(IgnoredOnParcel::class.java.name) + val TYPE_PARCELER_FQ_NAMES = listOf( + FqName(kotlinx.parcelize.TypeParceler::class.java.name), + FqName(kotlinx.android.parcel.TypeParceler::class.java.name) + ) + + val WRITE_WITH_FQ_NAMES = listOf( + FqName(kotlinx.parcelize.WriteWith::class.java.name), + FqName(kotlinx.android.parcel.WriteWith::class.java.name) + ) + + val IGNORED_ON_PARCEL_FQ_NAMES = listOf( + FqName(kotlinx.parcelize.IgnoredOnParcel::class.java.name), + FqName(kotlinx.android.parcel.IgnoredOnParcel::class.java.name) + ) } override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { @@ -53,15 +62,15 @@ class ParcelizeAnnotationChecker : CallChecker { val annotationEntry = resolvedCall.call.callElement.getNonStrictParentOfType() ?: return val annotationOwner = annotationEntry.getStrictParentOfType() ?: return - if (annotationClass.fqNameSafe == TYPE_PARCELER_FQNAME) { + if (annotationClass.fqNameSafe in TYPE_PARCELER_FQ_NAMES) { checkTypeParcelerUsage(resolvedCall, annotationEntry, context, annotationOwner) } - if (annotationClass.fqNameSafe == WRITE_WITH_FQNAME) { + if (annotationClass.fqNameSafe in WRITE_WITH_FQ_NAMES) { checkWriteWithUsage(resolvedCall, annotationEntry, context, annotationOwner) } - if (annotationClass.fqNameSafe == IGNORED_ON_PARCEL_FQNAME) { + if (annotationClass.fqNameSafe in IGNORED_ON_PARCEL_FQ_NAMES) { checkIgnoredOnParcelUsage(annotationEntry, context, annotationOwner) } } @@ -84,7 +93,7 @@ class ParcelizeAnnotationChecker : CallChecker { val thisMappedType = resolvedCall.typeArguments.values.takeIf { it.size == 2 }?.first() ?: return val duplicatingAnnotationCount = descriptor.annotations - .filter { it.fqName == TYPE_PARCELER_FQNAME } + .filter { it.fqName in TYPE_PARCELER_FQ_NAMES } .mapNotNull { it.type.arguments.takeIf { args -> args.size == 2 }?.first()?.type } .count { it == thisMappedType } diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeCodegenExtension.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeCodegenExtension.kt index 0176567e4a5..35dfb95aac1 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeCodegenExtension.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeCodegenExtension.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.parcelize import com.intellij.psi.PsiElement -import kotlinx.parcelize.TypeParceler import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy.CodegenBased @@ -17,8 +16,8 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.parcelize.ParcelizeAnnotationChecker.Companion.TYPE_PARCELER_FQ_NAMES import org.jetbrains.kotlin.parcelize.ParcelizeResolveExtension.Companion.createMethod import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.* import org.jetbrains.kotlin.parcelize.serializers.* @@ -427,10 +426,9 @@ open class ParcelizeCodegenExtension : ParcelizeExtensionBase, ExpressionCodegen } internal fun getTypeParcelers(annotations: Annotations): List { - val typeParcelerFqName = FqName(TypeParceler::class.java.name) val serializers = mutableListOf() - for (annotation in annotations.filter { it.fqName == typeParcelerFqName }) { + for (annotation in annotations.filter { it.fqName in TYPE_PARCELER_FQ_NAMES }) { val (mappedType, parcelerType) = annotation.type.arguments.takeIf { it.size == 2 } ?: continue serializers += TypeParcelerMapping(mappedType.type, parcelerType.type) } diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeDeclarationChecker.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeDeclarationChecker.kt index 3189f197468..56bcc1788b6 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeDeclarationChecker.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeDeclarationChecker.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.parcelize -import kotlinx.parcelize.IgnoredOnParcel import org.jetbrains.kotlin.codegen.ClassBuilderMode import org.jetbrains.kotlin.codegen.FrameMap import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -37,7 +36,10 @@ val ANDROID_PARCEL_CLASS_FQNAME = FqName("android.os.Parcel") class ParcelizeDeclarationChecker : DeclarationChecker { private companion object { - private val IGNORED_ON_PARCEL_FQNAME = FqName(IgnoredOnParcel::class.java.canonicalName) + private val IGNORED_ON_PARCEL_FQ_NAMES = listOf( + FqName(kotlinx.parcelize.IgnoredOnParcel::class.java.canonicalName), + FqName(kotlinx.android.parcel.IgnoredOnParcel::class.java.canonicalName) + ) } override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { @@ -91,7 +93,7 @@ class ParcelizeDeclarationChecker : DeclarationChecker { bindingContext: BindingContext ) { fun hasIgnoredOnParcel(): Boolean { - fun Annotations.hasIgnoredOnParcel() = any { it.fqName == IGNORED_ON_PARCEL_FQNAME } + fun Annotations.hasIgnoredOnParcel() = any { it.fqName in IGNORED_ON_PARCEL_FQ_NAMES } return property.annotations.hasIgnoredOnParcel() || (property.getter?.annotations?.hasIgnoredOnParcel() ?: false) } diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeResolveExtension.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeResolveExtension.kt index d46f4d05511..05eaf8694d7 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeResolveExtension.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ParcelizeResolveExtension.kt @@ -17,10 +17,10 @@ package org.jetbrains.kotlin.parcelize import com.intellij.psi.PsiElement -import kotlinx.parcelize.Parceler -import kotlinx.parcelize.Parcelize import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotated +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl @@ -169,11 +169,44 @@ interface ParcelizeSyntheticComponent { } } -val PARCELIZE_CLASS_FQNAME: FqName = FqName(Parcelize::class.java.canonicalName) -internal val PARCELER_FQNAME: FqName = FqName(Parceler::class.java.canonicalName) +val PARCELIZE_CLASS_FQ_NAMES: List = listOf( + FqName(kotlinx.parcelize.Parcelize::class.java.canonicalName), + FqName(kotlinx.android.parcel.Parcelize::class.java.canonicalName) +) + +internal val PARCELER_FQNAME = FqName(kotlinx.parcelize.Parceler::class.java.canonicalName) val ClassDescriptor.isParcelize: Boolean - get() = this.annotations.hasAnnotation(PARCELIZE_CLASS_FQNAME) + get() { + for (fqName in PARCELIZE_CLASS_FQ_NAMES) { + if (this.annotations.hasAnnotation(fqName)) { + return true + } + } -val KotlinType.isParceler - get() = constructor.declarationDescriptor?.fqNameSafe == PARCELER_FQNAME \ No newline at end of file + return false + } + +val KotlinType.isParceler: Boolean + get() = constructor.declarationDescriptor?.fqNameSafe == PARCELER_FQNAME + +fun Annotated.findAnyAnnotation(fqNames: List): AnnotationDescriptor? { + for (fqName in fqNames) { + val annotation = annotations.findAnnotation(fqName) + if (annotation != null) { + return annotation + } + } + + return null +} + +fun Annotated.hasAnyAnnotation(fqNames: List): Boolean { + for (fqName in fqNames) { + if (annotations.hasAnnotation(fqName)) { + return true + } + } + + return false +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt index 027f835ef12..85e6dfb0346 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelSerializerFactory.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.parcelize.serializers.RAW_VALUE_ANNOTATION_FQNAME +import org.jetbrains.kotlin.parcelize.serializers.RAW_VALUE_ANNOTATION_FQ_NAMES class IrParcelSerializerFactory(symbols: AndroidSymbols) { /** @@ -28,7 +28,7 @@ class IrParcelSerializerFactory(symbols: AndroidSymbols) { strict: Boolean = false, toplevel: Boolean = false ): IrParcelSerializer { - fun strict() = strict && !irType.hasAnnotation(RAW_VALUE_ANNOTATION_FQNAME) + fun strict() = strict && !irType.hasAnyAnnotation(RAW_VALUE_ANNOTATION_FQ_NAMES) scope.getCustomSerializer(irType)?.let { parceler -> return IrCustomParcelSerializer(parceler) diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelerScope.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelerScope.kt index 6574f1cd3a6..608c0e775b3 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelerScope.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/IrParcelerScope.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.typeOrNull import org.jetbrains.kotlin.ir.util.constructedClass import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable -import org.jetbrains.kotlin.ir.util.getAnnotation import org.jetbrains.kotlin.parcelize.ParcelizeAnnotationChecker // Keep track of all custom parcelers which are currently in scope. @@ -30,7 +29,7 @@ class IrParcelerScope(private val parent: IrParcelerScope? = null) { } fun IrParcelerScope?.getCustomSerializer(irType: IrType): IrClass? { - return irType.getAnnotation(ParcelizeAnnotationChecker.WRITE_WITH_FQNAME)?.let { writeWith -> + return irType.getAnyAnnotation(ParcelizeAnnotationChecker.WRITE_WITH_FQ_NAMES)?.let { writeWith -> (writeWith.type as IrSimpleType).arguments.single().typeOrNull!!.getClass()!! } ?: this?.get(irType) } @@ -41,7 +40,7 @@ fun IrParcelerScope?.hasCustomSerializer(irType: IrType): Boolean { fun IrAnnotationContainer.getParcelerScope(parent: IrParcelerScope? = null): IrParcelerScope? { val typeParcelerAnnotations = annotations.filterTo(mutableListOf()) { - it.symbol.owner.constructedClass.fqNameWhenAvailable == ParcelizeAnnotationChecker.TYPE_PARCELER_FQNAME + it.symbol.owner.constructedClass.fqNameWhenAvailable in ParcelizeAnnotationChecker.TYPE_PARCELER_FQ_NAMES } if (typeParcelerAnnotations.isEmpty()) diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/irUtils.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/irUtils.kt index 50403ecbcb2..ea6069bfebd 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/irUtils.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/ir/irUtils.kt @@ -8,12 +8,10 @@ package org.jetbrains.kotlin.parcelize.ir import org.jetbrains.kotlin.backend.common.ir.allOverridden import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrProperty -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol @@ -23,14 +21,14 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.parcelize.ANDROID_PARCELABLE_CLASS_FQNAME import org.jetbrains.kotlin.parcelize.ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME import org.jetbrains.kotlin.parcelize.PARCELER_FQNAME -import org.jetbrains.kotlin.parcelize.PARCELIZE_CLASS_FQNAME +import org.jetbrains.kotlin.parcelize.PARCELIZE_CLASS_FQ_NAMES import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase.Companion.CREATOR_NAME import org.jetbrains.kotlin.types.Variance // true if the class should be processed by the parcelize plugin val IrClass.isParcelize: Boolean - get() = kind in ParcelizeExtensionBase.ALLOWED_CLASS_KINDS && hasAnnotation(PARCELIZE_CLASS_FQNAME) + get() = kind in ParcelizeExtensionBase.ALLOWED_CLASS_KINDS && hasAnyAnnotation(PARCELIZE_CLASS_FQ_NAMES) // Finds the getter for a pre-existing CREATOR field on the class companion, which is used for manual Parcelable implementations in Kotlin. val IrClass.creatorGetter: IrSimpleFunctionSymbol? @@ -175,3 +173,24 @@ fun IrClass.getMethodWithoutArguments(name: String): IrSimpleFunction = function.name.asString() == name && function.dispatchReceiverParameter != null && function.extensionReceiverParameter == null && function.valueParameters.isEmpty() } + +internal fun IrAnnotationContainer.hasAnyAnnotation(fqNames: List): Boolean { + for (fqName in fqNames) { + if (hasAnnotation(fqName)) { + return true + } + } + + return false +} + +internal fun IrAnnotationContainer.getAnyAnnotation(fqNames: List): IrConstructorCall? { + for (fqName in fqNames) { + val annotation = getAnnotation(fqName) + if (annotation != null) { + return annotation + } + } + + return null +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/serializers/ParcelSerializer.kt b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/serializers/ParcelSerializer.kt index 3960d14d68f..0f2bd4021d2 100644 --- a/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/serializers/ParcelSerializer.kt +++ b/plugins/parcelize/parcelize-compiler/src/org/jetbrains/kotlin/parcelize/serializers/ParcelSerializer.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.parcelize.serializers -import kotlinx.parcelize.WriteWith import org.jetbrains.kotlin.codegen.FrameMap import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.ClassDescriptor @@ -27,6 +26,8 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.kotlin.TypeMappingMode import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.parcelize.findAnyAnnotation +import org.jetbrains.kotlin.parcelize.hasAnyAnnotation import org.jetbrains.kotlin.parcelize.isParcelize import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe @@ -42,7 +43,10 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import java.util.* import java.util.concurrent.ConcurrentHashMap -val RAW_VALUE_ANNOTATION_FQNAME = FqName("kotlinx.parcelize.RawValue") +val RAW_VALUE_ANNOTATION_FQ_NAMES = listOf( + FqName(kotlinx.parcelize.RawValue::class.java.name), + FqName(kotlinx.android.parcel.RawValue::class.java.name) +) internal typealias TypeParcelerMapping = Pair @@ -64,7 +68,10 @@ interface ParcelSerializer { } companion object { - private val WRITE_WITH_FQNAME = FqName(WriteWith::class.java.name) + private val WRITE_WITH_FQ_NAMES = listOf( + FqName(kotlinx.parcelize.WriteWith::class.java.name), + FqName(kotlinx.android.parcel.WriteWith::class.java.name), + ) private fun KotlinTypeMapper.mapTypeSafe(type: KotlinType, forceBoxed: Boolean) = when { type.isError -> Type.getObjectType("java/lang/Object") @@ -81,10 +88,10 @@ interface ParcelSerializer { val typeMapper = context.typeMapper val className = asmType.className - fun strict() = strict && !type.annotations.hasAnnotation(RAW_VALUE_ANNOTATION_FQNAME) + fun strict() = strict && !type.hasAnyAnnotation(RAW_VALUE_ANNOTATION_FQ_NAMES) fun findCustomParcelerType(type: KotlinType): KotlinType? { - type.annotations.findAnnotation(WRITE_WITH_FQNAME)?.let { writeWith -> + type.findAnyAnnotation(WRITE_WITH_FQ_NAMES)?.let { writeWith -> val parceler = writeWith.type.arguments.singleOrNull()?.type if (parceler != null && !parceler.isError) { return parceler @@ -371,7 +378,7 @@ interface ParcelSerializer { } else -> { - if (strict && !type.annotations.hasAnnotation(RAW_VALUE_ANNOTATION_FQNAME)) + if (strict && !type.hasAnyAnnotation(RAW_VALUE_ANNOTATION_FQ_NAMES)) throw IllegalArgumentException("Illegal type") else GenericParcelSerializer(asmType)