[Parcelize] Extract common names, class ids and FQNs into separate object

This commit is contained in:
Dmitriy Novozhilov
2021-11-08 16:55:18 +03:00
committed by teamcityserver
parent edc74b8838
commit 409f96678a
18 changed files with 185 additions and 133 deletions
@@ -23,7 +23,13 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.containingPackage
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DEPRECATED_RUNTIME_PACKAGE
import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.TYPE_PARCELER_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_WITH_FQ_NAMES
import org.jetbrains.kotlin.parcelize.diagnostic.ErrorsParcelize
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
@@ -38,11 +44,6 @@ import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
import org.jetbrains.kotlin.types.typeUtil.supertypes
open class ParcelizeAnnotationChecker : CallChecker {
@Suppress("DEPRECATION")
companion object {
val DEPRECATED_RUNTIME_PACKAGE = FqName("kotlinx.android.parcel")
}
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
val constructorDescriptor = resolvedCall.resultingDescriptor as? ClassConstructorDescriptor ?: return
val annotationClass = constructorDescriptor.constructedClass.takeIf { it.kind == ClassKind.ANNOTATION_CLASS } ?: return
@@ -159,7 +160,7 @@ open class ParcelizeAnnotationChecker : CallChecker {
}
fun KotlinType.fqName() = constructor.declarationDescriptor?.fqNameSafe
val parcelerSuperType = parcelerClass.defaultType.supertypes().firstOrNull { it.fqName() == PARCELER_FQNAME } ?: return
val parcelerSuperType = parcelerClass.defaultType.supertypes().firstOrNull { it.fqName() == PARCELER_FQN } ?: return
val expectedType = parcelerSuperType.arguments.singleOrNull()?.type ?: return
if (!actualType.isSubtypeOf(expectedType)) {
@@ -188,4 +189,4 @@ internal inline fun <reified T : PsiElement> PsiElement.getStrictParentOfType():
internal inline fun <reified T : PsiElement> PsiElement.getNonStrictParentOfType(): T? {
return PsiTreeUtil.getParentOfType(this, T::class.java, false)
}
}
@@ -9,7 +9,6 @@ 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.OwnerKind
import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
import org.jetbrains.kotlin.descriptors.*
@@ -17,6 +16,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
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.ParcelizeNames.TYPE_PARCELER_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeResolveExtension.Companion.createMethod
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.*
import org.jetbrains.kotlin.parcelize.serializers.*
@@ -375,7 +376,7 @@ open class ParcelizeCodegenExtension : ParcelizeExtensionBase, ExpressionCodegen
).write(codegen, overriddenFunction) {
if (parcelerObject != null) {
val newArrayMethod = parcelerObject.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("newArray"), NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS)
.getContributedFunctions(NEW_ARRAY_NAME, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS)
.firstOrNull {
it.typeParameters.isEmpty()
&& it.kind == CallableMemberDescriptor.Kind.DECLARATION
@@ -435,4 +436,4 @@ internal fun getTypeParcelers(annotations: Annotations): List<TypeParcelerMappin
}
return serializers
}
}
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
import org.jetbrains.kotlin.parcelize.diagnostic.ErrorsParcelize
import org.jetbrains.kotlin.parcelize.serializers.ParcelSerializer
import org.jetbrains.kotlin.parcelize.serializers.isParcelable
@@ -29,10 +31,6 @@ import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.supertypes
val ANDROID_PARCELABLE_CLASS_FQNAME = FqName("android.os.Parcelable")
val ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME = FqName("android.os.Parcelable.Creator")
val ANDROID_PARCEL_CLASS_FQNAME = FqName("android.os.Parcel")
open class ParcelizeDeclarationChecker : DeclarationChecker {
private companion object {
private val IGNORED_ON_PARCEL_FQ_NAMES = listOf(
@@ -126,7 +124,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
}
for (type in descriptor.defaultType.supertypes()) {
if (type.constructor.declarationDescriptor?.fqNameSafe == OLD_PARCELER_FQNAME) {
if (type.constructor.declarationDescriptor?.fqNameSafe == OLD_PARCELER_FQN) {
val reportElement = declaration.nameIdentifier ?: declaration.getObjectKeyword() ?: declaration
diagnosticHolder.report(ErrorsParcelize.DEPRECATED_PARCELER.on(reportElement))
break
@@ -179,7 +177,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
}
val superTypes = TypeUtils.getAllSupertypes(descriptor.defaultType)
if (superTypes.none { it.constructor.declarationDescriptor?.fqNameSafe == ANDROID_PARCELABLE_CLASS_FQNAME }) {
if (superTypes.none { it.constructor.declarationDescriptor?.fqNameSafe == PARCELABLE_FQN }) {
val reportElement = declaration.nameIdentifier ?: declaration
diagnosticHolder.report(ErrorsParcelize.NO_PARCELABLE_SUPERTYPE.on(reportElement))
}
@@ -0,0 +1,75 @@
/*
* Copyright 2010-2021 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 org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
object ParcelizeNames {
// -------------------- Packages --------------------
val DEPRECATED_RUNTIME_PACKAGE = FqName("kotlinx.android.parcel")
private val PACKAGES_FQ_NAMES = listOf(
FqName("kotlinx.parcelize"),
DEPRECATED_RUNTIME_PACKAGE
)
// -------------------- Class ids --------------------
val PARCELIZE_ID = ClassId(FqName("kotlinx.parcelize"), Name.identifier("Parcelize"))
val OLD_PARCELIZE_ID = ClassId(FqName("kotlinx.android.parcel"), Name.identifier("Parcelize"))
val PARCEL_ID = ClassId(FqName("android.os"), Name.identifier("Parcel"))
val PARCELABLE_ID = ClassId(FqName("android.os"), Name.identifier("Parcelable"))
val CREATOR_ID = PARCELABLE_ID.createNestedClassId(Name.identifier("Creator"))
val PARCELER_ID = ClassId(FqName("kotlinx.parcelize"), Name.identifier("Parceler"))
val OLD_PARCELER_ID = ClassId(FqName("kotlinx.android.parcel"), Name.identifier("Parceler"))
val TYPE_PARCELER_CLASS_IDS = createClassIds("TypeParceler")
val WRITE_WITH_CLASS_IDS = createClassIds("WriteWith")
val IGNORED_ON_PARCEL_CLASS_IDS = createClassIds("IgnoredOnParcel")
val PARCELIZE_CLASS_CLASS_IDS = createClassIds("Parcelize")
val RAW_VALUE_ANNOTATION_CLASS_IDS = createClassIds("RawValue")
// -------------------- FQNs --------------------
val PARCELIZE_FQN = PARCELIZE_ID.asSingleFqName()
val OLD_PARCELIZE_FQN = OLD_PARCELIZE_ID.asSingleFqName()
val PARCELABLE_FQN = PARCELABLE_ID.asSingleFqName()
val CREATOR_FQN = CREATOR_ID.asSingleFqName()
val TYPE_PARCELER_FQ_NAMES = TYPE_PARCELER_CLASS_IDS.fqNames()
val WRITE_WITH_FQ_NAMES = WRITE_WITH_CLASS_IDS.fqNames()
val IGNORED_ON_PARCEL_FQ_NAMES = IGNORED_ON_PARCEL_CLASS_IDS.fqNames()
val PARCELIZE_CLASS_FQ_NAMES: List<FqName> = PARCELIZE_CLASS_CLASS_IDS.fqNames()
val RAW_VALUE_ANNOTATION_FQ_NAMES = RAW_VALUE_ANNOTATION_CLASS_IDS.fqNames()
val PARCELER_FQN = PARCELER_ID.asSingleFqName()
val OLD_PARCELER_FQN = OLD_PARCELER_ID.asSingleFqName()
// -------------------- Names --------------------
val DESCRIBE_CONTENTS_NAME = Name.identifier("describeContents")
val WRITE_TO_PARCEL_NAME = Name.identifier("writeToParcel")
val NEW_ARRAY_NAME = Name.identifier("newArray")
val CREATE_FROM_PARCEL_NAME = Name.identifier("createFromParcel")
val DEST_NAME = Name.identifier("dest")
val FLAGS_NAME = Name.identifier("flags")
val CREATOR_NAME = Name.identifier("CREATOR")
// -------------------- Utils --------------------
private fun createClassIds(name: String): List<ClassId> {
return PACKAGES_FQ_NAMES.map { ClassId(it, Name.identifier(name)) }
}
private fun List<ClassId>.fqNames(): List<FqName> {
return map { it.asSingleFqName() }
}
}
@@ -24,9 +24,16 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_ID
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DESCRIBE_CONTENTS_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCEL_ID
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.DESCRIBE_CONTENTS
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.WRITE_TO_PARCEL
import org.jetbrains.kotlin.resolve.BindingContext
@@ -41,11 +48,11 @@ import org.jetbrains.kotlin.types.SimpleType
open class ParcelizeResolveExtension : SyntheticResolveExtension {
companion object {
fun resolveParcelClassType(module: ModuleDescriptor): SimpleType? {
return module.findClassAcrossModuleDependencies(ClassId.topLevel(FqName("android.os.Parcel")))?.defaultType
return module.findClassAcrossModuleDependencies(PARCEL_ID)?.defaultType
}
fun resolveParcelableCreatorClassType(module: ModuleDescriptor): SimpleType? {
val creatorClassId = ClassId(FqName("android.os"), FqName("Parcelable.Creator"), false)
val creatorClassId = CREATOR_ID
return module.findClassAcrossModuleDependencies(creatorClassId)?.defaultType
}
@@ -163,47 +170,13 @@ interface ParcelizeSyntheticComponent {
val componentKind: ComponentKind
enum class ComponentKind(val methodName: String) {
WRITE_TO_PARCEL("writeToParcel"),
DESCRIBE_CONTENTS("describeContents"),
NEW_ARRAY("newArray"),
CREATE_FROM_PARCEL("createFromParcel")
WRITE_TO_PARCEL(WRITE_TO_PARCEL_NAME.identifier),
DESCRIBE_CONTENTS(DESCRIBE_CONTENTS_NAME.identifier),
NEW_ARRAY(NEW_ARRAY_NAME.identifier),
CREATE_FROM_PARCEL(CREATE_FROM_PARCEL_NAME.identifier)
}
}
val PACKAGES_FQ_NAMES = listOf(
FqName("kotlinx.parcelize"),
FqName("kotlinx.android.parcel")
)
private fun createClassIds(name: String): List<ClassId> {
return PACKAGES_FQ_NAMES.map { ClassId(it, Name.identifier(name)) }
}
private fun List<ClassId>.fqNames(): List<FqName> {
return map { it.asSingleFqName() }
}
val TYPE_PARCELER_CLASS_IDS = createClassIds("TypeParceler")
val TYPE_PARCELER_FQ_NAMES = TYPE_PARCELER_CLASS_IDS.fqNames()
val WRITE_WITH_CLASS_IDS = createClassIds("WriteWith")
val WRITE_WITH_FQ_NAMES = WRITE_WITH_CLASS_IDS.fqNames()
val IGNORED_ON_PARCEL_CLASS_IDS = createClassIds("IgnoredOnParcel")
val IGNORED_ON_PARCEL_FQ_NAMES = IGNORED_ON_PARCEL_CLASS_IDS.fqNames()
val PARCELIZE_CLASS_CLASS_IDS = createClassIds("Parcelize")
val PARCELIZE_CLASS_FQ_NAMES: List<FqName> = PARCELIZE_CLASS_CLASS_IDS.fqNames()
val RAW_VALUE_ANNOTATION_CLASS_IDS = createClassIds("RawValue")
val RAW_VALUE_ANNOTATION_FQ_NAMES = RAW_VALUE_ANNOTATION_CLASS_IDS.fqNames()
internal val PARCELER_CLASS_ID = ClassId(FqName("kotlinx.parcelize"), Name.identifier("Parceler"))
internal val PARCELER_FQNAME = PARCELER_CLASS_ID.asSingleFqName()
internal val OLD_PARCELER_CLASS_ID = ClassId(FqName("kotlinx.android.parcel"), Name.identifier("Parceler"))
internal val OLD_PARCELER_FQNAME = OLD_PARCELER_CLASS_ID.asSingleFqName()
val ClassDescriptor.hasParcelizeAnnotation: Boolean
get() = PARCELIZE_CLASS_FQ_NAMES.any(annotations::hasAnnotation)
@@ -213,7 +186,7 @@ val ClassDescriptor.isParcelize: Boolean
|| getSuperInterfaces().any { DescriptorUtils.isSealedClass(it) && it.hasParcelizeAnnotation }
val KotlinType.isParceler: Boolean
get() = constructor.declarationDescriptor?.fqNameSafe == PARCELER_FQNAME
get() = constructor.declarationDescriptor?.fqNameSafe == PARCELER_FQN
fun Annotated.findAnyAnnotation(fqNames: List<FqName>): AnnotationDescriptor? {
for (fqName in fqNames) {
@@ -32,25 +32,19 @@ import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.isInt
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DESCRIBE_CONTENTS_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DEST_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.FLAGS_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELIZE_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCEL_ID
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class FirParcelizeDeclarationGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
companion object {
private val PARCELIZE_ID = ClassId(FqName("kotlinx.parcelize"), Name.identifier("Parcelize"))
private val OLD_PARCELIZE_ID = ClassId(FqName("kotlinx.android.parcel"), Name.identifier("Parcelize"))
private val PREDICATE = has(PARCELIZE_ID.asSingleFqName(), OLD_PARCELIZE_ID.asSingleFqName())
private val DESCRIBE_CONTENTS_NAME = Name.identifier(ComponentKind.DESCRIBE_CONTENTS.methodName)
private val WRITE_TO_PARCEL_NAME = Name.identifier(ComponentKind.WRITE_TO_PARCEL.methodName)
private val DEST_NAME = Name.identifier("dest")
private val FLAGS_NAME = Name.identifier("flags")
private val PARCEL_ID = ClassId(FqName("android.os"), Name.identifier("Parcel"))
private val PREDICATE = has(PARCELIZE_FQN, OLD_PARCELIZE_FQN)
private val parcelizeMethodsNames = setOf(DESCRIBE_CONTENTS_NAME, WRITE_TO_PARCEL_NAME)
}
@@ -15,7 +15,12 @@ import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.parcelize.*
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DEPRECATED_RUNTIME_PACKAGE
import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_CLASS_IDS
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_CLASS_IDS
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_CLASS_IDS
import org.jetbrains.kotlin.parcelize.ParcelizeNames.TYPE_PARCELER_CLASS_IDS
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_WITH_CLASS_IDS
object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() {
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -46,7 +51,7 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker() {
reporter: DiagnosticReporter,
isForbidden: Boolean
) {
if (annotationClassId.packageFqName == ParcelizeAnnotationChecker.DEPRECATED_RUNTIME_PACKAGE) {
if (annotationClassId.packageFqName == DEPRECATED_RUNTIME_PACKAGE) {
val factory = if (isForbidden) KtErrorsParcelize.FORBIDDEN_DEPRECATED_ANNOTATION else KtErrorsParcelize.DEPRECATED_ANNOTATION
reporter.reportOn(annotationCall.source, factory, context)
}
@@ -28,19 +28,15 @@ import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.isSubtypeOf
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.parcelize.OLD_PARCELER_CLASS_ID
import org.jetbrains.kotlin.parcelize.PARCELIZE_CLASS_CLASS_IDS
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_ID
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_ID
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_CLASS_IDS
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
object FirParcelizeClassChecker : FirClassChecker() {
private val CREATOR_NAME = Name.identifier("CREATOR")
private val PARCELABLE_CLASS_ID = ClassId(FqName("android.os"), Name.identifier("Parcelable"))
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
checkParcelableClass(declaration, context, reporter)
checkParcelerClass(declaration, context, reporter)
@@ -80,7 +76,7 @@ object FirParcelizeClassChecker : FirClassChecker() {
}
val supertypes = lookupSuperTypes(klass, lookupInterfaces = true, deep = true, context.session, substituteTypes = false)
if (supertypes.none { it.classId == PARCELABLE_CLASS_ID }) {
if (supertypes.none { it.classId == PARCELABLE_ID }) {
reporter.reportOn(source, KtErrorsParcelize.NO_PARCELABLE_SUPERTYPE, context)
}
@@ -88,7 +84,7 @@ object FirParcelizeClassChecker : FirClassChecker() {
val superTypeRef = klass.superTypeRefs[index]
val superType = superTypeRef.coneType
val parcelableType = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(PARCELABLE_CLASS_ID),
ConeClassLikeLookupTagImpl(PARCELABLE_ID),
emptyArray(),
isNullable = false
)
@@ -109,7 +105,7 @@ object FirParcelizeClassChecker : FirClassChecker() {
if (klass !is FirRegularClass || klass.isCompanion) return
for (superTypeRef in klass.superTypeRefs) {
withSuppressedDiagnostics(superTypeRef, context) {
if (superTypeRef.coneType.classId == OLD_PARCELER_CLASS_ID) {
if (superTypeRef.coneType.classId == OLD_PARCELER_ID) {
val strategy = if (klass.name == SpecialNames.NO_NAME_PROVIDED) {
SourceElementPositioningStrategies.OBJECT_KEYWORD
} else {
@@ -25,13 +25,11 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.IGNORED_ON_PARCEL_CLASS_IDS
import org.jetbrains.kotlin.parcelize.PARCELER_CLASS_ID
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_CLASS_IDS
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_ID
object FirParcelizePropertyChecker : FirPropertyChecker() {
private val CREATOR_NAME = Name.identifier("CREATOR")
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(context.session) ?: return
@@ -94,7 +92,7 @@ object FirParcelizePropertyChecker : FirPropertyChecker() {
private fun FirRegularClassSymbol.hasCustomParceler(session: FirSession): Boolean {
val companionObjectSymbol = this.companionObjectSymbol ?: return false
return lookupSuperTypes(companionObjectSymbol, lookupInterfaces = true, deep = true, session).any {
it.classId == PARCELER_CLASS_ID
it.classId == PARCELER_ID
}
}
}
@@ -22,6 +22,10 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.ParcelizeNames
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
// All of the IR declarations needed by the parcelize plugin. Note that the declarations are generated based on JVM descriptors and
// hence contain just enough information to produce correct JVM bytecode for *calls*. In particular, we omit generic types and
@@ -165,12 +169,12 @@ class AndroidSymbols(
val t = addTypeParameter("T", irBuiltIns.anyNType)
parent = androidOsParcelable.owner
addFunction("createFromParcel", t.defaultType, Modality.ABSTRACT).apply {
addFunction(CREATE_FROM_PARCEL_NAME.identifier, t.defaultType, Modality.ABSTRACT).apply {
addValueParameter("source", androidOsParcel.defaultType)
}
addFunction(
"newArray", irBuiltIns.arrayClass.typeWith(t.defaultType.makeNullable()),
NEW_ARRAY_NAME.identifier, irBuiltIns.arrayClass.typeWith(t.defaultType.makeNullable()),
Modality.ABSTRACT
).apply {
addValueParameter("size", irBuiltIns.intType)
@@ -434,7 +438,7 @@ class AndroidSymbols(
}.symbol
val textUtilsWriteToParcel: IrSimpleFunctionSymbol =
androidTextTextUtils.owner.addFunction("writeToParcel", irBuiltIns.unitType, isStatic = true).apply {
androidTextTextUtils.owner.addFunction(WRITE_TO_PARCEL_NAME.identifier, irBuiltIns.unitType, isStatic = true).apply {
addValueParameter("cs", irBuiltIns.charSequenceClass.defaultType)
addValueParameter("p", androidOsParcel.defaultType)
addValueParameter("parcelableFlags", irBuiltIns.intType)
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.parcelize.RAW_VALUE_ANNOTATION_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
/**
@@ -13,9 +13,8 @@ import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.types.typeOrNull
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.parcelize.ParcelizeAnnotationChecker
import org.jetbrains.kotlin.parcelize.TYPE_PARCELER_FQ_NAMES
import org.jetbrains.kotlin.parcelize.WRITE_WITH_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.TYPE_PARCELER_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_WITH_FQ_NAMES
// Keep track of all custom parcelers which are currently in scope.
// Note that custom parcelers are resolved in *reverse* lexical order.
@@ -15,10 +15,10 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
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.PARCELER_FQNAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent
import org.jetbrains.kotlin.parcelize.fir.FirParcelizePluginKey
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
class ParcelizeFirIrTransformer(
context: IrPluginContext,
@@ -44,7 +44,7 @@ class ParcelizeFirIrTransformer(
// If the companion extends Parceler, it can override parts of the generated implementation.
val parcelerObject = declaration.companionObject()?.takeIf {
it.isSubclassOfFqName(PARCELER_FQNAME.asString())
it.isSubclassOfFqName(PARCELER_FQN.asString())
}
for (function in declaration.functions) {
@@ -80,3 +80,4 @@ class ParcelizeFirIrTransformer(
generateCreator(declaration, parcelerObject, parcelableProperties)
}
}
@@ -30,8 +30,11 @@ import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.parcelize.ANDROID_PARCELABLE_CLASS_FQNAME
import org.jetbrains.kotlin.parcelize.PARCELER_FQNAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DESCRIBE_CONTENTS_NAME
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
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -59,7 +62,7 @@ class ParcelizeIrTransformer(
&& callee.isInline
&& callee.fqNameWhenAvailable?.asString() == "kotlinx.parcelize.ParcelableCreatorKt.parcelableCreator"
&& callee.typeParameters.singleOrNull()?.let {
it.isReified && it.superTypes.singleOrNull()?.classFqName?.asString() == "android.os.Parcelable"
it.isReified && it.superTypes.singleOrNull()?.classFqName == PARCELABLE_FQN
} == true
) {
expression.getTypeArgument(0)?.getClass()?.let { parcelableClass ->
@@ -120,13 +123,13 @@ class ParcelizeIrTransformer(
// If the companion extends Parceler, it can override parts of the generated implementation.
val parcelerObject = declaration.companionObject()?.takeIf {
it.isSubclassOfFqName(PARCELER_FQNAME.asString())
it.isSubclassOfFqName(PARCELER_FQN.asString())
}
if (declaration.descriptor.hasSyntheticDescribeContents()) {
val describeContents = declaration.addOverride(
ANDROID_PARCELABLE_CLASS_FQNAME,
"describeContents",
PARCELABLE_FQN,
DESCRIBE_CONTENTS_NAME.identifier,
context.irBuiltIns.intType,
modality = Modality.OPEN
).apply {
@@ -147,14 +150,14 @@ class ParcelizeIrTransformer(
if (declaration.descriptor.hasSyntheticWriteToParcel()) {
val writeToParcel = declaration.addOverride(
ANDROID_PARCELABLE_CLASS_FQNAME,
"writeToParcel",
PARCELABLE_FQN,
WRITE_TO_PARCEL_NAME.identifier,
context.irBuiltIns.unitType,
modality = Modality.OPEN
).apply {
val receiverParameter = dispatchReceiverParameter!!
val parcelParameter = addValueParameter("out", androidSymbols.androidOsParcel.defaultType)
val flagsParameter = addValueParameter("flags", context.irBuiltIns.intType)
val flagsParameter = addValueParameter(FLAGS_NAME, context.irBuiltIns.intType)
// We need to defer the construction of the writer, since it may refer to the [writeToParcel] methods in other
// @Parcelize classes in the current module, which might not be constructed yet at this point.
@@ -20,6 +20,9 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
abstract class ParcelizeIrTransformerBase(
@@ -80,7 +83,7 @@ abstract class ParcelizeIrTransformerBase(
val creatorType = androidSymbols.androidOsParcelableCreator.typeWith(declarationType)
declaration.addField {
name = ParcelizeExtensionBase.CREATOR_NAME
name = CREATOR_NAME
type = creatorType
isStatic = true
isFinal = true
@@ -103,7 +106,7 @@ abstract class ParcelizeIrTransformerBase(
}
val arrayType = context.irBuiltIns.arrayClass.typeWith(declarationType.makeNullable())
addFunction("newArray", arrayType).apply {
addFunction(NEW_ARRAY_NAME.identifier, arrayType).apply {
overriddenSymbols = listOf(androidSymbols.androidOsParcelableCreator.getSimpleFunction(name.asString())!!)
val sizeParameter = addValueParameter("size", context.irBuiltIns.intType)
body = context.createIrBuilder(symbol).run {
@@ -117,7 +120,7 @@ abstract class ParcelizeIrTransformerBase(
}
}
addFunction("createFromParcel", declarationType).apply {
addFunction(CREATE_FROM_PARCEL_NAME.identifier, declarationType).apply {
overriddenSymbols = listOf(androidSymbols.androidOsParcelableCreator.getSimpleFunction(name.asString())!!)
val parcelParameter = addValueParameter("parcel", androidSymbols.androidOsParcel.defaultType)
@@ -12,8 +12,6 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.addField
import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
@@ -24,13 +22,15 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.ANDROID_PARCELABLE_CLASS_FQNAME
import org.jetbrains.kotlin.parcelize.ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME
import org.jetbrains.kotlin.parcelize.PARCELER_FQNAME
import org.jetbrains.kotlin.parcelize.PARCELIZE_CLASS_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase.Companion.CREATOR_NAME
import org.jetbrains.kotlin.types.Variance
// true if the class should be processed by the parcelize plugin
@@ -74,10 +74,10 @@ fun IrBuilderWithScope.parcelerCreate(parceler: IrClass, parcel: IrValueDeclarat
// object P: Parceler<T> { fun newArray(size: Int): Array<T> }
fun IrBuilderWithScope.parcelerNewArray(parceler: IrClass?, size: IrValueDeclaration): IrExpression? =
parceler?.parcelerSymbolByName("newArray")?.takeIf {
parceler?.parcelerSymbolByName(NEW_ARRAY_NAME.identifier)?.takeIf {
// The `newArray` method in `kotlinx.parcelize.Parceler` is stubbed out and we
// have to produce a new implementation, unless the user overrides it.
!it.owner.isFakeOverride || it.owner.resolveFakeOverride()?.parentClassOrNull?.fqNameWhenAvailable != PARCELER_FQNAME
!it.owner.isFakeOverride || it.owner.resolveFakeOverride()?.parentClassOrNull?.fqNameWhenAvailable != PARCELER_FQN
}?.let { newArraySymbol ->
irCall(newArraySymbol).apply {
dispatchReceiver = irGetObject(parceler.symbol)
@@ -93,7 +93,7 @@ fun IrBuilderWithScope.parcelableWriteToParcel(
flags: IrExpression
): IrExpression {
val writeToParcel = parcelableClass.functions.first { function ->
function.name.asString() == "writeToParcel" && function.overridesFunctionIn(ANDROID_PARCELABLE_CLASS_FQNAME)
function.name == WRITE_TO_PARCEL_NAME && function.overridesFunctionIn(PARCELABLE_FQN)
}
return irCall(writeToParcel).apply {
@@ -106,7 +106,7 @@ fun IrBuilderWithScope.parcelableWriteToParcel(
// class C : Parcelable.Creator<T> { fun createFromParcel(parcel: Parcel): T ...}
fun IrBuilderWithScope.parcelableCreatorCreateFromParcel(creator: IrExpression, parcel: IrExpression): IrExpression {
val createFromParcel = creator.type.getClass()!!.functions.first { function ->
function.name.asString() == "createFromParcel" && function.overridesFunctionIn(ANDROID_PARCELABLE_CREATOR_CLASS_FQNAME)
function.name == CREATE_FROM_PARCEL_NAME && function.overridesFunctionIn(CREATOR_FQN)
}
return irCall(createFromParcel).apply {
@@ -150,7 +150,7 @@ fun AndroidIrBuilder.getParcelableCreator(irClass: IrClass): IrExpression {
// has already done the work.
private fun IrClass.parcelerSymbolByName(name: String): IrSimpleFunctionSymbol? =
functions.firstOrNull { function ->
function.name.asString() == name && function.overridesFunctionIn(PARCELER_FQNAME)
function.name.asString() == name && function.overridesFunctionIn(PARCELER_FQN)
}?.symbol
fun IrSimpleFunction.overridesFunctionIn(fqName: FqName): Boolean =
@@ -232,4 +232,4 @@ internal fun IrAnnotationContainer.getAnyAnnotation(fqNames: List<FqName>): IrCo
}
return null
}
}
@@ -26,7 +26,8 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.RAW_VALUE_ANNOTATION_FQ_NAMES
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
import org.jetbrains.kotlin.parcelize.findAnyAnnotation
import org.jetbrains.kotlin.parcelize.hasAnyAnnotation
import org.jetbrains.kotlin.parcelize.isParcelize
@@ -448,7 +449,7 @@ interface ParcelSerializer {
}
}
internal fun KotlinType.isParcelable() = matchesFqNameWithSupertypes("android.os.Parcelable")
internal fun KotlinType.isParcelable() = matchesFqNameWithSupertypes(PARCELABLE_FQN.asString())
private fun KotlinType.matchesFqName(fqName: String): Boolean {
return this.constructor.declarationDescriptor?.fqNameSafe?.asString() == fqName
@@ -460,4 +461,4 @@ private fun KotlinType.matchesFqNameWithSupertypes(fqName: String): Boolean {
}
return TypeUtils.getAllSupertypes(this).any { it.matchesFqName(fqName) }
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.DESCRIBE_CONTENTS
import org.jetbrains.kotlin.parcelize.ParcelizeSyntheticComponent.ComponentKind.WRITE_TO_PARCEL
@@ -20,7 +21,6 @@ import java.io.FileDescriptor
interface ParcelizeExtensionBase {
companion object {
val FILE_DESCRIPTOR_FQNAME = FqName(FileDescriptor::class.java.canonicalName)
val CREATOR_NAME = Name.identifier("CREATOR")
val ALLOWED_CLASS_KINDS = listOf(ClassKind.CLASS, ClassKind.OBJECT, ClassKind.ENUM_CLASS)
}
@@ -57,4 +57,4 @@ interface ParcelizeExtensionBase {
return writeToParcelMethods.size == 1
}
}
}