Remove old JVM backend implementation of Parcelize
There's no way for the end user to use this implementation anymore, since old JVM backend cannot be enabled, and nothing else from Kotlin depends on it.
This commit is contained in:
+2
-1
@@ -2,7 +2,8 @@
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.addExtensionReceiver
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.psiElement
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isJvmInterface
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.RecordComponentVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class ParcelizeClinitClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
||||
override fun interceptClassBuilderFactory(
|
||||
interceptedFactory: ClassBuilderFactory,
|
||||
bindingContext: BindingContext,
|
||||
diagnostics: DiagnosticSink
|
||||
): ClassBuilderFactory {
|
||||
return ParcelableClinitClassBuilderFactory(interceptedFactory, bindingContext)
|
||||
}
|
||||
|
||||
private inner class ParcelableClinitClassBuilderFactory(
|
||||
private val delegateFactory: ClassBuilderFactory,
|
||||
val bindingContext: BindingContext
|
||||
) : ClassBuilderFactory {
|
||||
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder {
|
||||
return AndroidOnDestroyCollectorClassBuilder(origin, delegateFactory.newClassBuilder(origin), bindingContext)
|
||||
}
|
||||
|
||||
override fun getClassBuilderMode() = delegateFactory.classBuilderMode
|
||||
|
||||
override fun asText(builder: ClassBuilder?): String? {
|
||||
return delegateFactory.asText((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun asBytes(builder: ClassBuilder?): ByteArray? {
|
||||
return delegateFactory.asBytes((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
delegateFactory.close()
|
||||
}
|
||||
}
|
||||
|
||||
private class AndroidOnDestroyCollectorClassBuilder(
|
||||
val declarationOrigin: JvmDeclarationOrigin,
|
||||
val delegateClassBuilder: ClassBuilder,
|
||||
val bindingContext: BindingContext
|
||||
) : DelegatingClassBuilder() {
|
||||
private var currentClass: KtClassOrObject? = null
|
||||
private var currentClassName: String? = null
|
||||
private var isClinitGenerated = false
|
||||
|
||||
override fun getDelegate() = delegateClassBuilder
|
||||
|
||||
override fun defineClass(
|
||||
origin: PsiElement?,
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String,
|
||||
interfaces: Array<out String>
|
||||
) {
|
||||
currentClass = origin as? KtClassOrObject
|
||||
currentClassName = name
|
||||
isClinitGenerated = false
|
||||
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
override fun done(generateSmapCopyToAnnotation: Boolean) {
|
||||
if (!isClinitGenerated && currentClass != null && currentClassName != null) {
|
||||
val descriptor = bindingContext[BindingContext.CLASS, currentClass]
|
||||
if (descriptor != null && declarationOrigin.descriptor == descriptor && descriptor.isParcelize) {
|
||||
val baseVisitor = super.newMethod(JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_STATIC, "<clinit>", "()V", null, null)
|
||||
val visitor = ClinitAwareMethodVisitor(currentClassName!!, baseVisitor)
|
||||
|
||||
visitor.visitCode()
|
||||
visitor.visitInsn(Opcodes.RETURN)
|
||||
visitor.visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
super.done(generateSmapCopyToAnnotation)
|
||||
}
|
||||
|
||||
override fun newMethod(
|
||||
origin: JvmDeclarationOrigin,
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
if (name == "<clinit>" && currentClass != null && currentClassName != null) {
|
||||
isClinitGenerated = true
|
||||
|
||||
val descriptor = bindingContext[BindingContext.CLASS, currentClass]
|
||||
if (descriptor != null && declarationOrigin.descriptor == descriptor && descriptor.isParcelize) {
|
||||
return ClinitAwareMethodVisitor(
|
||||
currentClassName!!,
|
||||
super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
|
||||
override fun newRecordComponent(name: String, desc: String, signature: String?): RecordComponentVisitor {
|
||||
return AbstractClassBuilder.EMPTY_RECORD_VISITOR
|
||||
}
|
||||
}
|
||||
|
||||
private class ClinitAwareMethodVisitor(val parcelableName: String, mv: MethodVisitor) : MethodVisitor(Opcodes.API_VERSION, mv) {
|
||||
override fun visitInsn(opcode: Int) {
|
||||
if (opcode == Opcodes.RETURN) {
|
||||
val iv = InstructionAdapter(this)
|
||||
val creatorName = "$parcelableName\$Creator"
|
||||
val creatorType = Type.getObjectType(creatorName)
|
||||
|
||||
iv.anew(creatorType)
|
||||
iv.dup()
|
||||
iv.invokespecial(creatorName, "<init>", "()V", false)
|
||||
iv.putstatic(parcelableName, "CREATOR", "Landroid/os/Parcelable\$Creator;")
|
||||
}
|
||||
|
||||
super.visitInsn(opcode)
|
||||
}
|
||||
}
|
||||
}
|
||||
-426
@@ -1,426 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy.CodegenBased
|
||||
import org.jetbrains.kotlin.codegen.context.ClassContext
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeResolveExtension.Companion.createMethod
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.*
|
||||
import org.jetbrains.kotlin.parcelize.serializers.*
|
||||
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase.Companion.FILE_DESCRIPTOR_FQNAME
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
open class ParcelizeCodegenExtension : ParcelizeExtensionBase, ExpressionCodegenExtension {
|
||||
open fun isAvailable(element: PsiElement): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override val shouldGenerateClassSyntheticPartsInLightClassesMode: Boolean
|
||||
get() = true
|
||||
|
||||
override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {
|
||||
val declaration = codegen.myClass as? PsiElement ?: return
|
||||
if (!isAvailable(declaration)) {
|
||||
return
|
||||
}
|
||||
|
||||
val parcelableClass = codegen.descriptor
|
||||
if (!parcelableClass.isParcelizeClassDescriptor) {
|
||||
return
|
||||
}
|
||||
|
||||
val propertiesToSerialize = getPropertiesToSerialize(codegen, parcelableClass)
|
||||
|
||||
val parcelerObject = parcelableClass.companionObjectDescriptor?.takeIf {
|
||||
TypeUtils.getAllSupertypes(it.defaultType).any { supertype -> supertype.isParceler }
|
||||
}
|
||||
|
||||
with(parcelableClass) {
|
||||
if (hasSyntheticDescribeContents()) {
|
||||
writeDescribeContentsFunction(codegen, propertiesToSerialize)
|
||||
}
|
||||
|
||||
if (hasSyntheticWriteToParcel()) {
|
||||
writeWriteToParcel(codegen, propertiesToSerialize, PARCEL_TYPE, parcelerObject)
|
||||
}
|
||||
|
||||
if (!hasCreatorField()) {
|
||||
writeCreatorAccessField(codegen, parcelableClass)
|
||||
}
|
||||
}
|
||||
|
||||
if (codegen.state.classBuilderMode != ClassBuilderMode.LIGHT_CLASSES) {
|
||||
val parcelClassType = ParcelizeResolveExtension.resolveParcelClassType(parcelableClass.module)
|
||||
?: error("Can't resolve 'android.os.Parcel' class")
|
||||
|
||||
val parcelableCreatorClassType = ParcelizeResolveExtension.resolveParcelableCreatorClassType(parcelableClass.module)
|
||||
?: error("Can't resolve 'android.os.Parcelable.Creator' class")
|
||||
|
||||
writeCreatorClass(
|
||||
codegen,
|
||||
parcelableClass, parcelClassType, parcelableCreatorClassType,
|
||||
PARCEL_TYPE, parcelerObject, propertiesToSerialize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCompanionClassType(containerAsmType: Type, parcelerObject: ClassDescriptor): Pair<Type, String> {
|
||||
val shortName = parcelerObject.name
|
||||
return Pair(Type.getObjectType(containerAsmType.internalName + "\$$shortName"), shortName.asString())
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.writeWriteToParcel(
|
||||
codegen: ImplementationBodyCodegen,
|
||||
properties: List<PropertyToSerialize>,
|
||||
parcelAsmType: Type,
|
||||
parcelerObject: ClassDescriptor?
|
||||
): Unit? {
|
||||
val containerAsmType = codegen.typeMapper.mapType(this.defaultType)
|
||||
|
||||
return findFunction(WRITE_TO_PARCEL)?.write(codegen) {
|
||||
if (parcelerObject != null) {
|
||||
val (companionAsmType, companionFieldName) = getCompanionClassType(containerAsmType, parcelerObject)
|
||||
|
||||
v.getstatic(containerAsmType.internalName, companionFieldName, companionAsmType.descriptor)
|
||||
v.load(0, containerAsmType)
|
||||
v.load(1, PARCEL_TYPE)
|
||||
v.load(2, Type.INT_TYPE)
|
||||
v.invokevirtual(
|
||||
companionAsmType.internalName, "write",
|
||||
"(${containerAsmType.descriptor}${PARCEL_TYPE.descriptor}I)V", false
|
||||
)
|
||||
} else {
|
||||
val frameMap = FrameMap().apply {
|
||||
enterTemp(containerAsmType)
|
||||
enterTemp(PARCEL_TYPE)
|
||||
enterTemp(Type.INT_TYPE)
|
||||
}
|
||||
|
||||
val globalContext = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType, emptyList(), frameMap)
|
||||
|
||||
if (properties.isEmpty()) {
|
||||
val entityType = this@writeWriteToParcel.defaultType
|
||||
val asmType = codegen.state.typeMapper.mapType(entityType)
|
||||
val serializer = if (this@writeWriteToParcel.kind == ClassKind.CLASS) {
|
||||
NullAwareParcelSerializerWrapper(ZeroParameterClassSerializer(asmType, entityType))
|
||||
} else {
|
||||
ParcelSerializer.get(entityType, asmType, globalContext, strict = true)
|
||||
}
|
||||
|
||||
v.load(1, parcelAsmType)
|
||||
v.load(0, containerAsmType)
|
||||
serializer.writeValue(v)
|
||||
} else {
|
||||
for ((fieldName, type, parcelers) in properties) {
|
||||
val asmType = codegen.typeMapper.mapType(type)
|
||||
|
||||
v.load(1, parcelAsmType)
|
||||
v.load(0, containerAsmType)
|
||||
v.getfield(containerAsmType.internalName, fieldName, asmType.descriptor)
|
||||
|
||||
val serializer = ParcelSerializer.get(type, asmType, globalContext.copy(typeParcelers = parcelers))
|
||||
serializer.writeValue(v)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
v.areturn(Type.VOID_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.writeDescribeContentsFunction(
|
||||
codegen: ImplementationBodyCodegen,
|
||||
propertiesToSerialize: List<PropertyToSerialize>
|
||||
): Unit? {
|
||||
val hasFileDescriptorAnywhere = propertiesToSerialize.any { it.type.containsFileDescriptor() }
|
||||
|
||||
return findFunction(DESCRIBE_CONTENTS)?.write(codegen) {
|
||||
v.aconst(if (hasFileDescriptorAnywhere) 1 /* CONTENTS_FILE_DESCRIPTOR */ else 0)
|
||||
v.areturn(Type.INT_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.containsFileDescriptor(): Boolean {
|
||||
val declarationDescriptor = this.constructor.declarationDescriptor
|
||||
if (declarationDescriptor != null) {
|
||||
if (declarationDescriptor.fqNameSafe == FILE_DESCRIPTOR_FQNAME) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return this.arguments.any { it.type.containsFileDescriptor() }
|
||||
}
|
||||
|
||||
data class PropertyToSerialize(val name: String, val type: KotlinType, val parcelers: List<TypeParcelerMapping>)
|
||||
|
||||
private fun getPropertiesToSerialize(
|
||||
codegen: ImplementationBodyCodegen,
|
||||
parcelableClass: ClassDescriptor
|
||||
): List<PropertyToSerialize> {
|
||||
if (parcelableClass.kind != ClassKind.CLASS) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val constructor = parcelableClass.constructors.firstOrNull { it.isPrimary } ?: return emptyList()
|
||||
|
||||
val propertiesToSerialize = constructor.valueParameters.mapNotNull { param ->
|
||||
codegen.bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, param]
|
||||
}
|
||||
|
||||
val classParcelers = getTypeParcelers(parcelableClass.annotations)
|
||||
|
||||
return propertiesToSerialize.map {
|
||||
PropertyToSerialize(it.name.asString(), it.type, classParcelers + getTypeParcelers(it.annotations))
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeCreateFromParcel(
|
||||
codegen: ImplementationBodyCodegen,
|
||||
parcelableClass: ClassDescriptor,
|
||||
parcelableCreatorClassType: KotlinType,
|
||||
creatorClass: ClassDescriptorImpl,
|
||||
parcelClassType: KotlinType,
|
||||
parcelAsmType: Type,
|
||||
parcelerObject: ClassDescriptor?,
|
||||
properties: List<PropertyToSerialize>
|
||||
) {
|
||||
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.defaultType.replaceArgumentsWithStarProjections(), "in" to parcelClassType
|
||||
).write(codegen, overriddenFunction) {
|
||||
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", false)
|
||||
} else {
|
||||
v.anew(containerAsmType)
|
||||
v.dup()
|
||||
|
||||
val asmConstructorParameters = StringBuilder()
|
||||
val frameMap = FrameMap().apply {
|
||||
enterTemp(creatorAsmType)
|
||||
enterTemp(PARCEL_TYPE)
|
||||
}
|
||||
|
||||
val globalContext = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType, emptyList(), frameMap)
|
||||
|
||||
if (properties.isEmpty()) {
|
||||
val entityType = parcelableClass.defaultType
|
||||
val asmType = codegen.state.typeMapper.mapType(entityType)
|
||||
val serializer = if (parcelableClass.kind == ClassKind.CLASS) {
|
||||
NullAwareParcelSerializerWrapper(ZeroParameterClassSerializer(asmType, entityType))
|
||||
} else {
|
||||
ParcelSerializer.get(entityType, asmType, globalContext, strict = true)
|
||||
}
|
||||
v.load(1, parcelAsmType)
|
||||
serializer.readValue(v)
|
||||
} else {
|
||||
for ((_, type, parcelers) in properties) {
|
||||
val asmType = codegen.typeMapper.mapType(type)
|
||||
asmConstructorParameters.append(asmType.descriptor)
|
||||
|
||||
val serializer = ParcelSerializer.get(type, asmType, globalContext.copy(typeParcelers = parcelers))
|
||||
v.load(1, parcelAsmType)
|
||||
serializer.readValue(v)
|
||||
}
|
||||
|
||||
v.invokespecial(containerAsmType.internalName, "<init>", "($asmConstructorParameters)V", false)
|
||||
}
|
||||
}
|
||||
|
||||
v.areturn(containerAsmType)
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
fieldSignature,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private fun writeCreatorClass(
|
||||
codegen: ImplementationBodyCodegen,
|
||||
parcelableClass: ClassDescriptor,
|
||||
parcelClassType: KotlinType,
|
||||
parcelableCreatorClassType: KotlinType,
|
||||
parcelAsmType: Type,
|
||||
parcelerObject: ClassDescriptor?,
|
||||
properties: List<PropertyToSerialize>
|
||||
) {
|
||||
val containerAsmType = codegen.typeMapper.mapType(parcelableClass.defaultType)
|
||||
val creatorAsmType = Type.getObjectType(containerAsmType.internalName + "\$Creator")
|
||||
|
||||
val creatorClass = ClassDescriptorImpl(
|
||||
parcelableClass, Name.identifier("Creator"), Modality.FINAL, ClassKind.CLASS, listOf(parcelableCreatorClassType),
|
||||
parcelableClass.source, false, LockBasedStorageManager.NO_LOCKS
|
||||
)
|
||||
|
||||
creatorClass.initialize(
|
||||
MemberScope.Empty, emptySet(),
|
||||
DescriptorFactory.createPrimaryConstructorForObject(creatorClass, creatorClass.source)
|
||||
)
|
||||
|
||||
val classBuilderForCreator = codegen.state.factory.newVisitor(
|
||||
JvmDeclarationOrigin(JvmDeclarationOriginKind.OTHER, null, creatorClass),
|
||||
Type.getObjectType(creatorAsmType.internalName),
|
||||
codegen.myClass.containingKtFile
|
||||
)
|
||||
|
||||
val classContextForCreator = ClassContext(
|
||||
codegen.typeMapper, creatorClass, OwnerKind.IMPLEMENTATION, codegen.context.parentContext, null
|
||||
)
|
||||
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, classSignature, "java/lang/Object",
|
||||
arrayOf("android/os/Parcelable\$Creator")
|
||||
)
|
||||
|
||||
codegen.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC)
|
||||
codegenForCreator.v.visitInnerClass(creatorAsmType.internalName, containerAsmType.internalName, "Creator", ACC_PUBLIC or ACC_STATIC)
|
||||
|
||||
writeSyntheticClassMetadata(classBuilderForCreator, codegen.state, InlineUtil.isInPublicInlineScope(parcelableClass))
|
||||
|
||||
writeCreatorConstructor(codegenForCreator, creatorClass, creatorAsmType)
|
||||
writeNewArrayMethod(codegenForCreator, parcelableClass, parcelableCreatorClassType, creatorClass, parcelerObject)
|
||||
|
||||
writeCreateFromParcel(
|
||||
codegenForCreator,
|
||||
parcelableClass, parcelableCreatorClassType, creatorClass, parcelClassType,
|
||||
parcelAsmType, parcelerObject, properties
|
||||
)
|
||||
|
||||
classBuilderForCreator.done(codegen.state.generateSmapCopyToAnnotation)
|
||||
}
|
||||
|
||||
private fun writeCreatorConstructor(codegen: ImplementationBodyCodegen, creatorClass: ClassDescriptor, creatorAsmType: Type) {
|
||||
DescriptorFactory.createPrimaryConstructorForObject(creatorClass, creatorClass.source)
|
||||
.apply {
|
||||
returnType = creatorClass.defaultType
|
||||
}.write(codegen) {
|
||||
v.load(0, creatorAsmType)
|
||||
v.invokespecial("java/lang/Object", "<init>", "()V", false)
|
||||
v.areturn(Type.VOID_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
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, parcelableClass.defaultType.replaceArgumentsWithStarProjections()),
|
||||
"size" to builtIns.intType
|
||||
).write(codegen, overriddenFunction) {
|
||||
if (parcelerObject != null) {
|
||||
val newArrayMethod = parcelerObject.unsubstitutedMemberScope
|
||||
.getContributedFunctions(NEW_ARRAY_NAME, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS)
|
||||
.firstOrNull {
|
||||
it.typeParameters.isEmpty()
|
||||
&& it.kind == CallableMemberDescriptor.Kind.DECLARATION
|
||||
&& (it.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.valueParameters[0].type))
|
||||
&& !((it.containingDeclaration as? ClassDescriptor)?.defaultType?.isParceler ?: true)
|
||||
}
|
||||
|
||||
if (newArrayMethod != null) {
|
||||
val containerAsmType = codegen.typeMapper.mapType(parcelableClass.defaultType)
|
||||
val (companionAsmType, companionFieldName) = getCompanionClassType(containerAsmType, parcelerObject)
|
||||
|
||||
v.getstatic(containerAsmType.internalName, companionFieldName, companionAsmType.descriptor)
|
||||
v.load(1, Type.INT_TYPE)
|
||||
v.invokevirtual(companionAsmType.internalName, "newArray", "(I)[$parcelableAsmType", false)
|
||||
v.areturn(Type.getType("[$parcelableAsmType"))
|
||||
|
||||
return@write
|
||||
}
|
||||
}
|
||||
|
||||
v.load(1, Type.INT_TYPE)
|
||||
v.newarray(parcelableAsmType)
|
||||
v.areturn(Type.getType("[$parcelableAsmType"))
|
||||
}
|
||||
}
|
||||
|
||||
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: ParcelizeSyntheticComponent.ComponentKind): SimpleFunctionDescriptor? {
|
||||
return memberScope
|
||||
.getContributedFunctions(Name.identifier(componentKind.methodName), NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS)
|
||||
.firstOrNull()
|
||||
}
|
||||
}
|
||||
-2
@@ -8,8 +8,6 @@ package org.jetbrains.kotlin.parcelize
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.parcelize.ir.AndroidSymbols
|
||||
import org.jetbrains.kotlin.parcelize.ir.ParcelizeFirIrTransformer
|
||||
|
||||
class ParcelizeFirIrGeneratorExtension : IrGenerationExtension {
|
||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||
|
||||
+1
-2
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.util.companionObject
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent
|
||||
import org.jetbrains.kotlin.parcelize.fir.ParcelizePluginKey
|
||||
|
||||
class ParcelizeFirIrTransformer(
|
||||
-3
@@ -8,8 +8,6 @@ package org.jetbrains.kotlin.parcelize
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.parcelize.ir.AndroidSymbols
|
||||
import org.jetbrains.kotlin.parcelize.ir.ParcelizeIrTransformer
|
||||
|
||||
class ParcelizeIrGeneratorExtension : IrGenerationExtension {
|
||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||
@@ -17,4 +15,3 @@ class ParcelizeIrGeneratorExtension : IrGenerationExtension {
|
||||
ParcelizeIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.parcelize.ParcelizeNames.FLAGS_NAME
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class ParcelizeIrTransformer(
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.parcelize.ir
|
||||
package org.jetbrains.kotlin.parcelize
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
Reference in New Issue
Block a user