Parcelize: Use the class loader of the Parcelable class for reading
In `readBundle`, `readPersistableBundle`, and `readValue`.
This commit is contained in:
committed by
Alexander Udalov
parent
08eaac7e56
commit
897c09bf8d
-14
@@ -37,13 +37,6 @@ class AndroidIrBuilder internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun parcelReadValue(receiver: IrExpression, loader: IrExpression): IrExpression {
|
||||
return irCall(androidSymbols.parcelReadValue).apply {
|
||||
dispatchReceiver = receiver
|
||||
putValueArgument(0, loader)
|
||||
}
|
||||
}
|
||||
|
||||
fun parcelWriteInt(receiver: IrExpression, value: IrExpression): IrExpression {
|
||||
return irCall(androidSymbols.parcelWriteInt).apply {
|
||||
dispatchReceiver = receiver
|
||||
@@ -66,13 +59,6 @@ class AndroidIrBuilder internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun parcelWriteValue(receiver: IrExpression, v: IrExpression): IrExpression {
|
||||
return irCall(androidSymbols.parcelWriteValue).apply {
|
||||
dispatchReceiver = receiver
|
||||
putValueArgument(0, v)
|
||||
}
|
||||
}
|
||||
|
||||
fun textUtilsWriteToParcel(cs: IrExpression, p: IrExpression, parcelableFlags: IrExpression): IrExpression {
|
||||
return irCall(androidSymbols.textUtilsWriteToParcel).apply {
|
||||
putValueArgument(0, cs)
|
||||
|
||||
+6
-2
@@ -209,7 +209,9 @@ class AndroidSymbols(
|
||||
androidOsParcel.owner.addFunction("createStringArrayList", javaUtilArrayList.defaultType).symbol
|
||||
|
||||
val parcelReadBundle: IrSimpleFunctionSymbol =
|
||||
androidOsParcel.owner.addFunction("readBundle", androidOsBundle.defaultType).symbol
|
||||
androidOsParcel.owner.addFunction("readBundle", androidOsBundle.defaultType).apply {
|
||||
addValueParameter("loader", javaLangClassLoader.defaultType)
|
||||
}.symbol
|
||||
|
||||
val parcelReadByte: IrSimpleFunctionSymbol =
|
||||
androidOsParcel.owner.addFunction("readByte", irBuiltIns.byteType).symbol
|
||||
@@ -235,7 +237,9 @@ class AndroidSymbols(
|
||||
}.symbol
|
||||
|
||||
val parcelReadPersistableBundle: IrSimpleFunctionSymbol =
|
||||
androidOsParcel.owner.addFunction("readPersistableBundle", androidOsPersistableBundle.defaultType).symbol
|
||||
androidOsParcel.owner.addFunction("readPersistableBundle", androidOsPersistableBundle.defaultType).apply {
|
||||
addValueParameter("loader", javaLangClassLoader.defaultType)
|
||||
}.symbol
|
||||
|
||||
val parcelReadSerializable: IrSimpleFunctionSymbol =
|
||||
androidOsParcel.owner.addFunction("readSerializable", javaIoSerializable.defaultType).symbol
|
||||
|
||||
+10
-8
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.parcelize.RAW_VALUE_ANNOTATION_FQ_NAMES
|
||||
|
||||
class IrParcelSerializerFactory(symbols: AndroidSymbols) {
|
||||
class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
||||
/**
|
||||
* Resolve the given [irType] to a corresponding [IrParcelSerializer]. This depends on the TypeParcelers which
|
||||
* are currently in [scope], as well as the type of the enclosing Parceleable class [parcelizeType], which is needed
|
||||
@@ -43,9 +43,13 @@ class IrParcelSerializerFactory(symbols: AndroidSymbols) {
|
||||
"kotlin.CharSequence", "java.lang.CharSequence" ->
|
||||
return charSequenceSerializer
|
||||
"android.os.Bundle" ->
|
||||
return bundleSerializer
|
||||
return IrParcelSerializerWithClassLoader(parcelizeType, symbols.parcelReadBundle, symbols.parcelWriteBundle)
|
||||
"android.os.PersistableBundle" ->
|
||||
return persistableBundleSerializer
|
||||
return IrParcelSerializerWithClassLoader(
|
||||
parcelizeType,
|
||||
symbols.parcelReadPersistableBundle,
|
||||
symbols.parcelWritePersistableBundle
|
||||
)
|
||||
|
||||
// Non-nullable built-in serializers
|
||||
"kotlin.Byte", "java.lang.Byte" ->
|
||||
@@ -251,14 +255,15 @@ class IrParcelSerializerFactory(symbols: AndroidSymbols) {
|
||||
throw IllegalArgumentException("Illegal type, could not find a specific serializer for ${irType.render()}")
|
||||
|
||||
else ->
|
||||
return IrGenericValueParcelSerializer(parcelizeType)
|
||||
return IrParcelSerializerWithClassLoader(parcelizeType, symbols.parcelReadValue, symbols.parcelWriteValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun wrapNullableSerializerIfNeeded(irType: IrType, serializer: IrParcelSerializer) =
|
||||
if (irType.isNullable()) IrNullAwareParcelSerializer(serializer) else serializer
|
||||
|
||||
private val irBuiltIns: IrBuiltIns = symbols.irBuiltIns
|
||||
private val irBuiltIns: IrBuiltIns
|
||||
get() = symbols.irBuiltIns
|
||||
|
||||
private val stringArraySerializer = IrSimpleParcelSerializer(symbols.parcelCreateStringArray, symbols.parcelWriteStringArray)
|
||||
private val stringListSerializer = IrSimpleParcelSerializer(symbols.parcelCreateStringArrayList, symbols.parcelWriteStringList)
|
||||
@@ -298,9 +303,6 @@ class IrParcelSerializerFactory(symbols: AndroidSymbols) {
|
||||
|
||||
private val sizeSerializer = IrSimpleParcelSerializer(symbols.parcelReadSize, symbols.parcelWriteSize)
|
||||
private val sizeFSerializer = IrSimpleParcelSerializer(symbols.parcelReadSizeF, symbols.parcelWriteSizeF)
|
||||
private val bundleSerializer = IrSimpleParcelSerializer(symbols.parcelReadBundle, symbols.parcelWriteBundle)
|
||||
private val persistableBundleSerializer =
|
||||
IrSimpleParcelSerializer(symbols.parcelReadPersistableBundle, symbols.parcelWritePersistableBundle)
|
||||
private val sparseBooleanArraySerializer =
|
||||
IrSimpleParcelSerializer(symbols.parcelReadSparseBooleanArray, symbols.parcelWriteSparseBooleanArray)
|
||||
}
|
||||
|
||||
+14
-4
@@ -215,15 +215,25 @@ class IrGenericParcelableParcelSerializer(private val parcelizeType: IrType) : I
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback parcel serializer for unknown types using Parcel.readValue/writeValue.
|
||||
// Creates a serializer from a pair of parcel methods of the form reader(ClassLoader)T and writer(T)V.
|
||||
// This needs a reference to the parcelize type itself in order to find the correct class loader to use, see KT-20027.
|
||||
class IrGenericValueParcelSerializer(private val parcelizeType: IrType) : IrParcelSerializer {
|
||||
class IrParcelSerializerWithClassLoader(
|
||||
private val parcelizeType: IrType,
|
||||
private val reader: IrSimpleFunctionSymbol,
|
||||
private val writer: IrSimpleFunctionSymbol
|
||||
) : IrParcelSerializer {
|
||||
override fun AndroidIrBuilder.readParcel(parcel: IrValueDeclaration): IrExpression {
|
||||
return parcelReadValue(irGet(parcel), classGetClassLoader(javaClassReference(parcelizeType)))
|
||||
return irCall(reader).apply {
|
||||
dispatchReceiver = irGet(parcel)
|
||||
putValueArgument(0, classGetClassLoader(javaClassReference(parcelizeType)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun AndroidIrBuilder.writeParcel(parcel: IrValueDeclaration, flags: IrValueDeclaration, value: IrExpression): IrExpression {
|
||||
return parcelWriteValue(irGet(parcel), value)
|
||||
return irCall(writer).apply {
|
||||
dispatchReceiver = irGet(parcel)
|
||||
putValueArgument(0, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
public final class A$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final A createFromParcel(android.os.Parcel parcel) {
|
||||
LABEL (L0)
|
||||
ALOAD (1)
|
||||
LDC (parcel)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||
NEW
|
||||
DUP
|
||||
ALOAD (1)
|
||||
LDC (LA;)
|
||||
INVOKEVIRTUAL (java/lang/Class, getClassLoader, ()Ljava/lang/ClassLoader;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, readValue, (Ljava/lang/ClassLoader;)Ljava/lang/Object;)
|
||||
ALOAD (1)
|
||||
LDC (LA;)
|
||||
INVOKEVIRTUAL (java/lang/Class, getClassLoader, ()Ljava/lang/ClassLoader;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, readBundle, (Ljava/lang/ClassLoader;)Landroid/os/Bundle;)
|
||||
ALOAD (1)
|
||||
LDC (LA;)
|
||||
INVOKEVIRTUAL (java/lang/Class, getClassLoader, ()Ljava/lang/ClassLoader;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, readPersistableBundle, (Ljava/lang/ClassLoader;)Landroid/os/PersistableBundle;)
|
||||
INVOKESPECIAL (A, <init>, (Ljava/lang/Object;Landroid/os/Bundle;Landroid/os/PersistableBundle;)V)
|
||||
ARETURN
|
||||
LABEL (L1)
|
||||
}
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel source) {
|
||||
LABEL (L0)
|
||||
ALOAD (0)
|
||||
ALOAD (1)
|
||||
INVOKEVIRTUAL (A$Creator, createFromParcel, (Landroid/os/Parcel;)LA;)
|
||||
ARETURN
|
||||
LABEL (L1)
|
||||
}
|
||||
|
||||
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 java.lang.Object a
|
||||
|
||||
private final android.os.Bundle b
|
||||
|
||||
private final android.os.PersistableBundle c
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
public void <init>(java.lang.Object a, android.os.Bundle b, android.os.PersistableBundle c)
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public final java.lang.Object getA()
|
||||
|
||||
public final android.os.Bundle getB()
|
||||
|
||||
public final android.os.PersistableBundle getC()
|
||||
|
||||
public void writeToParcel(android.os.Parcel out, int flags) {
|
||||
LABEL (L0)
|
||||
ALOAD (1)
|
||||
LDC (out)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||
ALOAD (1)
|
||||
ALOAD (0)
|
||||
GETFIELD (A, a, Ljava/lang/Object;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, writeValue, (Ljava/lang/Object;)V)
|
||||
ALOAD (1)
|
||||
ALOAD (0)
|
||||
GETFIELD (A, b, Landroid/os/Bundle;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, writeBundle, (Landroid/os/Bundle;)V)
|
||||
ALOAD (1)
|
||||
ALOAD (0)
|
||||
GETFIELD (A, c, Landroid/os/PersistableBundle;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, writePersistableBundle, (Landroid/os/PersistableBundle;)V)
|
||||
RETURN
|
||||
LABEL (L1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// CURIOUS_ABOUT writeToParcel, createFromParcel
|
||||
// WITH_RUNTIME
|
||||
|
||||
// Test to ensure that we are using the correct class loader
|
||||
// for generic types and bundles. See:
|
||||
// - https://issuetracker.google.com/184072801
|
||||
// - https://issuetracker.google.com/187577721
|
||||
|
||||
import kotlinx.parcelize.*
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.os.PersistableBundle
|
||||
|
||||
@Parcelize
|
||||
class A<T>(val a: @RawValue T, val b: Bundle, val c: PersistableBundle) : Parcelable
|
||||
@@ -0,0 +1,79 @@
|
||||
public final class A$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final A createFromParcel(android.os.Parcel in) {
|
||||
LABEL (L0)
|
||||
ALOAD (1)
|
||||
LDC (in)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||
NEW
|
||||
DUP
|
||||
ALOAD (1)
|
||||
LDC (Ljava/lang/Object;)
|
||||
INVOKEVIRTUAL (java/lang/Class, getClassLoader, ()Ljava/lang/ClassLoader;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, readValue, (Ljava/lang/ClassLoader;)Ljava/lang/Object;)
|
||||
ALOAD (1)
|
||||
INVOKEVIRTUAL (android/os/Parcel, readBundle, ()Landroid/os/Bundle;)
|
||||
ALOAD (1)
|
||||
INVOKEVIRTUAL (android/os/Parcel, readBundle, ()Landroid/os/PersistableBundle;)
|
||||
INVOKESPECIAL (A, <init>, (Ljava/lang/Object;Landroid/os/Bundle;Landroid/os/PersistableBundle;)V)
|
||||
ARETURN
|
||||
LABEL (L1)
|
||||
}
|
||||
|
||||
public java.lang.Object createFromParcel(android.os.Parcel p0) {
|
||||
LABEL (L0)
|
||||
LINENUMBER (15)
|
||||
ALOAD (0)
|
||||
ALOAD (1)
|
||||
INVOKEVIRTUAL (A$Creator, createFromParcel, (Landroid/os/Parcel;)LA;)
|
||||
ARETURN
|
||||
}
|
||||
|
||||
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 java.lang.Object a
|
||||
|
||||
private final android.os.Bundle b
|
||||
|
||||
private final android.os.PersistableBundle c
|
||||
|
||||
static void <clinit>()
|
||||
|
||||
public void <init>(java.lang.Object a, android.os.Bundle b, android.os.PersistableBundle c)
|
||||
|
||||
public int describeContents()
|
||||
|
||||
public final java.lang.Object getA()
|
||||
|
||||
public final android.os.Bundle getB()
|
||||
|
||||
public final android.os.PersistableBundle getC()
|
||||
|
||||
public void writeToParcel(android.os.Parcel parcel, int flags) {
|
||||
LABEL (L0)
|
||||
ALOAD (1)
|
||||
LDC (parcel)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkNotNullParameter, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||
ALOAD (1)
|
||||
ALOAD (0)
|
||||
GETFIELD (A, a, Ljava/lang/Object;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, writeValue, (Ljava/lang/Object;)V)
|
||||
ALOAD (1)
|
||||
ALOAD (0)
|
||||
GETFIELD (A, b, Landroid/os/Bundle;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, writeBundle, (Landroid/os/Bundle;)V)
|
||||
ALOAD (1)
|
||||
ALOAD (0)
|
||||
GETFIELD (A, c, Landroid/os/PersistableBundle;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, writeBundle, (Landroid/os/PersistableBundle;)V)
|
||||
RETURN
|
||||
LABEL (L1)
|
||||
}
|
||||
}
|
||||
+5
@@ -30,6 +30,11 @@ public class ParcelizeBytecodeListingTestGenerated extends AbstractParcelizeByte
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-compiler/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classLoaderValues.kt")
|
||||
public void testClassLoaderValues() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/classLoaderValues.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("customDescribeContents.kt")
|
||||
public void testCustomDescribeContents() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customDescribeContents.kt");
|
||||
|
||||
+5
@@ -30,6 +30,11 @@ public class ParcelizeIrBytecodeListingTestGenerated extends AbstractParcelizeIr
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/parcelize/parcelize-compiler/testData/codegen"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classLoaderValues.kt")
|
||||
public void testClassLoaderValues() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/classLoaderValues.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("customDescribeContents.kt")
|
||||
public void testCustomDescribeContents() throws Exception {
|
||||
runTest("plugins/parcelize/parcelize-compiler/testData/codegen/customDescribeContents.kt");
|
||||
|
||||
Reference in New Issue
Block a user