[Parcelize] Allow parcelize to work on common code in multiplatform.
Since parcelize is Android specific, it should only be enabled for Android compilation. In order to allow parcelize to generate code for declarations in common code, we make checkers platform checkers and we allow the registration of an additional annotations to trigger parcelize processing. That way, code such as: ``` package my.package annotation class Parcelize expect interface MyParcelable @Parcelize data class User(name: String): MyParcelable ``` Will work with an Android platform actual of the form: ``` actual typealias MyParcelable = android.os.Parcelable ``` And telling the plugin to trigger parcelize processing with the additional annotation `my.package.Parcelize`. Fixes https://issuetracker.google.com/315775835.
This commit is contained in:
+3
-2
@@ -12,9 +12,10 @@ import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.inlineClassRepresentation
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
|
||||
|
||||
class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
||||
class IrParcelSerializerFactory(private val symbols: AndroidSymbols, private val parcelizeAnnotations: List<FqName>) {
|
||||
private val supportedBySimpleListSerializer = setOf(
|
||||
"kotlin.collections.List", "kotlin.collections.MutableList", "kotlin.collections.ArrayList",
|
||||
"java.util.List", "java.util.ArrayList",
|
||||
@@ -313,7 +314,7 @@ class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
||||
// @Parcelize), we'll have a field in the class itself. Finally, with Parcelable instances which were
|
||||
// manually implemented in Kotlin, we'll instead have an @JvmField property getter in the companion object.
|
||||
return if (classifier.modality == Modality.FINAL && classifier.psiElement != null
|
||||
&& (classifier.isParcelize || classifier.hasCreatorField)
|
||||
&& (classifier.isParcelize(parcelizeAnnotations) || classifier.hasCreatorField)
|
||||
) {
|
||||
wrapNullableSerializerIfNeeded(irType, IrEfficientParcelableParcelSerializer(classifier))
|
||||
} else {
|
||||
|
||||
+3
-2
@@ -8,10 +8,11 @@ package org.jetbrains.kotlin.parcelize
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class ParcelizeFirIrGeneratorExtension : IrGenerationExtension {
|
||||
class ParcelizeFirIrGeneratorExtension(private val parcelizeAnnotations: List<FqName>) : IrGenerationExtension {
|
||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
||||
ParcelizeFirIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
||||
ParcelizeFirIrTransformer(pluginContext, androidSymbols, parcelizeAnnotations).transform(moduleFragment)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -14,13 +14,15 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.util.companionObject
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
|
||||
import org.jetbrains.kotlin.parcelize.fir.ParcelizePluginKey
|
||||
|
||||
class ParcelizeFirIrTransformer(
|
||||
context: IrPluginContext,
|
||||
androidSymbols: AndroidSymbols
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols) {
|
||||
androidSymbols: AndroidSymbols,
|
||||
parcelizeAnnotations: List<FqName>
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols, parcelizeAnnotations) {
|
||||
|
||||
fun transform(moduleFragment: IrModuleFragment) {
|
||||
moduleFragment.accept(this, null)
|
||||
@@ -34,7 +36,7 @@ class ParcelizeFirIrTransformer(
|
||||
|
||||
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
||||
// should process their immediate subclasses.
|
||||
if (!declaration.isParcelize || declaration.modality == Modality.SEALED)
|
||||
if (!declaration.isParcelize(parcelizeAnnotations) || declaration.modality == Modality.SEALED)
|
||||
return
|
||||
|
||||
val parcelableProperties = declaration.parcelableProperties
|
||||
|
||||
+4
-2
@@ -8,10 +8,12 @@ package org.jetbrains.kotlin.parcelize
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class ParcelizeIrGeneratorExtension : IrGenerationExtension {
|
||||
// This class is open so that the IDE integration can create a subclass with a fixed set of annotations.
|
||||
open class ParcelizeIrGeneratorExtension(private val parcelizeAnnotations: List<FqName>) : IrGenerationExtension {
|
||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
||||
ParcelizeIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
||||
ParcelizeIrTransformer(pluginContext, androidSymbols, parcelizeAnnotations).transform(moduleFragment)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -36,8 +36,9 @@ import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class ParcelizeIrTransformer(
|
||||
context: IrPluginContext,
|
||||
androidSymbols: AndroidSymbols
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols) {
|
||||
androidSymbols: AndroidSymbols,
|
||||
parcelizeAnnotations: List<FqName>
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols, parcelizeAnnotations) {
|
||||
private val symbolMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
|
||||
fun transform(moduleFragment: IrModuleFragment) {
|
||||
@@ -101,7 +102,7 @@ class ParcelizeIrTransformer(
|
||||
|
||||
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
||||
// should process their immediate subclasses.
|
||||
if (!declaration.isParcelize || declaration.modality == Modality.SEALED)
|
||||
if (!declaration.isParcelize(parcelizeAnnotations) || declaration.modality == Modality.SEALED)
|
||||
return
|
||||
|
||||
val parcelableProperties = declaration.parcelableProperties
|
||||
|
||||
+4
-2
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
|
||||
@@ -27,7 +28,8 @@ import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
|
||||
|
||||
abstract class ParcelizeIrTransformerBase(
|
||||
protected val context: IrPluginContext,
|
||||
protected val androidSymbols: AndroidSymbols
|
||||
protected val androidSymbols: AndroidSymbols,
|
||||
protected val parcelizeAnnotations: List<FqName>
|
||||
) : ParcelizeExtensionBase, IrElementVisitorVoid {
|
||||
private val irFactory: IrFactory = IrFactoryImpl
|
||||
|
||||
@@ -173,7 +175,7 @@ abstract class ParcelizeIrTransformerBase(
|
||||
val parceler by lazy(parcelerThunk)
|
||||
}
|
||||
|
||||
private val serializerFactory = IrParcelSerializerFactory(androidSymbols)
|
||||
private val serializerFactory = IrParcelSerializerFactory(androidSymbols, parcelizeAnnotations)
|
||||
|
||||
protected val IrClass.parcelableProperties: List<ParcelableProperty?>
|
||||
get() {
|
||||
|
||||
+4
-5
@@ -27,17 +27,16 @@ import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_FQ_NAMES
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
||||
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
|
||||
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 &&
|
||||
(hasAnyAnnotation(PARCELIZE_CLASS_FQ_NAMES) || superTypes.any { superType ->
|
||||
fun IrClass.isParcelize(parcelizeAnnotations: List<FqName>): Boolean =
|
||||
kind in ParcelizeExtensionBase.ALLOWED_CLASS_KINDS &&
|
||||
(hasAnyAnnotation(parcelizeAnnotations) || superTypes.any { superType ->
|
||||
superType.classOrNull?.owner?.let {
|
||||
it.modality == Modality.SEALED && it.hasAnyAnnotation(PARCELIZE_CLASS_FQ_NAMES)
|
||||
it.modality == Modality.SEALED && it.hasAnyAnnotation(parcelizeAnnotations)
|
||||
} == true
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user