Parcelize: Add an intrinsic to access Parcelable CREATOR fields
Fixes KT-19853. The CREATOR field is a static field on a Parcelable class which is not visible from Kotlin since the necessary metadata would have to be in a Companion object which may not exist. This commit adds a [parcelableCreator] function to kotlinx.parcelize, which is optimized to a direct field access whenever possible.
This commit is contained in:
committed by
Alexander Udalov
parent
897c09bf8d
commit
fc013c6b9f
+1
-8
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase.Companion.CREATOR_NAME
|
||||
|
||||
interface IrParcelSerializer {
|
||||
fun AndroidIrBuilder.readParcel(parcel: IrValueDeclaration): IrExpression
|
||||
@@ -189,13 +188,7 @@ class IrCharSequenceParcelSerializer : IrParcelSerializer {
|
||||
// Parcel serializer for Parcelables in the same module, which accesses the writeToParcel/createFromParcel methods without reflection.
|
||||
class IrEfficientParcelableParcelSerializer(private val irClass: IrClass) : IrParcelSerializer {
|
||||
override fun AndroidIrBuilder.readParcel(parcel: IrValueDeclaration): IrExpression {
|
||||
val creator: IrExpression = irClass.fields.find { it.name == CREATOR_NAME }?.let { creatorField ->
|
||||
irGetField(null, creatorField)
|
||||
} ?: irCall(irClass.creatorGetter!!).apply {
|
||||
dispatchReceiver = irGetObject(irClass.companionObject()!!.symbol)
|
||||
}
|
||||
|
||||
return parcelableCreatorCreateFromParcel(creator, irGet(parcel))
|
||||
return parcelableCreatorCreateFromParcel(getParcelableCreator(irClass), irGet(parcel))
|
||||
}
|
||||
|
||||
override fun AndroidIrBuilder.writeParcel(parcel: IrValueDeclaration, flags: IrValueDeclaration, value: IrExpression): IrExpression {
|
||||
|
||||
+21
@@ -59,8 +59,29 @@ class ParcelizeIrTransformer(private val context: IrPluginContext, private val a
|
||||
deferredOperations.forEach { it() }
|
||||
|
||||
// Remap broken stubs, which psi2ir generates for the synthetic descriptors coming from the ParcelizeResolveExtension.
|
||||
// Replace the `parcelableCreator` intrinsic with a direct field access.
|
||||
moduleFragment.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
// Handle the `parcelableCreator` intrinsic
|
||||
val callee = expression.symbol.owner
|
||||
if (
|
||||
callee.dispatchReceiverParameter == null
|
||||
&& callee.extensionReceiverParameter == null
|
||||
&& callee.valueParameters.isEmpty()
|
||||
&& callee.isInline
|
||||
&& callee.fqNameWhenAvailable?.asString() == "kotlinx.parcelize.ParcelableCreatorKt.parcelableCreator"
|
||||
&& callee.typeParameters.singleOrNull()?.let {
|
||||
it.isReified && it.superTypes.singleOrNull()?.classFqName?.asString() == "android.os.Parcelable"
|
||||
} == true
|
||||
) {
|
||||
expression.getTypeArgument(0)?.getClass()?.let { parcelableClass ->
|
||||
androidSymbols.createBuilder(expression.symbol).apply {
|
||||
return getParcelableCreator(parcelableClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remap calls to `describeContents` and `writeToParcel`
|
||||
val remappedSymbol = symbolMap[expression.symbol]
|
||||
?: return super.visitCall(expression)
|
||||
return IrCallImpl(
|
||||
|
||||
@@ -7,17 +7,23 @@ 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.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addField
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
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
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
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
|
||||
@@ -103,6 +109,36 @@ fun IrBuilderWithScope.parcelableCreatorCreateFromParcel(creator: IrExpression,
|
||||
}
|
||||
}
|
||||
|
||||
// Construct an expression to access the parcelable creator field in the given class.
|
||||
fun AndroidIrBuilder.getParcelableCreator(irClass: IrClass): IrExpression {
|
||||
// For classes annotated with `Parcelize` in the same module we can
|
||||
// use the creator field directly, since we add it ourselves.
|
||||
irClass.fields.find { it.name == CREATOR_NAME }?.let { creatorField ->
|
||||
return irGetField(null, creatorField)
|
||||
}
|
||||
|
||||
// For parcelable classes which do not use `Parcelize`, the creator field
|
||||
// will be present as a `JvmField` on the companion object.
|
||||
irClass.creatorGetter?.let { getter ->
|
||||
return irCall(getter).apply {
|
||||
dispatchReceiver = irGetObject(irClass.companionObject()!!.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
// For classes in different modules, the creator field may not exist,
|
||||
// since static fields are not present in the Kotlin metadata.
|
||||
// As a workaround we create a synthetic field here together with a
|
||||
// field access.
|
||||
val creatorType = androidSymbols.androidOsParcelableCreator.typeWith(irClass.symbol.starProjectedType)
|
||||
val creatorField = irClass.factory.createField(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB,
|
||||
IrFieldSymbolImpl(), CREATOR_NAME, creatorType, DescriptorVisibilities.PUBLIC,
|
||||
isFinal = true, isExternal = false, isStatic = true,
|
||||
).also { it.parent = irClass }
|
||||
|
||||
return irGetField(null, creatorField)
|
||||
}
|
||||
|
||||
// Find a named function declaration which overrides the corresponding function in [Parceler].
|
||||
// This is more reliable than trying to match the functions signature ourselves, since the frontend
|
||||
// has already done the work.
|
||||
|
||||
@@ -53,8 +53,9 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<PrimitiveTypes>(parcel)
|
||||
val second2 = readFromParcel<PrimitiveTypes>(parcel)
|
||||
val parcelableCreator = parcelableCreator<PrimitiveTypes>()
|
||||
val first2 = parcelableCreator.createFromParcel(parcel)
|
||||
val second2 = parcelableCreator.createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
assert(second == second2)
|
||||
|
||||
@@ -36,9 +36,10 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<UnsignedTypes>(parcel)
|
||||
val second2 = readFromParcel<UnsignedTypes>(parcel)
|
||||
val third2 = readFromParcel<UnsignedTypes>(parcel)
|
||||
val parcelableCreator = parcelableCreator<UnsignedTypes>()
|
||||
val first2 = parcelableCreator.createFromParcel(parcel)
|
||||
val second2 = parcelableCreator.createFromParcel(parcel)
|
||||
val third2 = parcelableCreator.createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
assert(second == second2)
|
||||
|
||||
@@ -33,7 +33,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
}
|
||||
@@ -37,5 +37,5 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<ServiceContainer>(parcel)
|
||||
val test2 = parcelableCreator<ServiceContainer>().createFromParcel(parcel)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<BoxedTypes>(parcel)
|
||||
val first2 = parcelableCreator<BoxedTypes>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
}
|
||||
@@ -19,7 +19,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<User>(parcel)
|
||||
val test2 = parcelableCreator<User>().createFromParcel(parcel)
|
||||
|
||||
assert(compareBundles(test.a, test2.a))
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(test.simple.toString() == test2.simple.toString())
|
||||
assert(test.spanned.toString() == test2.spanned.toString())
|
||||
|
||||
@@ -31,7 +31,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val creator = User::class.java.getDeclaredField("CREATOR").get(null) as Parcelable.Creator<User>
|
||||
val creator = parcelableCreator<User>()
|
||||
val result = parcel.createTypedArray(creator)
|
||||
|
||||
assert(result.size == 2)
|
||||
|
||||
@@ -31,7 +31,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val userParcelable2 = readFromParcel<UserParcelable>(parcel)
|
||||
val userParcelable2 = parcelableCreator<UserParcelable>().createFromParcel(parcel)
|
||||
|
||||
assert(userParcelable.user.name == userParcelable2.user.name)
|
||||
assert(userParcelable2.user.age == 0)
|
||||
|
||||
@@ -36,7 +36,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Ints>(parcel)
|
||||
val test2 = parcelableCreator<Ints>().createFromParcel(parcel)
|
||||
|
||||
assert(test2.a == -test.a)
|
||||
assert(test2.b == -test.b)
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
println(test.toString())
|
||||
println(test2.toString())
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(test.a == "Abc" && test.b == "Abc" && test.c == "Abc" && test.d == "Abc")
|
||||
assert(test2.a == "3" && test2.b == "3" && test2.c == "Abc" && test2.d == "ABC")
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
with (test) {
|
||||
assert(a == "Abc" && b == "Abc" && c == listOf("A", "bc") && d == listOf("A", "bc") && e == listOf("A", "bc"))
|
||||
|
||||
@@ -30,7 +30,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val user2 = readFromParcel<User>(parcel)
|
||||
val user2 = parcelableCreator<User>().createFromParcel(parcel)
|
||||
|
||||
assert(user.firstName == user2.firstName)
|
||||
assert(user.secondName == user2.secondName)
|
||||
|
||||
@@ -27,8 +27,8 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val black2 = readFromParcel<Color>(parcel)
|
||||
val obj2 = readFromParcel<Obj>(parcel)
|
||||
val black2 = parcelableCreator<Color>().createFromParcel(parcel)
|
||||
val obj2 = parcelableCreator<Obj>().createFromParcel(parcel)
|
||||
|
||||
println(black2)
|
||||
println(obj2)
|
||||
|
||||
@@ -22,6 +22,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
assert(test == test2)
|
||||
}
|
||||
@@ -21,5 +21,5 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<ExceptionContainer>(parcel)
|
||||
val test2 = parcelableCreator<ExceptionContainer>().createFromParcel(parcel)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(test.callback() == 1)
|
||||
}
|
||||
@@ -20,7 +20,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Section<Bundle>>(parcel)
|
||||
val test2 = parcelableCreator<Section<Bundle>>().createFromParcel(parcel)
|
||||
|
||||
assert(test.title == test2.title)
|
||||
assert(test2.faTitle.size() == 0)
|
||||
|
||||
@@ -22,6 +22,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val boxLoaded = readFromParcel<Box<Foo>>(parcel)
|
||||
val boxLoaded = parcelableCreator<Box<Foo>>().createFromParcel(parcel)
|
||||
assert(box == boxLoaded)
|
||||
}
|
||||
@@ -34,6 +34,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val film2 = readFromParcel<Film>(parcel)
|
||||
val film2 = parcelableCreator<Film>().createFromParcel(parcel)
|
||||
assert(film == film2)
|
||||
}
|
||||
@@ -27,7 +27,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<J>(parcel)
|
||||
val test2 = parcelableCreator<J>().createFromParcel(parcel)
|
||||
|
||||
assert(test.j.j1 == test2.j.j1)
|
||||
}
|
||||
@@ -23,7 +23,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<M>(parcel)
|
||||
val test2 = parcelableCreator<M>().createFromParcel(parcel)
|
||||
|
||||
assert(test.m.m1 == test2.m.m1)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
@file:JvmName("TestKt")
|
||||
package test
|
||||
|
||||
import kotlinx.parcelize.*
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
|
||||
@Parcelize
|
||||
class A(val value: Int) : Parcelable
|
||||
|
||||
fun box() = parcelTest { parcel ->
|
||||
parcel.writeTypedList(listOf(A(0), A(1)))
|
||||
|
||||
val bytes = parcel.marshall()
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val creator = parcelableCreator<A>()
|
||||
val deserialized = mutableListOf<A>()
|
||||
parcel.readTypedList(deserialized, creator)
|
||||
assert(deserialized.size == 2)
|
||||
assert(deserialized[0].value == 0)
|
||||
assert(deserialized[1].value == 1)
|
||||
}
|
||||
@@ -34,7 +34,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
}
|
||||
@@ -41,7 +41,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first.parcelableEnum == ParcelableEnum.THREE)
|
||||
assert(first2.parcelableEnum == ParcelableEnum.ONE)
|
||||
|
||||
@@ -24,6 +24,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
readFromParcel<User>(parcel)
|
||||
readFromParcel<User2>(parcel)
|
||||
parcelableCreator<User>().createFromParcel(parcel)
|
||||
parcelableCreator<User2>().createFromParcel(parcel)
|
||||
}
|
||||
@@ -30,7 +30,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val foo2 = readFromParcel<Foo>(parcel)
|
||||
val foo2 = parcelableCreator<Foo>().createFromParcel(parcel)
|
||||
assert(foo2.values.size() == 1)
|
||||
assert(foo2.values.get(1) != null) // SparseArray.contains was only added in Android R
|
||||
assert(foo2.values.get(1).size() == 1)
|
||||
|
||||
@@ -19,5 +19,5 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
readFromParcel<MyObject>(parcel)
|
||||
parcelableCreator<MyObject>().createFromParcel(parcel)
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val a2 = readFromParcel<A>(parcel)
|
||||
val parcelableCreator = parcelableCreator<A>()
|
||||
val a2 = parcelableCreator.createFromParcel(parcel)
|
||||
assert(a2.params != null)
|
||||
assert(Arrays.equals(a1.params!!, a2.params!!))
|
||||
val b2 = readFromParcel<A>(parcel)
|
||||
val b2 = parcelableCreator.createFromParcel(parcel)
|
||||
assert(b1 == b2)
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val a2 = readFromParcel<A>(parcel)
|
||||
val parcelableCreator = parcelableCreator<A>()
|
||||
val a2 = parcelableCreator.createFromParcel(parcel)
|
||||
assert(a2.params != null)
|
||||
assert(Arrays.equals(a1.params!!, a2.params!!))
|
||||
val b2 = readFromParcel<A>(parcel)
|
||||
val b2 = parcelableCreator.createFromParcel(parcel)
|
||||
assert(b1 == b2)
|
||||
}
|
||||
|
||||
@@ -59,6 +59,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val a2 = readFromParcel<A>(parcel)
|
||||
val a2 = parcelableCreator<A>().createFromParcel(parcel)
|
||||
assert(a1.pair == a2.pair)
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
assert((first.d as LinkedList<*>).size == 1)
|
||||
|
||||
@@ -19,7 +19,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
}
|
||||
@@ -33,7 +33,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
assert((first.c as HashMap<*, *>).size == 1)
|
||||
|
||||
@@ -19,7 +19,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
}
|
||||
@@ -35,7 +35,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val first2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
}
|
||||
@@ -20,7 +20,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val second = readFromParcel<Data>(parcel)
|
||||
val second = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(second.data.size == 1)
|
||||
assert(Arrays.equals(second.data[0], arrayOf(0, 1)))
|
||||
}
|
||||
@@ -20,7 +20,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val second = readFromParcel<Data>(parcel)
|
||||
val second = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(second.data.size == 1)
|
||||
assert(Arrays.equals(second.data[0], arrayOf(0, 1)))
|
||||
}
|
||||
@@ -20,7 +20,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val second = readFromParcel<Data>(parcel)
|
||||
val second = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(second.data.size == 1)
|
||||
val entry = second.data.entries.single()
|
||||
assert(Arrays.equals(entry.key, arrayOf(0)))
|
||||
|
||||
@@ -29,6 +29,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
assert(test == test2)
|
||||
}
|
||||
@@ -24,7 +24,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val second = readFromParcel<Data>(parcel)
|
||||
val second = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(second.data.size() == 1)
|
||||
assert(Arrays.equals(second.data.get(0), arrayOf(0, 1)))
|
||||
}
|
||||
@@ -27,7 +27,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val second = readFromParcel<Data>(parcel)
|
||||
val second = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(second.values.size() == 1)
|
||||
val secondInnerArray = second.values.get(10)
|
||||
assert(secondInnerArray.size() == 1)
|
||||
|
||||
@@ -20,7 +20,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val creator = User::class.java.getDeclaredField("CREATOR").get(null) as Parcelable.Creator<User>
|
||||
val creator = parcelableCreator<User>()
|
||||
val result = parcel.createTypedArray(creator)
|
||||
|
||||
assert(result.size == 2)
|
||||
|
||||
@@ -35,7 +35,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val creator = User::class.java.getDeclaredField("CREATOR").get(null) as Parcelable.Creator<User>
|
||||
val creator = parcelableCreator<User>()
|
||||
val result = parcel.createTypedArray(creator)
|
||||
|
||||
assert(result.size == 3)
|
||||
|
||||
@@ -30,8 +30,9 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val second2 = readFromParcel<Test>(parcel)
|
||||
val parcelableCreator = parcelableCreator<Test>()
|
||||
val first2 = parcelableCreator.createFromParcel(parcel)
|
||||
val second2 = parcelableCreator.createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
assert(second == second2)
|
||||
|
||||
@@ -21,8 +21,9 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<Test>(parcel)
|
||||
val second2 = readFromParcel<Test>(parcel)
|
||||
val parcelableCreator = parcelableCreator<Test>()
|
||||
val first2 = parcelableCreator.createFromParcel(parcel)
|
||||
val second2 = parcelableCreator.createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
assert(second == second2)
|
||||
|
||||
@@ -26,6 +26,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
assert(test == test2)
|
||||
}
|
||||
@@ -34,6 +34,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val data2 = readFromParcel<Data>(parcel)
|
||||
val data2 = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(data2.uuid.uuid == data.uuid.uuid)
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,6 +33,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val data2 = readFromParcel<Data>(parcel)
|
||||
val data2 = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(data2.uuid.uuid == data.uuid.uuid)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<User>(parcel)
|
||||
val test2 = parcelableCreator<User>().createFromParcel(parcel)
|
||||
|
||||
assert(compareBundles(test.a, test2.a))
|
||||
}
|
||||
|
||||
@@ -31,8 +31,9 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val first2 = readFromParcel<PrimitiveTypes>(parcel)
|
||||
val second2 = readFromParcel<PrimitiveTypes>(parcel)
|
||||
val parcelableCreator = parcelableCreator<PrimitiveTypes>()
|
||||
val first2 = parcelableCreator.createFromParcel(parcel)
|
||||
val second2 = parcelableCreator.createFromParcel(parcel)
|
||||
|
||||
assert(first == first2)
|
||||
assert(second == second2)
|
||||
|
||||
@@ -22,6 +22,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val data = readFromParcel<Data>(parcel)
|
||||
val data = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(data.value == "OK")
|
||||
}
|
||||
|
||||
@@ -30,6 +30,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<Test>(parcel)
|
||||
val test2 = parcelableCreator<Test>().createFromParcel(parcel)
|
||||
assert(test == test2)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val second = readFromParcel<Bar>(parcel)
|
||||
val second = parcelableCreator<Bar>().createFromParcel(parcel)
|
||||
|
||||
assert(first == second)
|
||||
}
|
||||
@@ -20,6 +20,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val user2 = readFromParcel<User>(parcel)
|
||||
val user2 = parcelableCreator<User>().createFromParcel(parcel)
|
||||
assert(user == user2)
|
||||
}
|
||||
@@ -20,6 +20,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val user2 = readFromParcel<User>(parcel)
|
||||
val creator = User::class.java.getDeclaredField("CREATOR").get(null) as Parcelable.Creator<User>
|
||||
val user2 = creator.createFromParcel(parcel)
|
||||
assert(user == user2)
|
||||
}
|
||||
@@ -27,7 +27,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val user2 = readFromParcel<User>(parcel)
|
||||
val user2 = parcelableCreator<User>().createFromParcel(parcel)
|
||||
|
||||
assert(compareSparseIntArrays(user.a, user2.a))
|
||||
assert(compareSparseLongArrays(user.b, user2.b))
|
||||
|
||||
@@ -19,7 +19,7 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val test2 = readFromParcel<User>(parcel)
|
||||
val test2 = parcelableCreator<User>().createFromParcel(parcel)
|
||||
|
||||
assert(compareSparseBooleanArrays(test.a, test2.a))
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val covariant2 = readFromParcel<Covariant<String>>(parcel)
|
||||
val covariant2 = parcelableCreator<Covariant<String>>().createFromParcel(parcel)
|
||||
assert(covariant2.block() == "OK")
|
||||
|
||||
val contravariant2 = readFromParcel<Contravariant<String>>(parcel)
|
||||
val contravariant2 = parcelableCreator<Contravariant<String>>().createFromParcel(parcel)
|
||||
assert(contravariant2.block("OK"))
|
||||
|
||||
val invariant2 = readFromParcel<Invariant<String>>(parcel)
|
||||
val invariant2 = parcelableCreator<Invariant<String>>().createFromParcel(parcel)
|
||||
assert(invariant2.s.toString() == "OK")
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val data2 = readFromParcel<Wrapper>(parcel)
|
||||
val data2 = parcelableCreator<Wrapper>().createFromParcel(parcel)
|
||||
assert(data2 == data)
|
||||
|
||||
val none2 = readFromParcel<NullableWrapper>(parcel)
|
||||
val none2 = parcelableCreator<NullableWrapper>().createFromParcel(parcel)
|
||||
assert(none2 == none)
|
||||
}
|
||||
|
||||
@@ -49,6 +49,6 @@ fun box() = parcelTest { parcel ->
|
||||
parcel.unmarshall(bytes, 0, bytes.size)
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val data2 = readFromParcel<Data>(parcel)
|
||||
val data2 = parcelableCreator<Data>().createFromParcel(parcel)
|
||||
assert(data2 == data)
|
||||
}
|
||||
|
||||
@@ -11,8 +11,3 @@ fun parcelTest(block: (Parcel) -> Unit): String {
|
||||
parcel.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T> readFromParcel(parcel: Parcel): T {
|
||||
val creator = T::class.java.getDeclaredField("CREATOR").get(null)
|
||||
return creator::class.java.getDeclaredMethod("createFromParcel", Parcel::class.java).invoke(creator, parcel) as T
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
public final class A$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final A createFromParcel(android.os.Parcel parcel)
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel source)
|
||||
|
||||
public final A[] newArray(int size)
|
||||
|
||||
public java.lang.Object[] newArray(int size)
|
||||
}
|
||||
|
||||
public final class A : java/lang/Object, android/os/Parcelable {
|
||||
public final static android.os.Parcelable$Creator CREATOR
|
||||
|
||||
private final int value
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
public void <init>(int value)
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public final int getValue()
|
||||
|
||||
public void writeToParcel(android.os.Parcel out, int flags)
|
||||
}
|
||||
|
||||
public final class B$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final B createFromParcel(android.os.Parcel parcel)
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel source)
|
||||
|
||||
public final B[] newArray(int size)
|
||||
|
||||
public java.lang.Object[] newArray(int size)
|
||||
}
|
||||
|
||||
public final class B : java/lang/Object, android/os/Parcelable {
|
||||
public final static android.os.Parcelable$Creator CREATOR
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
public void <init>()
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public void writeToParcel(android.os.Parcel out, int flags)
|
||||
}
|
||||
|
||||
public final class C$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final C createFromParcel(android.os.Parcel parcel)
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel source)
|
||||
|
||||
public final C[] newArray(int size)
|
||||
|
||||
public java.lang.Object[] newArray(int size)
|
||||
}
|
||||
|
||||
public final class C : java/lang/Object, android/os/Parcelable {
|
||||
public final static android.os.Parcelable$Creator CREATOR
|
||||
|
||||
public final static C INSTANCE
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
private void <init>()
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public void writeToParcel(android.os.Parcel out, int flags)
|
||||
}
|
||||
|
||||
public final class ParcelableCreatorKt : java/lang/Object {
|
||||
public final static void test1() {
|
||||
GETSTATIC (A, CREATOR, Landroid/os/Parcelable$Creator;)
|
||||
POP
|
||||
GETSTATIC (B, CREATOR, Landroid/os/Parcelable$Creator;)
|
||||
POP
|
||||
GETSTATIC (C, CREATOR, Landroid/os/Parcelable$Creator;)
|
||||
POP
|
||||
LABEL (L0)
|
||||
LINENUMBER (20)
|
||||
RETURN
|
||||
}
|
||||
|
||||
public final static void test2() {
|
||||
ICONST_0
|
||||
ISTORE (0)
|
||||
LABEL (L0)
|
||||
LINENUMBER (23)
|
||||
ICONST_0
|
||||
ISTORE (1)
|
||||
LABEL (L1)
|
||||
ICONST_4
|
||||
LDC (T)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, reifiedOperationMarker, (ILjava/lang/String;)V)
|
||||
LDC (Landroid/os/Parcelable;)
|
||||
CHECKCAST
|
||||
LABEL (L2)
|
||||
LINENUMBER (30)
|
||||
LDC (CREATOR)
|
||||
INVOKEVIRTUAL (java/lang/Class, getDeclaredField, (Ljava/lang/String;)Ljava/lang/reflect/Field;)
|
||||
ACONST_NULL
|
||||
INVOKEVIRTUAL (java/lang/reflect/Field, get, (Ljava/lang/Object;)Ljava/lang/Object;)
|
||||
ASTORE (2)
|
||||
ALOAD (2)
|
||||
INSTANCEOF
|
||||
IFEQ (L3)
|
||||
ALOAD (2)
|
||||
CHECKCAST
|
||||
GOTO (L4)
|
||||
LABEL (L3)
|
||||
ACONST_NULL
|
||||
LABEL (L4)
|
||||
ASTORE (3)
|
||||
ALOAD (3)
|
||||
IFNONNULL (L5)
|
||||
LABEL (L6)
|
||||
LINENUMBER (31)
|
||||
NEW
|
||||
DUP
|
||||
LDC (Could not access CREATOR field in class )
|
||||
ICONST_4
|
||||
LDC (T)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, reifiedOperationMarker, (ILjava/lang/String;)V)
|
||||
LDC (Landroid/os/Parcelable;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Reflection, getOrCreateKotlinClass, (Ljava/lang/Class;)Lkotlin/reflect/KClass;)
|
||||
INVOKEINTERFACE (kotlin/reflect/KClass, getSimpleName, ()Ljava/lang/String;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, stringPlus, (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;)
|
||||
INVOKESPECIAL (java/lang/IllegalArgumentException, <init>, (Ljava/lang/String;)V)
|
||||
ATHROW
|
||||
LABEL (L5)
|
||||
LINENUMBER (30)
|
||||
ALOAD (3)
|
||||
CHECKCAST
|
||||
LABEL (L7)
|
||||
LINENUMBER (31)
|
||||
NOP
|
||||
LABEL (L8)
|
||||
POP
|
||||
LABEL (L9)
|
||||
LINENUMBER (24)
|
||||
RETURN
|
||||
LABEL (L10)
|
||||
}
|
||||
|
||||
public final static void test3() {
|
||||
LABEL (L0)
|
||||
LINENUMBER (27)
|
||||
ICONST_0
|
||||
ISTORE (0)
|
||||
LABEL (L1)
|
||||
LINENUMBER (32)
|
||||
ICONST_0
|
||||
ISTORE (1)
|
||||
LABEL (L2)
|
||||
LDC (LA;)
|
||||
LABEL (L3)
|
||||
LINENUMBER (33)
|
||||
LDC (CREATOR)
|
||||
INVOKEVIRTUAL (java/lang/Class, getDeclaredField, (Ljava/lang/String;)Ljava/lang/reflect/Field;)
|
||||
ACONST_NULL
|
||||
INVOKEVIRTUAL (java/lang/reflect/Field, get, (Ljava/lang/Object;)Ljava/lang/Object;)
|
||||
ASTORE (2)
|
||||
ALOAD (2)
|
||||
INSTANCEOF
|
||||
IFEQ (L4)
|
||||
ALOAD (2)
|
||||
CHECKCAST
|
||||
GOTO (L5)
|
||||
LABEL (L4)
|
||||
ACONST_NULL
|
||||
LABEL (L5)
|
||||
ASTORE (3)
|
||||
ALOAD (3)
|
||||
IFNONNULL (L6)
|
||||
LABEL (L7)
|
||||
LINENUMBER (34)
|
||||
NEW
|
||||
DUP
|
||||
LDC (Could not access CREATOR field in class )
|
||||
LDC (LA;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Reflection, getOrCreateKotlinClass, (Ljava/lang/Class;)Lkotlin/reflect/KClass;)
|
||||
INVOKEINTERFACE (kotlin/reflect/KClass, getSimpleName, ()Ljava/lang/String;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, stringPlus, (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;)
|
||||
INVOKESPECIAL (java/lang/IllegalArgumentException, <init>, (Ljava/lang/String;)V)
|
||||
ATHROW
|
||||
LABEL (L6)
|
||||
LINENUMBER (33)
|
||||
NOP
|
||||
LABEL (L8)
|
||||
LINENUMBER (34)
|
||||
NOP
|
||||
LABEL (L9)
|
||||
LINENUMBER (35)
|
||||
NOP
|
||||
LABEL (L10)
|
||||
LINENUMBER (28)
|
||||
RETURN
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// CURIOUS_ABOUT test1, test2, test3
|
||||
// WITH_RUNTIME
|
||||
|
||||
import kotlinx.parcelize.*
|
||||
import android.os.Parcelable
|
||||
|
||||
@Parcelize
|
||||
class A(val value: Int) : Parcelable
|
||||
|
||||
@Parcelize
|
||||
class B : Parcelable
|
||||
|
||||
@Parcelize
|
||||
object C : Parcelable
|
||||
|
||||
fun test1() {
|
||||
parcelableCreator<A>()
|
||||
parcelableCreator<B>()
|
||||
parcelableCreator<C>()
|
||||
}
|
||||
|
||||
inline fun <reified T : Parcelable> test2() {
|
||||
parcelableCreator<T>()
|
||||
}
|
||||
|
||||
fun test3() {
|
||||
test2<A>()
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
public final class A$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final A createFromParcel(android.os.Parcel in)
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel p0)
|
||||
|
||||
public final A[] newArray(int size)
|
||||
|
||||
public java.lang.Object[] newArray(int p0)
|
||||
}
|
||||
|
||||
public final class A : java/lang/Object, android/os/Parcelable {
|
||||
public final static android.os.Parcelable$Creator CREATOR
|
||||
|
||||
private final int value
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
public void <init>(int value)
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public final int getValue()
|
||||
|
||||
public void writeToParcel(android.os.Parcel parcel, int flags)
|
||||
}
|
||||
|
||||
public final class B$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final B createFromParcel(android.os.Parcel in)
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel p0)
|
||||
|
||||
public final B[] newArray(int size)
|
||||
|
||||
public java.lang.Object[] newArray(int p0)
|
||||
}
|
||||
|
||||
public final class B : java/lang/Object, android/os/Parcelable {
|
||||
public final static android.os.Parcelable$Creator CREATOR
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
public void <init>()
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public void writeToParcel(android.os.Parcel parcel, int flags)
|
||||
}
|
||||
|
||||
public final class C$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final C createFromParcel(android.os.Parcel in)
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel p0)
|
||||
|
||||
public final C[] newArray(int size)
|
||||
|
||||
public java.lang.Object[] newArray(int p0)
|
||||
}
|
||||
|
||||
public final class C : java/lang/Object, android/os/Parcelable {
|
||||
public final static android.os.Parcelable$Creator CREATOR
|
||||
|
||||
public final static C INSTANCE
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
private void <init>()
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public void writeToParcel(android.os.Parcel parcel, int flags)
|
||||
}
|
||||
|
||||
public final class ParcelableCreatorKt : java/lang/Object {
|
||||
public final static void test1() {
|
||||
LABEL (L0)
|
||||
LINENUMBER (17)
|
||||
ICONST_0
|
||||
ISTORE (0)
|
||||
LABEL (L1)
|
||||
LDC (LA;)
|
||||
LABEL (L2)
|
||||
LINENUMBER (30)
|
||||
LDC (CREATOR)
|
||||
INVOKEVIRTUAL (java/lang/Class, getDeclaredField, (Ljava/lang/String;)Ljava/lang/reflect/Field;)
|
||||
ACONST_NULL
|
||||
INVOKEVIRTUAL (java/lang/reflect/Field, get, (Ljava/lang/Object;)Ljava/lang/Object;)
|
||||
ASTORE (1)
|
||||
ALOAD (1)
|
||||
INSTANCEOF
|
||||
IFEQ (L3)
|
||||
ALOAD (1)
|
||||
CHECKCAST
|
||||
GOTO (L4)
|
||||
LABEL (L3)
|
||||
ACONST_NULL
|
||||
LABEL (L4)
|
||||
ASTORE (2)
|
||||
ALOAD (2)
|
||||
IFNONNULL (L5)
|
||||
LABEL (L6)
|
||||
LINENUMBER (31)
|
||||
NEW
|
||||
DUP
|
||||
LDC (Could not access CREATOR field in class )
|
||||
LDC (LA;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Reflection, getOrCreateKotlinClass, (Ljava/lang/Class;)Lkotlin/reflect/KClass;)
|
||||
INVOKEINTERFACE (kotlin/reflect/KClass, getSimpleName, ()Ljava/lang/String;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, stringPlus, (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;)
|
||||
INVOKESPECIAL (java/lang/IllegalArgumentException, <init>, (Ljava/lang/String;)V)
|
||||
ATHROW
|
||||
LABEL (L5)
|
||||
LINENUMBER (30)
|
||||
NOP
|
||||
LABEL (L7)
|
||||
LINENUMBER (31)
|
||||
NOP
|
||||
LABEL (L8)
|
||||
LINENUMBER (18)
|
||||
ICONST_0
|
||||
ISTORE (0)
|
||||
LABEL (L9)
|
||||
LDC (LB;)
|
||||
LABEL (L10)
|
||||
LINENUMBER (32)
|
||||
LDC (CREATOR)
|
||||
INVOKEVIRTUAL (java/lang/Class, getDeclaredField, (Ljava/lang/String;)Ljava/lang/reflect/Field;)
|
||||
ACONST_NULL
|
||||
INVOKEVIRTUAL (java/lang/reflect/Field, get, (Ljava/lang/Object;)Ljava/lang/Object;)
|
||||
ASTORE (1)
|
||||
ALOAD (1)
|
||||
INSTANCEOF
|
||||
IFEQ (L11)
|
||||
ALOAD (1)
|
||||
CHECKCAST
|
||||
GOTO (L12)
|
||||
LABEL (L11)
|
||||
ACONST_NULL
|
||||
LABEL (L12)
|
||||
ASTORE (2)
|
||||
ALOAD (2)
|
||||
IFNONNULL (L13)
|
||||
LABEL (L14)
|
||||
LINENUMBER (33)
|
||||
NEW
|
||||
DUP
|
||||
LDC (Could not access CREATOR field in class )
|
||||
LDC (LB;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Reflection, getOrCreateKotlinClass, (Ljava/lang/Class;)Lkotlin/reflect/KClass;)
|
||||
INVOKEINTERFACE (kotlin/reflect/KClass, getSimpleName, ()Ljava/lang/String;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, stringPlus, (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;)
|
||||
INVOKESPECIAL (java/lang/IllegalArgumentException, <init>, (Ljava/lang/String;)V)
|
||||
ATHROW
|
||||
LABEL (L13)
|
||||
LINENUMBER (32)
|
||||
NOP
|
||||
LABEL (L15)
|
||||
LINENUMBER (33)
|
||||
NOP
|
||||
LABEL (L16)
|
||||
LINENUMBER (19)
|
||||
ICONST_0
|
||||
ISTORE (0)
|
||||
LABEL (L17)
|
||||
LDC (LC;)
|
||||
LABEL (L18)
|
||||
LINENUMBER (34)
|
||||
LDC (CREATOR)
|
||||
INVOKEVIRTUAL (java/lang/Class, getDeclaredField, (Ljava/lang/String;)Ljava/lang/reflect/Field;)
|
||||
ACONST_NULL
|
||||
INVOKEVIRTUAL (java/lang/reflect/Field, get, (Ljava/lang/Object;)Ljava/lang/Object;)
|
||||
ASTORE (1)
|
||||
ALOAD (1)
|
||||
INSTANCEOF
|
||||
IFEQ (L19)
|
||||
ALOAD (1)
|
||||
CHECKCAST
|
||||
GOTO (L20)
|
||||
LABEL (L19)
|
||||
ACONST_NULL
|
||||
LABEL (L20)
|
||||
ASTORE (2)
|
||||
ALOAD (2)
|
||||
IFNONNULL (L21)
|
||||
LABEL (L22)
|
||||
LINENUMBER (35)
|
||||
NEW
|
||||
DUP
|
||||
LDC (Could not access CREATOR field in class )
|
||||
LDC (LC;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Reflection, getOrCreateKotlinClass, (Ljava/lang/Class;)Lkotlin/reflect/KClass;)
|
||||
INVOKEINTERFACE (kotlin/reflect/KClass, getSimpleName, ()Ljava/lang/String;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, stringPlus, (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;)
|
||||
INVOKESPECIAL (java/lang/IllegalArgumentException, <init>, (Ljava/lang/String;)V)
|
||||
ATHROW
|
||||
LABEL (L21)
|
||||
LINENUMBER (34)
|
||||
NOP
|
||||
LABEL (L23)
|
||||
LINENUMBER (35)
|
||||
NOP
|
||||
LABEL (L24)
|
||||
LINENUMBER (20)
|
||||
RETURN
|
||||
}
|
||||
|
||||
public final static void test2() {
|
||||
LDC (0)
|
||||
ISTORE (0)
|
||||
LABEL (L0)
|
||||
LINENUMBER (23)
|
||||
ICONST_0
|
||||
ISTORE (1)
|
||||
LABEL (L1)
|
||||
ICONST_4
|
||||
LDC (T)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, reifiedOperationMarker, (ILjava/lang/String;)V)
|
||||
LDC (Landroid/os/Parcelable;)
|
||||
CHECKCAST
|
||||
LABEL (L2)
|
||||
LINENUMBER (36)
|
||||
LDC (CREATOR)
|
||||
INVOKEVIRTUAL (java/lang/Class, getDeclaredField, (Ljava/lang/String;)Ljava/lang/reflect/Field;)
|
||||
ACONST_NULL
|
||||
INVOKEVIRTUAL (java/lang/reflect/Field, get, (Ljava/lang/Object;)Ljava/lang/Object;)
|
||||
ASTORE (2)
|
||||
ALOAD (2)
|
||||
INSTANCEOF
|
||||
IFEQ (L3)
|
||||
ALOAD (2)
|
||||
CHECKCAST
|
||||
GOTO (L4)
|
||||
LABEL (L3)
|
||||
ACONST_NULL
|
||||
LABEL (L4)
|
||||
ASTORE (3)
|
||||
ALOAD (3)
|
||||
IFNONNULL (L5)
|
||||
LABEL (L6)
|
||||
LINENUMBER (37)
|
||||
NEW
|
||||
DUP
|
||||
LDC (Could not access CREATOR field in class )
|
||||
ICONST_4
|
||||
LDC (T)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, reifiedOperationMarker, (ILjava/lang/String;)V)
|
||||
LDC (Landroid/os/Parcelable;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Reflection, getOrCreateKotlinClass, (Ljava/lang/Class;)Lkotlin/reflect/KClass;)
|
||||
INVOKEINTERFACE (kotlin/reflect/KClass, getSimpleName, ()Ljava/lang/String;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, stringPlus, (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;)
|
||||
INVOKESPECIAL (java/lang/IllegalArgumentException, <init>, (Ljava/lang/String;)V)
|
||||
ATHROW
|
||||
LABEL (L5)
|
||||
LINENUMBER (36)
|
||||
ALOAD (3)
|
||||
CHECKCAST
|
||||
LABEL (L7)
|
||||
LINENUMBER (37)
|
||||
NOP
|
||||
LABEL (L8)
|
||||
POP
|
||||
LABEL (L9)
|
||||
LINENUMBER (24)
|
||||
RETURN
|
||||
LABEL (L10)
|
||||
}
|
||||
|
||||
public final static void test3() {
|
||||
LABEL (L0)
|
||||
LINENUMBER (27)
|
||||
ICONST_0
|
||||
ISTORE (0)
|
||||
LABEL (L1)
|
||||
LINENUMBER (38)
|
||||
ICONST_0
|
||||
ISTORE (1)
|
||||
LABEL (L2)
|
||||
LDC (LA;)
|
||||
LABEL (L3)
|
||||
LINENUMBER (39)
|
||||
LDC (CREATOR)
|
||||
INVOKEVIRTUAL (java/lang/Class, getDeclaredField, (Ljava/lang/String;)Ljava/lang/reflect/Field;)
|
||||
ACONST_NULL
|
||||
INVOKEVIRTUAL (java/lang/reflect/Field, get, (Ljava/lang/Object;)Ljava/lang/Object;)
|
||||
ASTORE (2)
|
||||
ALOAD (2)
|
||||
INSTANCEOF
|
||||
IFEQ (L4)
|
||||
ALOAD (2)
|
||||
CHECKCAST
|
||||
GOTO (L5)
|
||||
LABEL (L4)
|
||||
ACONST_NULL
|
||||
LABEL (L5)
|
||||
ASTORE (3)
|
||||
ALOAD (3)
|
||||
IFNONNULL (L6)
|
||||
LABEL (L7)
|
||||
LINENUMBER (40)
|
||||
NEW
|
||||
DUP
|
||||
LDC (Could not access CREATOR field in class )
|
||||
LDC (LA;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Reflection, getOrCreateKotlinClass, (Ljava/lang/Class;)Lkotlin/reflect/KClass;)
|
||||
INVOKEINTERFACE (kotlin/reflect/KClass, getSimpleName, ()Ljava/lang/String;)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, stringPlus, (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;)
|
||||
INVOKESPECIAL (java/lang/IllegalArgumentException, <init>, (Ljava/lang/String;)V)
|
||||
ATHROW
|
||||
LABEL (L6)
|
||||
LINENUMBER (39)
|
||||
NOP
|
||||
LABEL (L8)
|
||||
LINENUMBER (40)
|
||||
NOP
|
||||
LABEL (L9)
|
||||
LINENUMBER (41)
|
||||
NOP
|
||||
LABEL (L10)
|
||||
LINENUMBER (28)
|
||||
RETURN
|
||||
}
|
||||
}
|
||||
+5
@@ -165,6 +165,11 @@ public class ParcelizeBoxTestGenerated extends AbstractParcelizeBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/kt19749.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt19853.kt")
|
||||
public void testKt19853() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/kt19853.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20002.kt")
|
||||
public void testKt20002() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/kt20002.kt");
|
||||
|
||||
+5
@@ -105,6 +105,11 @@ public class ParcelizeBytecodeListingTestGenerated extends AbstractParcelizeByte
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/parcelable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("parcelableCreator.kt")
|
||||
public void testParcelableCreator() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/parcelableCreator.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("serializable.kt")
|
||||
public void testSerializable() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/serializable.kt");
|
||||
|
||||
+5
@@ -165,6 +165,11 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/kt19749.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt19853.kt")
|
||||
public void testKt19853() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/kt19853.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt20002.kt")
|
||||
public void testKt20002() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/box/kt20002.kt");
|
||||
|
||||
+5
@@ -105,6 +105,11 @@ public class ParcelizeIrBytecodeListingTestGenerated extends AbstractParcelizeIr
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/parcelable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("parcelableCreator.kt")
|
||||
public void testParcelableCreator() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/parcelableCreator.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("serializable.kt")
|
||||
public void testSerializable() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/serializable.kt");
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
package kotlinx.parcelize
|
||||
|
||||
import android.os.Parcelable
|
||||
|
||||
/**
|
||||
* Read the CREATOR field of the given [Parcelable] class. Calls to this function with
|
||||
* a concrete class will be optimized to a direct field access.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T : Parcelable> parcelableCreator(): Parcelable.Creator<T> =
|
||||
T::class.java.getDeclaredField("CREATOR").get(null) as? Parcelable.Creator<T>
|
||||
?: throw IllegalArgumentException("Could not access CREATOR field in class ${T::class.simpleName}")
|
||||
Reference in New Issue
Block a user