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()) {
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<PropertyToSerialize>
@@ -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<TypeParcelerMapping> {
@@ -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,