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 f8a38d4a334..87eb5c20edf 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 @@ -77,7 +77,7 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg } if (!hasCreatorField()) { - writeCreatorAccessField(codegen) + writeCreatorAccessField(codegen, parcelableClass) } } @@ -85,7 +85,10 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg val parcelClassType = ParcelableResolveExtension.resolveParcelClassType(parcelableClass.module) ?: error("Can't resolve 'android.os.Parcel' class") - writeCreatorClass(codegen, parcelableClass, parcelClassType, PARCEL_TYPE, parcelerObject, propertiesToSerialize) + val parcelableCreatorClassType = ParcelableResolveExtension.resolveParcelableCreatorClassType(parcelableClass.module) + ?: error("Can't resolve 'android.os.Parcelable.Creator' class") + + writeCreatorClass(codegen, parcelableClass, parcelClassType, parcelableCreatorClassType, PARCEL_TYPE, parcelerObject, propertiesToSerialize) } } @@ -202,6 +205,7 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg private fun writeCreateFromParcel( codegen: ImplementationBodyCodegen, parcelableClass: ClassDescriptor, + parcelableCreatorClassType: KotlinType, creatorClass: ClassDescriptorImpl, parcelClassType: KotlinType, parcelAsmType: Type, @@ -211,10 +215,12 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg val containerAsmType = codegen.typeMapper.mapType(parcelableClass) val creatorAsmType = codegen.typeMapper.mapType(creatorClass) + val overriddenFunction = parcelableCreatorClassType.findFunction(CREATE_FROM_PARCEL) + ?: error("Can't resolve 'android.os.Parcelable.Creator.${CREATE_FROM_PARCEL.methodName}' method") createMethod( creatorClass, CREATE_FROM_PARCEL, Modality.FINAL, - parcelableClass.builtIns.anyType, "in" to parcelClassType - ).write(codegen) { + parcelableClass.defaultType, "in" to parcelClassType + ).write(codegen, overriddenFunction) { if (parcelerObject != null) { val (companionAsmType, companionFieldName) = getCompanionClassType(containerAsmType, parcelerObject) @@ -262,17 +268,20 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg } } - private fun writeCreatorAccessField(codegen: ImplementationBodyCodegen) { + private fun writeCreatorAccessField(codegen: ImplementationBodyCodegen, parcelableClass: ClassDescriptor) { val creatorType = Type.getObjectType("android/os/Parcelable\$Creator") + val parcelableType = codegen.typeMapper.mapType(parcelableClass) + val fieldSignature = "L${creatorType.internalName}<${parcelableType.descriptor}>;" codegen.v.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_STATIC or ACC_PUBLIC or ACC_FINAL, "CREATOR", - creatorType.descriptor, null, null) + creatorType.descriptor, fieldSignature, null) } private fun writeCreatorClass( codegen: ImplementationBodyCodegen, parcelableClass: ClassDescriptor, parcelClassType: KotlinType, + parcelableCreatorClassType: KotlinType, parcelAsmType: Type, parcelerObject: ClassDescriptor?, properties: List @@ -281,7 +290,7 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg val creatorAsmType = Type.getObjectType(containerAsmType.internalName + "\$Creator") val creatorClass = ClassDescriptorImpl( - parcelableClass, Name.identifier("Creator"), Modality.FINAL, ClassKind.CLASS, emptyList(), + parcelableClass, Name.identifier("Creator"), Modality.FINAL, ClassKind.CLASS, listOf(parcelableCreatorClassType), parcelableClass.source, false, LockBasedStorageManager.NO_LOCKS) creatorClass.initialize( @@ -298,8 +307,9 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg val codegenForCreator = ImplementationBodyCodegen( codegen.myClass, classContextForCreator, classBuilderForCreator, codegen.state, codegen.parentCodegen, false) + val classSignature = "Ljava/lang/Object;Landroid/os/Parcelable\$Creator<${containerAsmType.descriptor}>;" classBuilderForCreator.defineClass(null, V1_6, ACC_PUBLIC or ACC_FINAL or ACC_SUPER, - creatorAsmType.internalName, null, "java/lang/Object", + creatorAsmType.internalName, classSignature, "java/lang/Object", arrayOf("android/os/Parcelable\$Creator")) codegen.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC) @@ -308,8 +318,8 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg writeSyntheticClassMetadata(classBuilderForCreator, codegen.state) writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType) - writeNewArrayMethod(codegenForCreator, parcelableClass, creatorClass, parcelerObject) - writeCreateFromParcel(codegenForCreator, parcelableClass, creatorClass, parcelClassType, parcelAsmType, parcelerObject, properties) + writeNewArrayMethod(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelerObject) + writeCreateFromParcel(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelClassType, parcelAsmType, parcelerObject, properties) classBuilderForCreator.done() } @@ -328,16 +338,19 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg private fun writeNewArrayMethod( codegen: ImplementationBodyCodegen, parcelableClass: ClassDescriptor, + parcelableCreatorClassType: KotlinType, creatorClass: ClassDescriptorImpl, parcelerObject: ClassDescriptor? ) { val builtIns = parcelableClass.builtIns val parcelableAsmType = codegen.typeMapper.mapType(parcelableClass) + val overriddenFunction = parcelableCreatorClassType.findFunction(NEW_ARRAY) + ?: error("Can't resolve 'android.os.Parcelable.Creator.${NEW_ARRAY.methodName}' method") createMethod(creatorClass, NEW_ARRAY, Modality.FINAL, - builtIns.getArrayType(Variance.INVARIANT, builtIns.anyType), + builtIns.getArrayType(Variance.INVARIANT, parcelableClass.defaultType), "size" to builtIns.intType - ).write(codegen) { + ).write(codegen, overriddenFunction) { if (parcelerObject != null) { val newArrayMethod = parcelerObject.unsubstitutedMemberScope .getContributedFunctions(Name.identifier("newArray"), NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) @@ -367,14 +380,23 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg } } - private fun FunctionDescriptor.write(codegen: ImplementationBodyCodegen, code: ExpressionCodegen.() -> Unit) { + private fun FunctionDescriptor.write(codegen: ImplementationBodyCodegen, overriddenDescriptor: FunctionDescriptor? = null, code: ExpressionCodegen.() -> Unit) { val declarationOrigin = JvmDeclarationOrigin(JvmDeclarationOriginKind.OTHER, null, this) + if (overriddenDescriptor != null) { + this.overriddenDescriptors = listOf(overriddenDescriptor) + } codegen.functionCodegen.generateMethod(declarationOrigin, this, object : CodegenBased(codegen.state) { override fun doGenerateBody(e: ExpressionCodegen, signature: JvmMethodSignature) = with(e) { e.code() } }) } + + private fun KotlinType.findFunction(componentKind: ParcelableSyntheticComponent.ComponentKind): SimpleFunctionDescriptor? { + return memberScope + .getContributedFunctions(Name.identifier(componentKind.methodName), NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) + .firstOrNull() + } } internal fun getTypeParcelers(annotations: Annotations): List { diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableResolveExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableResolveExtension.kt index df68bcc55dd..81c6c662ace 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableResolveExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/parcel/ParcelableResolveExtension.kt @@ -44,6 +44,11 @@ open class ParcelableResolveExtension : SyntheticResolveExtension { return module.findClassAcrossModuleDependencies(ClassId.topLevel(FqName("android.os.Parcel")))?.defaultType } + fun resolveParcelableCreatorClassType(module: ModuleDescriptor): SimpleType? { + val creatorClassId = ClassId(FqName("android.os"), FqName("Parcelable.Creator"), false) + return module.findClassAcrossModuleDependencies(creatorClassId)?.defaultType + } + fun createMethod( classDescriptor: ClassDescriptor, componentKind: ParcelableSyntheticComponent.ComponentKind,