Parcelize: Avoid KotlinTypeMapper in ParcelizeDeclarationChecker
This commit is contained in:
+101
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of builtin Parcelable types.
|
||||||
|
*
|
||||||
|
* The Parcelize plugin has direct support for serializing all types in `PARCELABLE_BASE_TYPE_FQNAMES`,
|
||||||
|
* as well as the container types in `PARCELABLE_CONTAINER_FQNAMES` whenever all element types can be serialized.
|
||||||
|
*
|
||||||
|
* Apart from that, Parcelize can serialize all types with supertypes in `PARCELABLE_SUPERTYPE_FQNAMES` through
|
||||||
|
* reflection, as well as all objects, enums, and function types (since they are implicitly serializable).
|
||||||
|
*/
|
||||||
|
object BuiltinParcelableTypes {
|
||||||
|
val PARCELABLE_SUPERTYPE_FQNAMES = setOf(
|
||||||
|
"android.os.Parcelable",
|
||||||
|
"android.os.IBinder",
|
||||||
|
"java.io.Serializable"
|
||||||
|
)
|
||||||
|
|
||||||
|
val PARCELABLE_BASE_TYPE_FQNAMES = setOf(
|
||||||
|
"android.os.Bundle",
|
||||||
|
"android.os.PersistableBundle",
|
||||||
|
"android.util.Size",
|
||||||
|
"android.util.SizeF",
|
||||||
|
"android.util.SparseBooleanArray",
|
||||||
|
"android.util.SparseIntArray",
|
||||||
|
"android.util.SparseLongArray",
|
||||||
|
"java.io.FileDescriptor",
|
||||||
|
"java.lang.Boolean",
|
||||||
|
"java.lang.Byte",
|
||||||
|
"java.lang.CharSequence",
|
||||||
|
"java.lang.Character",
|
||||||
|
"java.lang.Double",
|
||||||
|
"java.lang.Float",
|
||||||
|
"java.lang.Integer",
|
||||||
|
"java.lang.Long",
|
||||||
|
"java.lang.Short",
|
||||||
|
"java.lang.String",
|
||||||
|
"kotlin.Boolean",
|
||||||
|
"kotlin.BooleanArray",
|
||||||
|
"kotlin.Byte",
|
||||||
|
"kotlin.ByteArray",
|
||||||
|
"kotlin.Char",
|
||||||
|
"kotlin.CharArray",
|
||||||
|
"kotlin.CharSequence",
|
||||||
|
"kotlin.Double",
|
||||||
|
"kotlin.DoubleArray",
|
||||||
|
"kotlin.Float",
|
||||||
|
"kotlin.FloatArray",
|
||||||
|
"kotlin.Int",
|
||||||
|
"kotlin.IntArray",
|
||||||
|
"kotlin.Long",
|
||||||
|
"kotlin.LongArray",
|
||||||
|
"kotlin.Short",
|
||||||
|
"kotlin.String",
|
||||||
|
"kotlin.UByte",
|
||||||
|
"kotlin.UByteArray",
|
||||||
|
"kotlin.UInt",
|
||||||
|
"kotlin.UIntArray",
|
||||||
|
"kotlin.ULong",
|
||||||
|
"kotlin.ULongArray",
|
||||||
|
"kotlin.UShort",
|
||||||
|
"kotlin.UShortArray",
|
||||||
|
) + PARCELABLE_SUPERTYPE_FQNAMES
|
||||||
|
|
||||||
|
val PARCELABLE_CONTAINER_FQNAMES = setOf(
|
||||||
|
"android.util.SparseArray",
|
||||||
|
"java.util.ArrayDeque",
|
||||||
|
"java.util.ArrayList",
|
||||||
|
"java.util.HashMap",
|
||||||
|
"java.util.HashSet",
|
||||||
|
"java.util.LinkedHashMap",
|
||||||
|
"java.util.LinkedHashSet",
|
||||||
|
"java.util.List",
|
||||||
|
"java.util.Map",
|
||||||
|
"java.util.NavigableMap",
|
||||||
|
"java.util.NavigableSet",
|
||||||
|
"java.util.Set",
|
||||||
|
"java.util.SortedMap",
|
||||||
|
"java.util.SortedSet",
|
||||||
|
"java.util.TreeMap",
|
||||||
|
"java.util.concurrent.ConcurrentHashMap",
|
||||||
|
"kotlin.Array",
|
||||||
|
"kotlin.collections.ArrayDeque",
|
||||||
|
"kotlin.collections.ArrayList",
|
||||||
|
"kotlin.collections.HashMap",
|
||||||
|
"kotlin.collections.HashSet",
|
||||||
|
"kotlin.collections.LinkedHashMap",
|
||||||
|
"kotlin.collections.LinkedHashSet",
|
||||||
|
"kotlin.collections.List",
|
||||||
|
"kotlin.collections.Map",
|
||||||
|
"kotlin.collections.MutableList",
|
||||||
|
"kotlin.collections.MutableMap",
|
||||||
|
"kotlin.collections.MutableSet",
|
||||||
|
"kotlin.collections.Set",
|
||||||
|
)
|
||||||
|
}
|
||||||
+49
-17
@@ -5,21 +5,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.parcelize
|
package org.jetbrains.kotlin.parcelize
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||||
import org.jetbrains.kotlin.codegen.FrameMap
|
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_FQN
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_FQN
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
|
||||||
import org.jetbrains.kotlin.parcelize.diagnostic.ErrorsParcelize
|
import org.jetbrains.kotlin.parcelize.diagnostic.ErrorsParcelize
|
||||||
import org.jetbrains.kotlin.parcelize.serializers.ParcelSerializer
|
|
||||||
import org.jetbrains.kotlin.parcelize.serializers.isParcelable
|
import org.jetbrains.kotlin.parcelize.serializers.isParcelable
|
||||||
|
import org.jetbrains.kotlin.parcelize.serializers.matchesFqNameWithSupertypes
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||||
@@ -27,9 +26,12 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
|
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmFieldAnnotation
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.isError
|
import org.jetbrains.kotlin.types.isError
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
open class ParcelizeDeclarationChecker : DeclarationChecker {
|
open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||||
private companion object {
|
private companion object {
|
||||||
@@ -239,28 +241,58 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val type = descriptor.type
|
val type = descriptor.type
|
||||||
|
|
||||||
if (!type.isError) {
|
if (!type.isError) {
|
||||||
val asmType = typeMapper.mapType(type, mode = TypeMappingMode.CLASS_DECLARATION)
|
val customParcelerTypes =
|
||||||
|
(getTypeParcelers(descriptor.annotations) + getTypeParcelers(containerClass.annotations)).map { (mappedType, _) ->
|
||||||
|
mappedType
|
||||||
|
}.toSet()
|
||||||
|
|
||||||
try {
|
if (!checkParcelableType(type, customParcelerTypes)) {
|
||||||
val parcelers = getTypeParcelers(descriptor.annotations) + getTypeParcelers(containerClass.annotations)
|
|
||||||
val context = ParcelSerializer.ParcelSerializerContext(
|
|
||||||
typeMapper,
|
|
||||||
typeMapper.mapClass(containerClass),
|
|
||||||
parcelers,
|
|
||||||
FrameMap()
|
|
||||||
)
|
|
||||||
|
|
||||||
ParcelSerializer.get(type, asmType, context, strict = true)
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
// get() throws IllegalArgumentException on unknown types
|
|
||||||
val reportElement = parameter.typeReference ?: parameter.nameIdentifier ?: parameter
|
val reportElement = parameter.typeReference ?: parameter.nameIdentifier ?: parameter
|
||||||
diagnosticHolder.report(ErrorsParcelize.PARCELABLE_TYPE_NOT_SUPPORTED.on(reportElement))
|
diagnosticHolder.report(ErrorsParcelize.PARCELABLE_TYPE_NOT_SUPPORTED.on(reportElement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkParcelableType(type: KotlinType, customParcelerTypes: Set<KotlinType>): Boolean {
|
||||||
|
if (type.hasAnyAnnotation(ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES)
|
||||||
|
|| type.hasAnyAnnotation(ParcelizeNames.WRITE_WITH_FQ_NAMES)
|
||||||
|
|| type in customParcelerTypes) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val upperBound = type.getErasedUpperBound()
|
||||||
|
val descriptor = upperBound.constructor.declarationDescriptor as? ClassDescriptor
|
||||||
|
?: return false
|
||||||
|
|
||||||
|
if (descriptor.kind.isSingleton || descriptor.kind.isEnumClass) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val fqName = descriptor.fqNameSafe.asString()
|
||||||
|
if (fqName in BuiltinParcelableTypes.PARCELABLE_BASE_TYPE_FQNAMES) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fqName in BuiltinParcelableTypes.PARCELABLE_CONTAINER_FQNAMES) {
|
||||||
|
return upperBound.arguments.all {
|
||||||
|
checkParcelableType(it.type, customParcelerTypes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (superFqName in BuiltinParcelableTypes.PARCELABLE_SUPERTYPE_FQNAMES) {
|
||||||
|
if (type.matchesFqNameWithSupertypes(superFqName)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type.isBuiltinFunctionalTypeOrSubtype
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.getErasedUpperBound(): KotlinType =
|
||||||
|
constructor.declarationDescriptor?.safeAs<TypeParameterDescriptor>()?.representativeUpperBound?.getErasedUpperBound()
|
||||||
|
?: this
|
||||||
|
|
||||||
private fun ClassDescriptor.hasCustomParceler(): Boolean {
|
private fun ClassDescriptor.hasCustomParceler(): Boolean {
|
||||||
val companionObjectSuperTypes = companionObjectDescriptor?.let { TypeUtils.getAllSupertypes(it.defaultType) } ?: return false
|
val companionObjectSuperTypes = companionObjectDescriptor?.let { TypeUtils.getAllSupertypes(it.defaultType) } ?: return false
|
||||||
return companionObjectSuperTypes.any { it.isParceler }
|
return companionObjectSuperTypes.any { it.isParceler }
|
||||||
|
|||||||
Reference in New Issue
Block a user