diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableClinitClassBuilderInterceptorExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableClinitClassBuilderInterceptorExtension.kt index 9b9aca494fc..bf221cbfeea 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableClinitClassBuilderInterceptorExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableClinitClassBuilderInterceptorExtension.kt @@ -84,6 +84,8 @@ class ParcelableClinitClassBuilderInterceptorExtension : ClassBuilderInterceptor ) { if (origin is KtClass) { currentClass = origin + } else { + currentClass = null } currentClassName = name @@ -118,7 +120,13 @@ class ParcelableClinitClassBuilderInterceptorExtension : ClassBuilderInterceptor ): MethodVisitor { if (name == "" && currentClass != null && currentClassName != null) { isClinitGenerated = true - return ClinitAwareMethodVisitor(currentClassName!!, super.newMethod(origin, access, name, desc, signature, exceptions)) + + val descriptor = bindingContext[BindingContext.CLASS, currentClass] + if (descriptor != null && descriptor.isMagicParcelable) { + return ClinitAwareMethodVisitor( + currentClassName!!, + super.newMethod(origin, access, name, desc, signature, exceptions)) + } } return super.newMethod(origin, access, name, desc, signature, exceptions) @@ -129,7 +137,7 @@ class ParcelableClinitClassBuilderInterceptorExtension : ClassBuilderInterceptor override fun visitInsn(opcode: Int) { if (opcode == Opcodes.RETURN) { val iv = InstructionAdapter(this) - val creatorName = "$parcelableName\$CREATOR" + val creatorName = "$parcelableName\$Creator" val creatorType = Type.getObjectType(creatorName) iv.anew(creatorType) diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt index 8316271002f..213cc74b9aa 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableCodegenExtension.kt @@ -170,14 +170,13 @@ class ParcelableCodegenExtension : ExpressionCodegenExtension { ) { val containerAsmType = codegen.typeMapper.mapType(parcelableClass) - createMethod(creatorClass, CREATE_FROM_PARCEL, parcelableClass.defaultType, "in" to parcelClassType).write(codegen) { + createMethod(creatorClass, CREATE_FROM_PARCEL, parcelableClass.builtIns.anyType, "in" to parcelClassType).write(codegen) { if (parcelerObject != null) { val (companionAsmType, companionFieldName) = getCompanionClassType(containerAsmType, parcelerObject) v.getstatic(containerAsmType.internalName, companionFieldName, companionAsmType.descriptor) v.load(1, PARCEL_TYPE) - v.invokevirtual(companionAsmType.internalName, "create", - "(${PARCEL_TYPE.descriptor})${containerAsmType.descriptor}", false) + v.invokevirtual(companionAsmType.internalName, "create", "(${PARCEL_TYPE.descriptor})Landroid/os/Parcelable;", false) } else { v.anew(containerAsmType) @@ -203,7 +202,7 @@ class ParcelableCodegenExtension : ExpressionCodegenExtension { private fun writeCreatorAccessField(codegen: ImplementationBodyCodegen, parcelableClass: ClassDescriptor) { val parcelableAsmType = codegen.typeMapper.mapType(parcelableClass.defaultType) - val creatorAsmType = Type.getObjectType(parcelableAsmType.internalName + "\$CREATOR") + val creatorAsmType = Type.getObjectType(parcelableAsmType.internalName + "\$Creator") codegen.v.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_STATIC or ACC_PUBLIC or ACC_FINAL, "CREATOR", creatorAsmType.descriptor, null, null) } @@ -217,7 +216,7 @@ class ParcelableCodegenExtension : ExpressionCodegenExtension { properties: List> ) { val containerAsmType = codegen.typeMapper.mapType(parcelableClass.defaultType) - val creatorAsmType = Type.getObjectType(containerAsmType.internalName + "\$CREATOR") + val creatorAsmType = Type.getObjectType(containerAsmType.internalName + "\$Creator") val creatorClass = ClassDescriptorImpl( parcelableClass.containingDeclaration, Name.identifier("Creator"), Modality.FINAL, ClassKind.CLASS, emptyList(), diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializer.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializer.kt index bf063732fc4..66c721b1675 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializer.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializer.kt @@ -16,9 +16,18 @@ package org.jetbrains.kotlin.android.parcel.serializers +import org.jetbrains.kotlin.android.parcel.isMagicParcelable import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.synthetic.isVisibleOutside import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -98,6 +107,14 @@ interface ParcelSerializer { Method("writeBundle"), Method("readBundle")) + type.isIBinder() -> NullCompliantObjectParcelSerializer(asmType, + Method("writeStrongBinder", "(Landroid/os/IBinder;)V"), + Method("readStrongBinder", "()Landroid/os/IBinder;")) + + type.isIInterface() -> NullCompliantObjectParcelSerializer(asmType, + Method("writeStrongInterface", "(Landroid/os/IInterface;)V"), + Method("readStrongInterface", "()Landroid/os/IInterface;")) + asmType.isPersistableBundle() -> NullCompliantObjectParcelSerializer(asmType, Method("writeBundle"), Method("readBundle")) @@ -118,14 +135,42 @@ interface ParcelSerializer { wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(asmType, elementSerializer)) } + type.isCharSequence() -> CharSequenceParcelSerializer(asmType) + type.isException() -> wrapToNullAwareIfNeeded(type, NullCompliantObjectParcelSerializer(asmType, Method("writeException"), Method("readException"))) + // Write at least a nullability byte. + // We don't want parcel to be empty in case if all constructor parameters are objects + type.isNamedObject() -> NullAwareParcelSerializerWrapper(ObjectParcelSerializer(asmType, type, typeMapper)) + + type.isEnum() -> wrapToNullAwareIfNeeded(type, EnumParcelSerializer(asmType)) + asmType.isFileDescriptor() -> wrapToNullAwareIfNeeded(type, NullCompliantObjectParcelSerializer(asmType, Method("writeRawFileDescriptor"), Method("readRawFileDescriptor"))) + type.isParcelable() -> { + val clazz = type.constructor.declarationDescriptor as? ClassDescriptor + if (clazz != null && clazz.modality == Modality.FINAL) { + val creatorVar = clazz.staticScope.getContributedVariables( + Name.identifier("CREATOR"), NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS).firstOrNull() + + val creatorAsmType = when { + creatorVar != null -> typeMapper.mapType(creatorVar.type) + clazz.isMagicParcelable -> Type.getObjectType(asmType.internalName + "\$Creator") + else -> null + } + + creatorAsmType?.let { EfficientParcelableParcelSerializer(asmType, creatorAsmType) } + ?: GenericParcelableParcelSerializer(asmType) + } + else { + GenericParcelableParcelSerializer(asmType) + } + } + type.isSerializable() -> NullCompliantObjectParcelSerializer(asmType, Method("writeSerializable"), Method("readSerializable")) @@ -151,6 +196,19 @@ interface ParcelSerializer { private fun Type.isSparseArray() = this.descriptor == "Landroid/util/SparseArray;" private fun KotlinType.isSerializable() = matchesFqNameWithSupertypes("java.io.Serializable") private fun KotlinType.isException() = matchesFqNameWithSupertypes("java.lang.Exception") + private fun KotlinType.isIBinder() = matchesFqNameWithSupertypes("android.os.IBinder") + private fun KotlinType.isIInterface() = matchesFqNameWithSupertypes("android.os.IInterface") + private fun KotlinType.isParcelable() = matchesFqNameWithSupertypes("android.os.Parcelable") + private fun KotlinType.isCharSequence() = matchesFqName("kotlin.CharSequence") || matchesFqName("java.lang.CharSequence") + + private fun KotlinType.isNamedObject(): Boolean { + val classDescriptor = constructor.declarationDescriptor as? ClassDescriptor ?: return false + if (!classDescriptor.visibility.isVisibleOutside()) return false + if (DescriptorUtils.isAnonymousObject(classDescriptor)) return false + return classDescriptor.kind == ClassKind.OBJECT + } + + private fun KotlinType.isEnum() = (constructor.declarationDescriptor as? ClassDescriptor)?.kind == ClassKind.ENUM_CLASS private fun Type.isPrimitive(): Boolean = when (this.sort) { Type.BOOLEAN, Type.CHAR, Type.BYTE, Type.SHORT, Type.INT, Type.FLOAT, Type.LONG, Type.DOUBLE -> true @@ -174,7 +232,7 @@ interface ParcelSerializer { return true } - return this.constructor.supertypes.any { it.matchesFqName(fqName) } + return TypeUtils.getAllSupertypes(this).any { it.matchesFqName(fqName) } } private fun KotlinType.matchesFqName(fqName: String): Boolean { diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializers.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializers.kt index 2258010dd01..b02d06d62ed 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializers.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/serializers/ParcelSerializers.kt @@ -16,6 +16,9 @@ package org.jetbrains.kotlin.android.parcel.serializers +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -383,6 +386,94 @@ internal class SparseArrayParcelSerializer(override val asmType: Type, private v } } +internal class ObjectParcelSerializer( + override val asmType: Type, + private val type: KotlinType, + private val typeMapper: KotlinTypeMapper +) : ParcelSerializer { + override fun writeValue(v: InstructionAdapter) { + v.pop2() + } + + override fun readValue(v: InstructionAdapter) { + v.pop() + + // Handle companion object + val clazz = type.constructor.declarationDescriptor as? ClassDescriptor + if (clazz != null && clazz.isCompanionObject) { + val outerClass = clazz.containingDeclaration as? ClassDescriptor + if (outerClass != null) { + v.getstatic(typeMapper.mapType(outerClass.defaultType).internalName, clazz.name.asString(), asmType.descriptor) + return + } + } + + v.getstatic(asmType.internalName, "INSTANCE", asmType.descriptor) + } +} + +internal class EnumParcelSerializer(override val asmType: Type) : ParcelSerializer { + override fun writeValue(v: InstructionAdapter) { + v.invokevirtual(asmType.internalName, "name", "()Ljava/lang/String;", false) + v.invokevirtual(PARCEL_TYPE.internalName, "writeString", "(Ljava/lang/String;)V", false) + } + + override fun readValue(v: InstructionAdapter) { + v.invokevirtual(PARCEL_TYPE.internalName, "readString", "()Ljava/lang/String;", false) + v.invokestatic(asmType.internalName, "valueOf", "(Ljava/lang/String;)${asmType.descriptor}", false) + } +} + +internal class CharSequenceParcelSerializer(override val asmType: Type) : ParcelSerializer { + override fun writeValue(v: InstructionAdapter) { + // -> parcel, seq + v.swap() // -> seq, parcel + v.aconst(0) // -> seq, parcel, flags + v.invokestatic("android/text/TextUtils", "writeToParcel", "(Ljava/lang/CharSequence;Landroid/os/Parcel;I)V", false) + } + + override fun readValue(v: InstructionAdapter) { + // -> parcel + v.getstatic("android/text/TextUtils", "CHAR_SEQUENCE_CREATOR", "Landroid/os/Parcelable\$Creator;") // -> parcel, creator + v.swap() // -> creator, parcel + v.invokeinterface("android/os/Parcelable\$Creator", "createFromParcel", "(Landroid/os/Parcel;)Ljava/lang/Object;") + v.castIfNeeded(asmType) + } +} + +internal class EfficientParcelableParcelSerializer(override val asmType: Type, private val creatorAsmType: Type) : ParcelSerializer { + override fun writeValue(v: InstructionAdapter) { + // -> parcel, parcelable + v.swap() // -> parcelable, parcel + v.aconst(0) // -> parcelable, parcel, flags + v.invokeinterface("android/os/Parcelable", "writeToParcel", "(Landroid/os/Parcel;I)V") + } + + override fun readValue(v: InstructionAdapter) { + // -> parcel + v.getstatic(asmType.internalName, "CREATOR", creatorAsmType.descriptor) // -> parcel, creator + v.swap() // -> creator, parcel + v.invokeinterface("android/os/Parcelable\$Creator", "createFromParcel", "(Landroid/os/Parcel;)Ljava/lang/Object;") + v.castIfNeeded(asmType) + } +} + +internal class GenericParcelableParcelSerializer(override val asmType: Type) : ParcelSerializer { + override fun writeValue(v: InstructionAdapter) { + // -> parcel, parcelable + v.aconst(0) // -> parcel, parcelable, flags + v.invokevirtual(PARCEL_TYPE.internalName, "writeParcelable", "(Landroid/os/Parcelable;I)V", false) + } + + override fun readValue(v: InstructionAdapter) { + // -> parcel + v.aconst(asmType) // -> 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) + } +} + internal class NullAwareParcelSerializerWrapper(val delegate: ParcelSerializer) : ParcelSerializer { override val asmType: Type get() = delegate.asmType diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/charSequence.kt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/charSequence.kt new file mode 100644 index 00000000000..488178f6f74 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/charSequence.kt @@ -0,0 +1,25 @@ +// WITH_RUNTIME + +@file:JvmName("TestKt") +package test + +import kotlinx.android.parcel.* +import android.os.Parcel +import android.os.Parcelable +import android.text.SpannableString + +@MagicParcel +data class Test(val simple: CharSequence, val spanned: CharSequence) : Parcelable + +fun box() = parcelTest { parcel -> + val test = Test("John", SpannableString("Smith")) + test.writeToParcel(parcel, 0) + + val bytes = parcel.marshall() + parcel.unmarshall(bytes, 0, bytes.size) + + val test2 = readFromParcel(parcel) + + assert(test.simple.toString() == test2.simple.toString()) + assert(test.spanned.toString() == test2.spanned.toString()) +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/enums.kt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/enums.kt new file mode 100644 index 00000000000..e68a86b5c05 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/enums.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME + +@file:JvmName("TestKt") +package test + +import kotlinx.android.parcel.* +import android.os.Parcel +import android.os.Parcelable + +enum class Color { + BLACK, WHITE +} + +@MagicParcel +data class Test(val name: String, val color: Color) : Parcelable + +fun box() = parcelTest { parcel -> + val test = Test("John", Color.WHITE) + test.writeToParcel(parcel, 0) + + val bytes = parcel.marshall() + parcel.unmarshall(bytes, 0, bytes.size) + + val test2 = readFromParcel(parcel) + assert(test == test2) +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/nestedParcelable.kt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/nestedParcelable.kt new file mode 100644 index 00000000000..9937b43b456 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/nestedParcelable.kt @@ -0,0 +1,33 @@ +// WITH_RUNTIME + +@file:JvmName("TestKt") +package test + +import kotlinx.android.parcel.* +import android.os.Parcel +import android.os.Parcelable + +// Starts with A, should be loaded before other classes +abstract class AParcelable : Parcelable + +@MagicParcel +data class P1(val a: String) : AParcelable() + +sealed class Sealed : AParcelable() + +@MagicParcel +data class Sealed1(val a: Int) : Sealed() + +@MagicParcel +data class Test(val a: P1, val b: AParcelable, val c: Sealed, val d: Sealed1) : Parcelable + +fun box() = parcelTest { parcel -> + val test = Test(P1(""), P1("My"), Sealed1(1), Sealed1(5)) + test.writeToParcel(parcel, 0) + + val bytes = parcel.marshall() + parcel.unmarshall(bytes, 0, bytes.size) + + val test2 = readFromParcel(parcel) + assert(test == test2) +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/objects.kt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/objects.kt new file mode 100644 index 00000000000..a673c3c52e0 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/box/objects.kt @@ -0,0 +1,30 @@ +// WITH_RUNTIME + +@file:JvmName("TestKt") +package test + +import kotlinx.android.parcel.* +import android.os.Parcel +import android.os.Parcelable + +object Obj1 { + object Obj2 +} + +@MagicParcel +data class Test(val o1: Obj1, val o2: Obj1.Obj2, val com: Com) : Parcelable { + companion object Com { + + } +} + +fun box() = parcelTest { parcel -> + val test = Test(Obj1, Obj1.Obj2, Test.Com) + test.writeToParcel(parcel, 0) + + val bytes = parcel.marshall() + parcel.unmarshall(bytes, 0, bytes.size) + + val test2 = readFromParcel(parcel) + assert(test == test2) +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/IBinderIInterface.kt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/IBinderIInterface.kt new file mode 100644 index 00000000000..104b477ba42 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/IBinderIInterface.kt @@ -0,0 +1,9 @@ +// CURIOUS_ABOUT writeToParcel, createFromParcel + +import kotlinx.android.parcel.* +import android.os.Parcelable +import android.os.IBinder +import android.os.IInterface + +@MagicParcel +class User(val binder: IBinder, val intf: IInterface?) : Parcelable \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/IBinderIInterface.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/IBinderIInterface.txt new file mode 100644 index 00000000000..1648f4ffd96 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/IBinderIInterface.txt @@ -0,0 +1,56 @@ +public static class User$Creator : java/lang/Object, android/os/Parcelable$Creator { + public void () + + 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) + INVOKEVIRTUAL (android/os/Parcel, readStrongBinder, ()Landroid/os/IBinder;) + ALOAD (1) + INVOKEVIRTUAL (android/os/Parcel, readStrongInterface, ()Landroid/os/IInterface;) + INVOKESPECIAL (User, , (Landroid/os/IBinder;Landroid/os/IInterface;)V) + ARETURN + LABEL (L1) + } + + public final User[] newArray(int p0) +} + +public final class User : java/lang/Object, android/os/Parcelable { + public final static User$Creator CREATOR + + private final android.os.IBinder binder + + private final android.os.IInterface intf + + static void () + + public void (android.os.IBinder p0, android.os.IInterface p1) + + public final int describeContents() + + public final android.os.IBinder getBinder() + + public final android.os.IInterface getIntf() + + 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 (binder, Landroid/os/IBinder;) + INVOKEVIRTUAL (android/os/Parcel, writeStrongBinder, (Landroid/os/IBinder;)V) + ALOAD (1) + ALOAD (0) + GETFIELD (intf, Landroid/os/IInterface;) + INVOKEVIRTUAL (android/os/Parcel, writeStrongInterface, (Landroid/os/IInterface;)V) + RETURN + LABEL (L1) + } +} diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customDescribeContents.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customDescribeContents.txt index 1342fcea441..13c201e8df0 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customDescribeContents.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customDescribeContents.txt @@ -1,13 +1,13 @@ -public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class User$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final User createFromParcel(android.os.Parcel p0) + public final java.lang.Object createFromParcel(android.os.Parcel p0) public final User[] newArray(int p0) } public final class User : java/lang/Object, android/os/Parcelable { - public final static User$CREATOR CREATOR + public final static User$Creator CREATOR private final int age diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimple.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimple.txt index ab2f97e0099..212e6f55206 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimple.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimple.txt @@ -1,27 +1,3 @@ -public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creator { - public void () - - public final User createFromParcel(android.os.Parcel p0) { - LABEL (L0) - ALOAD (1) - LDC (in) - INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkParameterIsNotNull, (Ljava/lang/Object;Ljava/lang/String;)V) - GETSTATIC (Companion, LUser$Companion;) - ALOAD (1) - INVOKEVIRTUAL (User$Companion, create, (Landroid/os/Parcel;)LUser;) - ARETURN - LABEL (L1) - } - - public final User[] newArray(int p0) { - LABEL (L0) - ILOAD (1) - ANEWARRAY - ARETURN - LABEL (L1) - } -} - final class User$Companion : java/lang/Object, kotlinx/android/parcel/Parceler { private void () @@ -57,8 +33,32 @@ final class User$Companion : java/lang/Object, kotlinx/android/parcel/Parceler { public void write(android.os.Parcelable p0, android.os.Parcel p1, int p2) } +public static class User$Creator : java/lang/Object, android/os/Parcelable$Creator { + public void () + + 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) + GETSTATIC (Companion, LUser$Companion;) + ALOAD (1) + INVOKEVIRTUAL (User$Companion, create, (Landroid/os/Parcel;)Landroid/os/Parcelable;) + ARETURN + LABEL (L1) + } + + public final User[] newArray(int p0) { + LABEL (L0) + ILOAD (1) + ANEWARRAY + ARETURN + LABEL (L1) + } +} + public final class User : java/lang/Object, android/os/Parcelable { - public final static User$CREATOR CREATOR + public final static User$Creator CREATOR public final static User$Companion Companion diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimpleWithNewArray.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimpleWithNewArray.txt index 1d2b1c795df..9e7343a3531 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimpleWithNewArray.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/customSimpleWithNewArray.txt @@ -1,18 +1,3 @@ -public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creator { - public void () - - public final User createFromParcel(android.os.Parcel p0) - - public final User[] newArray(int p0) { - LABEL (L0) - GETSTATIC (Companion, LUser$Companion;) - ILOAD (1) - INVOKEVIRTUAL (User$Companion, newArray, (I)[LUser;) - ARETURN - LABEL (L1) - } -} - final class User$Companion : java/lang/Object, kotlinx/android/parcel/Parceler { private void () @@ -46,8 +31,23 @@ final class User$Companion : java/lang/Object, kotlinx/android/parcel/Parceler { public void write(android.os.Parcelable p0, android.os.Parcel p1, int p2) } +public static class User$Creator : java/lang/Object, android/os/Parcelable$Creator { + public void () + + public final java.lang.Object createFromParcel(android.os.Parcel p0) + + public final User[] newArray(int p0) { + LABEL (L0) + GETSTATIC (Companion, LUser$Companion;) + ILOAD (1) + INVOKEVIRTUAL (User$Companion, newArray, (I)[LUser;) + ARETURN + LABEL (L1) + } +} + public final class User : java/lang/Object, android/os/Parcelable { - public final static User$CREATOR CREATOR + public final static User$Creator CREATOR public final static User$Companion Companion diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/duplicatingClinit.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/duplicatingClinit.txt index 7fc26586d07..5da1a980481 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/duplicatingClinit.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/duplicatingClinit.txt @@ -1,11 +1,3 @@ -public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creator { - public void () - - public final User createFromParcel(android.os.Parcel p0) - - public final User[] newArray(int p0) -} - public final class User$Companion : java/lang/Object { private void () @@ -18,8 +10,16 @@ public final class User$Companion : java/lang/Object { private static void test$annotations() } +public static class User$Creator : java/lang/Object, android/os/Parcelable$Creator { + public void () + + public final java.lang.Object createFromParcel(android.os.Parcel p0) + + public final User[] newArray(int p0) +} + public final class User : java/lang/Object, android/os/Parcelable { - public final static User$CREATOR CREATOR + public final static User$Creator CREATOR public final static User$Companion Companion @@ -41,8 +41,8 @@ public final class User : java/lang/Object, android/os/Parcelable { PUTSTATIC (test, Ljava/lang/StringBuilder;) NEW DUP - INVOKESPECIAL (User$CREATOR, , ()V) - PUTSTATIC (CREATOR, LUser$CREATOR;) + INVOKESPECIAL (User$Creator, , ()V) + PUTSTATIC (CREATOR, LUser$Creator;) RETURN } diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/listInsideList.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/listInsideList.txt index a446b1e3da1..75b8ec06748 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/listInsideList.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/listInsideList.txt @@ -1,13 +1,13 @@ -public static class Test$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class Test$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final Test createFromParcel(android.os.Parcel p0) + public final java.lang.Object createFromParcel(android.os.Parcel p0) public final Test[] newArray(int p0) } public final class Test : java/lang/Object { - public final static Test$CREATOR CREATOR + public final static Test$Creator CREATOR private final java.util.List names diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/nullableNotNullSize.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/nullableNotNullSize.txt index e8f77cd5a57..5e2bfc82c69 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/nullableNotNullSize.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/nullableNotNullSize.txt @@ -1,13 +1,13 @@ -public static class TestNotNull$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class TestNotNull$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final TestNotNull createFromParcel(android.os.Parcel p0) + public final java.lang.Object createFromParcel(android.os.Parcel p0) public final TestNotNull[] newArray(int p0) } public final class TestNotNull : java/lang/Object { - public final static TestNotNull$CREATOR CREATOR + public final static TestNotNull$Creator CREATOR private final android.util.Size a @@ -33,16 +33,16 @@ public final class TestNotNull : java/lang/Object { } } -public static class TestNullable$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class TestNullable$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final TestNullable createFromParcel(android.os.Parcel p0) + public final java.lang.Object createFromParcel(android.os.Parcel p0) public final TestNullable[] newArray(int p0) } public final class TestNullable : java/lang/Object { - public final static TestNullable$CREATOR CREATOR + public final static TestNullable$Creator CREATOR private final android.util.Size a diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/serializable.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/serializable.txt index 2050cce1d64..3b9f0cf8d49 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/serializable.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/serializable.txt @@ -10,10 +10,10 @@ public final class SerializableSimple : java/lang/Object, java/io/Serializable { public final java.lang.String getB() } -public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class User$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final User createFromParcel(android.os.Parcel p0) { + public final java.lang.Object createFromParcel(android.os.Parcel p0) { LABEL (L0) ALOAD (1) LDC (in) @@ -33,7 +33,7 @@ public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creat } public final class User : java/lang/Object, android/os/Parcelable { - public final static User$CREATOR CREATOR + public final static User$Creator CREATOR private final SerializableSimple notNull @@ -42,8 +42,8 @@ public final class User : java/lang/Object, android/os/Parcelable { static void () { NEW DUP - INVOKESPECIAL (User$CREATOR, , ()V) - PUTSTATIC (CREATOR, LUser$CREATOR;) + INVOKESPECIAL (User$Creator, , ()V) + PUTSTATIC (CREATOR, LUser$Creator;) RETURN } diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simple.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simple.txt index de7d18d0e67..5a31f8335a8 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simple.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simple.txt @@ -1,7 +1,7 @@ -public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class User$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final User createFromParcel(android.os.Parcel p0) { + public final java.lang.Object createFromParcel(android.os.Parcel p0) { LABEL (L0) ALOAD (1) LDC (in) @@ -25,7 +25,7 @@ public static class User$CREATOR : java/lang/Object, android/os/Parcelable$Creat } public final class User : java/lang/Object, android/os/Parcelable { - public final static User$CREATOR CREATOR + public final static User$Creator CREATOR private final int age @@ -38,8 +38,8 @@ public final class User : java/lang/Object, android/os/Parcelable { static void () { NEW DUP - INVOKESPECIAL (User$CREATOR, , ()V) - PUTSTATIC (CREATOR, LUser$CREATOR;) + INVOKESPECIAL (User$Creator, , ()V) + PUTSTATIC (CREATOR, LUser$Creator;) RETURN } diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simpleList.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simpleList.txt index 9cb608fc39d..152ac15976f 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simpleList.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/simpleList.txt @@ -1,13 +1,13 @@ -public static class Test$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class Test$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final Test createFromParcel(android.os.Parcel p0) + public final java.lang.Object createFromParcel(android.os.Parcel p0) public final Test[] newArray(int p0) } public final class Test : java/lang/Object { - public final static Test$CREATOR CREATOR + public final static Test$Creator CREATOR private final java.util.List names diff --git a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/size.txt b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/size.txt index 9db41d6f96e..5f4119a43df 100644 --- a/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/size.txt +++ b/plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/size.txt @@ -1,7 +1,7 @@ -public static class Test$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class Test$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final Test createFromParcel(android.os.Parcel p0) { + public final java.lang.Object createFromParcel(android.os.Parcel p0) { LABEL (L0) ALOAD (1) LDC (in) @@ -29,7 +29,7 @@ public static class Test$CREATOR : java/lang/Object, android/os/Parcelable$Creat } public final class Test : java/lang/Object, android/os/Parcelable { - public final static Test$CREATOR CREATOR + public final static Test$Creator CREATOR private final android.util.Size nullable @@ -88,10 +88,10 @@ public final class Test : java/lang/Object, android/os/Parcelable { } } -public static class TestF$CREATOR : java/lang/Object, android/os/Parcelable$Creator { +public static class TestF$Creator : java/lang/Object, android/os/Parcelable$Creator { public void () - public final TestF createFromParcel(android.os.Parcel p0) { + public final java.lang.Object createFromParcel(android.os.Parcel p0) { LABEL (L0) ALOAD (1) LDC (in) @@ -119,7 +119,7 @@ public static class TestF$CREATOR : java/lang/Object, android/os/Parcelable$Crea } public final class TestF : java/lang/Object, android/os/Parcelable { - public final static TestF$CREATOR CREATOR + public final static TestF$Creator CREATOR private final android.util.SizeF nullable diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/AbstractParcelBoxTest.kt b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/AbstractParcelBoxTest.kt index 4b18ac4945f..2ed68ec8ea7 100644 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/AbstractParcelBoxTest.kt +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/AbstractParcelBoxTest.kt @@ -43,10 +43,14 @@ abstract class AbstractParcelBoxTest : CodegenTestCase() { open protected fun getClassLoaderWithGeneratedFiles(): ClassLoader { return object : URLClassLoader(arrayOf(), this::class.java.classLoader) { init { - for (classFile in classFileFactory.getClassFiles()) { + for (classFile in classFileFactory.getClassFiles().sortedBy { it.relativePath }) { val bytes = classFile.asByteArray() val className = ClassNode().also { ClassReader(bytes).accept(it, ClassReader.EXPAND_FRAMES) }.name - defineClass(className.replace('/', '.'), ByteBuffer.wrap(bytes), null as ProtectionDomain?) + try { + defineClass(className.replace('/', '.'), ByteBuffer.wrap(bytes), null as ProtectionDomain?) + } catch (e: Throwable) { + throw RuntimeException("Can't load class $className", e) + } } } } diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBoxTest.kt b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBoxTest.kt index dc75da1b3dc..c4c53734b03 100644 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBoxTest.kt +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBoxTest.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.android.parcel -import android.os.Bundle import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -43,4 +42,8 @@ class ParcelBoxTest : AbstractParcelBoxTest() { @Test fun bundle() = doTest("bundle") @Test fun sparseArrays() = doTest("sparseArrays") @Test fun customSimple() = doTest("customSimple") + @Test fun charSequence() = doTest("charSequence") + @Test fun enums() = doTest("enums") + @Test fun objects() = doTest("objects") + @Test fun nestedParcelable() = doTest("nestedParcelable") } \ No newline at end of file diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBytecodeListingTestGenerated.java b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBytecodeListingTestGenerated.java index c62e168dc35..a893bf06ea1 100644 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBytecodeListingTestGenerated.java +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/parcel/ParcelBytecodeListingTestGenerated.java @@ -60,6 +60,12 @@ public class ParcelBytecodeListingTestGenerated extends AbstractParcelBytecodeLi doTest(fileName); } + @TestMetadata("IBinderIInterface.kt") + public void testIBinderIInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/IBinderIInterface.kt"); + doTest(fileName); + } + @TestMetadata("listInsideList.kt") public void testListInsideList() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/listInsideList.kt");