Fix Parcelize annotation implementing Parcelable.Creator<T>

This commit is contained in:
rbares
2020-04-11 20:15:35 +01:00
committed by Yan Zhulanow
parent 20793a65f4
commit 00ec50ff73
2 changed files with 40 additions and 13 deletions
@@ -77,7 +77,7 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg
} }
if (!hasCreatorField()) { if (!hasCreatorField()) {
writeCreatorAccessField(codegen) writeCreatorAccessField(codegen, parcelableClass)
} }
} }
@@ -85,7 +85,10 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg
val parcelClassType = ParcelableResolveExtension.resolveParcelClassType(parcelableClass.module) val parcelClassType = ParcelableResolveExtension.resolveParcelClassType(parcelableClass.module)
?: error("Can't resolve 'android.os.Parcel' class") ?: 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( private fun writeCreateFromParcel(
codegen: ImplementationBodyCodegen, codegen: ImplementationBodyCodegen,
parcelableClass: ClassDescriptor, parcelableClass: ClassDescriptor,
parcelableCreatorClassType: KotlinType,
creatorClass: ClassDescriptorImpl, creatorClass: ClassDescriptorImpl,
parcelClassType: KotlinType, parcelClassType: KotlinType,
parcelAsmType: Type, parcelAsmType: Type,
@@ -211,10 +215,12 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg
val containerAsmType = codegen.typeMapper.mapType(parcelableClass) val containerAsmType = codegen.typeMapper.mapType(parcelableClass)
val creatorAsmType = codegen.typeMapper.mapType(creatorClass) 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( createMethod(
creatorClass, CREATE_FROM_PARCEL, Modality.FINAL, creatorClass, CREATE_FROM_PARCEL, Modality.FINAL,
parcelableClass.builtIns.anyType, "in" to parcelClassType parcelableClass.defaultType, "in" to parcelClassType
).write(codegen) { ).write(codegen, overriddenFunction) {
if (parcelerObject != null) { if (parcelerObject != null) {
val (companionAsmType, companionFieldName) = getCompanionClassType(containerAsmType, parcelerObject) 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 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", 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( private fun writeCreatorClass(
codegen: ImplementationBodyCodegen, codegen: ImplementationBodyCodegen,
parcelableClass: ClassDescriptor, parcelableClass: ClassDescriptor,
parcelClassType: KotlinType, parcelClassType: KotlinType,
parcelableCreatorClassType: KotlinType,
parcelAsmType: Type, parcelAsmType: Type,
parcelerObject: ClassDescriptor?, parcelerObject: ClassDescriptor?,
properties: List<PropertyToSerialize> properties: List<PropertyToSerialize>
@@ -281,7 +290,7 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg
val creatorAsmType = Type.getObjectType(containerAsmType.internalName + "\$Creator") val creatorAsmType = Type.getObjectType(containerAsmType.internalName + "\$Creator")
val creatorClass = ClassDescriptorImpl( 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) parcelableClass.source, false, LockBasedStorageManager.NO_LOCKS)
creatorClass.initialize( creatorClass.initialize(
@@ -298,8 +307,9 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg
val codegenForCreator = ImplementationBodyCodegen( val codegenForCreator = ImplementationBodyCodegen(
codegen.myClass, classContextForCreator, classBuilderForCreator, codegen.state, codegen.parentCodegen, false) 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, 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")) arrayOf("android/os/Parcelable\$Creator"))
codegen.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC) 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) writeSyntheticClassMetadata(classBuilderForCreator, codegen.state)
writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType) writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType)
writeNewArrayMethod(codegenForCreator, parcelableClass, creatorClass, parcelerObject) writeNewArrayMethod(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelerObject)
writeCreateFromParcel(codegenForCreator, parcelableClass, creatorClass, parcelClassType, parcelAsmType, parcelerObject, properties) writeCreateFromParcel(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelClassType, parcelAsmType, parcelerObject, properties)
classBuilderForCreator.done() classBuilderForCreator.done()
} }
@@ -328,16 +338,19 @@ open class ParcelableCodegenExtension : ParcelableExtensionBase, ExpressionCodeg
private fun writeNewArrayMethod( private fun writeNewArrayMethod(
codegen: ImplementationBodyCodegen, codegen: ImplementationBodyCodegen,
parcelableClass: ClassDescriptor, parcelableClass: ClassDescriptor,
parcelableCreatorClassType: KotlinType,
creatorClass: ClassDescriptorImpl, creatorClass: ClassDescriptorImpl,
parcelerObject: ClassDescriptor? parcelerObject: ClassDescriptor?
) { ) {
val builtIns = parcelableClass.builtIns val builtIns = parcelableClass.builtIns
val parcelableAsmType = codegen.typeMapper.mapType(parcelableClass) 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, createMethod(creatorClass, NEW_ARRAY, Modality.FINAL,
builtIns.getArrayType(Variance.INVARIANT, builtIns.anyType), builtIns.getArrayType(Variance.INVARIANT, parcelableClass.defaultType),
"size" to builtIns.intType "size" to builtIns.intType
).write(codegen) { ).write(codegen, overriddenFunction) {
if (parcelerObject != null) { if (parcelerObject != null) {
val newArrayMethod = parcelerObject.unsubstitutedMemberScope val newArrayMethod = parcelerObject.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("newArray"), NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) .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) val declarationOrigin = JvmDeclarationOrigin(JvmDeclarationOriginKind.OTHER, null, this)
if (overriddenDescriptor != null) {
this.overriddenDescriptors = listOf(overriddenDescriptor)
}
codegen.functionCodegen.generateMethod(declarationOrigin, this, object : CodegenBased(codegen.state) { codegen.functionCodegen.generateMethod(declarationOrigin, this, object : CodegenBased(codegen.state) {
override fun doGenerateBody(e: ExpressionCodegen, signature: JvmMethodSignature) = with(e) { override fun doGenerateBody(e: ExpressionCodegen, signature: JvmMethodSignature) = with(e) {
e.code() 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<TypeParcelerMapping> { internal fun getTypeParcelers(annotations: Annotations): List<TypeParcelerMapping> {
@@ -44,6 +44,11 @@ open class ParcelableResolveExtension : SyntheticResolveExtension {
return module.findClassAcrossModuleDependencies(ClassId.topLevel(FqName("android.os.Parcel")))?.defaultType 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( fun createMethod(
classDescriptor: ClassDescriptor, classDescriptor: ClassDescriptor,
componentKind: ParcelableSyntheticComponent.ComponentKind, componentKind: ParcelableSyntheticComponent.ComponentKind,