Parcelable: Use ClassLoader from the container class to load Parcelable (KT-20027)
When the parameter type is just "Parcelable", we would not pick the wrong (system) class loader anymore.
This commit is contained in:
committed by
Yan Zhulanow
parent
c9ec1a2511
commit
3587a2a08e
+5
-2
@@ -114,6 +114,8 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
||||
"(${containerAsmType.descriptor}${PARCEL_TYPE.descriptor}I)V", false)
|
||||
}
|
||||
else {
|
||||
val context = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType)
|
||||
|
||||
for ((fieldName, type) in properties) {
|
||||
val asmType = codegen.typeMapper.mapType(type)
|
||||
|
||||
@@ -121,7 +123,7 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
||||
v.load(0, containerAsmType)
|
||||
v.getfield(containerAsmType.internalName, fieldName, asmType.descriptor)
|
||||
|
||||
val serializer = ParcelSerializer.get(type, asmType, codegen.typeMapper)
|
||||
val serializer = ParcelSerializer.get(type, asmType, context)
|
||||
serializer.writeValue(v)
|
||||
}
|
||||
}
|
||||
@@ -191,12 +193,13 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
||||
v.dup()
|
||||
|
||||
val asmConstructorParameters = StringBuilder()
|
||||
val context = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType)
|
||||
|
||||
for ((_, type) in properties) {
|
||||
val asmType = codegen.typeMapper.mapType(type)
|
||||
asmConstructorParameters.append(asmType.descriptor)
|
||||
|
||||
val serializer = ParcelSerializer.get(type, asmType, codegen.typeMapper)
|
||||
val serializer = ParcelSerializer.get(type, asmType, context)
|
||||
v.load(1, parcelAsmType)
|
||||
serializer.readValue(v)
|
||||
}
|
||||
|
||||
+9
-3
@@ -183,11 +183,16 @@ class ParcelableDeclarationChecker : SimpleDeclarationChecker {
|
||||
/* isJvm8TargetWithDefaults */ false)
|
||||
|
||||
for (parameter in primaryConstructor?.valueParameters.orEmpty()) {
|
||||
checkParcelableClassProperty(parameter, diagnosticHolder, typeMapper)
|
||||
checkParcelableClassProperty(parameter, descriptor, diagnosticHolder, typeMapper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkParcelableClassProperty(parameter: KtParameter, diagnosticHolder: DiagnosticSink, typeMapper: KotlinTypeMapper) {
|
||||
private fun checkParcelableClassProperty(
|
||||
parameter: KtParameter,
|
||||
containerClass: ClassDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
typeMapper: KotlinTypeMapper
|
||||
) {
|
||||
if (!parameter.hasValOrVar()) {
|
||||
val reportElement = parameter.nameIdentifier ?: parameter
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
@@ -201,7 +206,8 @@ class ParcelableDeclarationChecker : SimpleDeclarationChecker {
|
||||
val asmType = typeMapper.mapType(type)
|
||||
|
||||
try {
|
||||
ParcelSerializer.get(type, asmType, typeMapper, strict = true)
|
||||
val context = ParcelSerializer.ParcelSerializerContext(typeMapper, typeMapper.mapType(containerClass.defaultType))
|
||||
ParcelSerializer.get(type, asmType, context, strict = true)
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
// get() throws IllegalArgumentException on unknown types
|
||||
|
||||
+12
-8
@@ -44,6 +44,8 @@ interface ParcelSerializer {
|
||||
fun writeValue(v: InstructionAdapter)
|
||||
fun readValue(v: InstructionAdapter)
|
||||
|
||||
class ParcelSerializerContext(val typeMapper: KotlinTypeMapper, val containerClassType: Type)
|
||||
|
||||
companion object {
|
||||
private fun KotlinTypeMapper.mapTypeSafe(type: KotlinType): Type {
|
||||
return if (type.isError) Type.getObjectType("java/lang/Object") else mapType(type)
|
||||
@@ -52,17 +54,19 @@ interface ParcelSerializer {
|
||||
fun get(
|
||||
type: KotlinType,
|
||||
asmType: Type,
|
||||
typeMapper: KotlinTypeMapper,
|
||||
context: ParcelSerializerContext,
|
||||
forceBoxed: Boolean = false,
|
||||
strict: Boolean = false
|
||||
): ParcelSerializer {
|
||||
val typeMapper = context.typeMapper
|
||||
|
||||
val className = asmType.className
|
||||
fun strict() = strict && !type.annotations.hasAnnotation(RAWVALUE_ANNOTATION_FQNAME)
|
||||
|
||||
return when {
|
||||
asmType.sort == Type.ARRAY -> {
|
||||
val elementType = type.builtIns.getArrayElementType(type)
|
||||
val elementSerializer = get(elementType, typeMapper.mapTypeSafe(elementType), typeMapper, strict = strict())
|
||||
val elementSerializer = get(elementType, typeMapper.mapTypeSafe(elementType), context, strict = strict())
|
||||
|
||||
wrapToNullAwareIfNeeded(type, ArrayParcelSerializer(asmType, elementSerializer))
|
||||
}
|
||||
@@ -90,7 +94,7 @@ interface ParcelSerializer {
|
||||
-> {
|
||||
val elementType = type.arguments.single().type
|
||||
val elementSerializer = get(
|
||||
elementType, typeMapper.mapTypeSafe(elementType), typeMapper, forceBoxed = true, strict = strict())
|
||||
elementType, typeMapper.mapTypeSafe(elementType), context, forceBoxed = true, strict = strict())
|
||||
wrapToNullAwareIfNeeded(type, ListSetParcelSerializer(asmType, elementSerializer))
|
||||
}
|
||||
|
||||
@@ -104,9 +108,9 @@ interface ParcelSerializer {
|
||||
-> {
|
||||
val (keyType, valueType) = type.arguments.apply { assert(this.size == 2) }
|
||||
val keySerializer = get(
|
||||
keyType.type, typeMapper.mapTypeSafe(keyType.type), typeMapper, forceBoxed = true, strict = strict())
|
||||
keyType.type, typeMapper.mapTypeSafe(keyType.type), context, forceBoxed = true, strict = strict())
|
||||
val valueSerializer = get(
|
||||
valueType.type, typeMapper.mapTypeSafe(valueType.type), typeMapper, forceBoxed = true, strict = strict())
|
||||
valueType.type, typeMapper.mapTypeSafe(valueType.type), context, forceBoxed = true, strict = strict())
|
||||
wrapToNullAwareIfNeeded(type, MapParcelSerializer(asmType, keySerializer, valueSerializer))
|
||||
}
|
||||
|
||||
@@ -153,7 +157,7 @@ interface ParcelSerializer {
|
||||
asmType.isSparseArray() -> {
|
||||
val elementType = type.arguments.single().type
|
||||
val elementSerializer = get(
|
||||
elementType, typeMapper.mapTypeSafe(elementType), typeMapper, forceBoxed = true, strict = strict())
|
||||
elementType, typeMapper.mapTypeSafe(elementType), context, forceBoxed = true, strict = strict())
|
||||
wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(asmType, elementSerializer))
|
||||
}
|
||||
|
||||
@@ -186,10 +190,10 @@ interface ParcelSerializer {
|
||||
}
|
||||
|
||||
creatorAsmType?.let { EfficientParcelableParcelSerializer(asmType, creatorAsmType) }
|
||||
?: GenericParcelableParcelSerializer(asmType)
|
||||
?: GenericParcelableParcelSerializer(asmType, context.containerClassType)
|
||||
}
|
||||
else {
|
||||
GenericParcelableParcelSerializer(asmType)
|
||||
GenericParcelableParcelSerializer(asmType, context.containerClassType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -462,7 +462,7 @@ internal class EfficientParcelableParcelSerializer(override val asmType: Type, p
|
||||
}
|
||||
}
|
||||
|
||||
internal class GenericParcelableParcelSerializer(override val asmType: Type) : ParcelSerializer {
|
||||
internal class GenericParcelableParcelSerializer(override val asmType: Type, val containerClassType: Type) : ParcelSerializer {
|
||||
override fun writeValue(v: InstructionAdapter) {
|
||||
// -> parcel, parcelable
|
||||
v.aconst(0) // -> parcel, parcelable, flags
|
||||
@@ -471,7 +471,7 @@ internal class GenericParcelableParcelSerializer(override val asmType: Type) : P
|
||||
|
||||
override fun readValue(v: InstructionAdapter) {
|
||||
// -> parcel
|
||||
v.aconst(asmType) // -> parcel, type
|
||||
v.aconst(containerClassType) // -> parcel, type
|
||||
v.invokevirtual("java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false) // -> parcel, classloader
|
||||
v.invokevirtual(PARCEL_TYPE.internalName, "readParcelable", "(Ljava/lang/ClassLoader;)Landroid/os/Parcelable;", false)
|
||||
v.castIfNeeded(asmType)
|
||||
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
// CURIOUS_ABOUT writeToParcel, createFromParcel, <clinit>
|
||||
|
||||
package test
|
||||
|
||||
import kotlinx.android.parcel.*
|
||||
import android.os.Parcelable
|
||||
|
||||
@Parcelize
|
||||
class Foo(val parcelable: Parcelable): Parcelable
|
||||
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
public final class test/Foo$Companion : java/lang/Object {
|
||||
private void <init>()
|
||||
|
||||
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker p0)
|
||||
}
|
||||
|
||||
public static class test/Foo$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||
public void <init>()
|
||||
|
||||
public final java.lang.Object createFromParcel(android.os.Parcel p0) {
|
||||
LABEL (L0)
|
||||
ALOAD (1)
|
||||
LDC (in)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkParameterIsNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||
NEW
|
||||
DUP
|
||||
ALOAD (1)
|
||||
LDC (Ltest/Foo;)
|
||||
INVOKEVIRTUAL (java/lang/Class, getClassLoader, ()Ljava/lang/ClassLoader;)
|
||||
INVOKEVIRTUAL (android/os/Parcel, readParcelable, (Ljava/lang/ClassLoader;)Landroid/os/Parcelable;)
|
||||
INVOKESPECIAL (test/Foo, <init>, (Landroid/os/Parcelable;)V)
|
||||
ARETURN
|
||||
LABEL (L1)
|
||||
}
|
||||
|
||||
public final test.Foo[] newArray(int p0)
|
||||
}
|
||||
|
||||
public final class test/Foo : java/lang/Object, android/os/Parcelable {
|
||||
public final static test.Foo$Creator CREATOR
|
||||
|
||||
public final static test.Foo$Companion Companion
|
||||
|
||||
private final android.os.Parcelable parcelable
|
||||
|
||||
static void <clinit>() {
|
||||
NEW
|
||||
DUP
|
||||
ACONST_NULL
|
||||
INVOKESPECIAL (test/Foo$Companion, <init>, (Lkotlin/jvm/internal/DefaultConstructorMarker;)V)
|
||||
PUTSTATIC (Companion, Ltest/Foo$Companion;)
|
||||
NEW
|
||||
DUP
|
||||
INVOKESPECIAL (test/Foo$Creator, <init>, ()V)
|
||||
PUTSTATIC (CREATOR, Ltest/Foo$Creator;)
|
||||
RETURN
|
||||
}
|
||||
|
||||
public void <init>(android.os.Parcelable p0)
|
||||
|
||||
public final int describeContents()
|
||||
|
||||
public final android.os.Parcelable getParcelable()
|
||||
|
||||
public final void writeToParcel(android.os.Parcel p0, int p1) {
|
||||
LABEL (L0)
|
||||
ALOAD (1)
|
||||
LDC (parcel)
|
||||
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkParameterIsNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||
ALOAD (1)
|
||||
ALOAD (0)
|
||||
GETFIELD (parcelable, Landroid/os/Parcelable;)
|
||||
LDC (0)
|
||||
INVOKEVIRTUAL (android/os/Parcel, writeParcelable, (Landroid/os/Parcelable;I)V)
|
||||
RETURN
|
||||
LABEL (L1)
|
||||
}
|
||||
}
|
||||
+6
@@ -84,6 +84,12 @@ public class ParcelBytecodeListingTestGenerated extends AbstractParcelBytecodeLi
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("parcelable.kt")
|
||||
public void testParcelable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/parcelable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("serializable.kt")
|
||||
public void testSerializable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/serializable.kt");
|
||||
|
||||
Reference in New Issue
Block a user