[Parcelize] Allow parcelize to work on common code in multiplatform.
Since parcelize is Android specific, it should only be enabled for Android compilation. In order to allow parcelize to generate code for declarations in common code, we make checkers platform checkers and we allow the registration of an additional annotations to trigger parcelize processing. That way, code such as: ``` package my.package annotation class Parcelize expect interface MyParcelable @Parcelize data class User(name: String): MyParcelable ``` Will work with an Android platform actual of the form: ``` actual typealias MyParcelable = android.os.Parcelable ``` And telling the plugin to trigger parcelize processing with the additional annotation `my.package.Parcelize`. Fixes https://issuetracker.google.com/315775835.
This commit is contained in:
+3
-2
@@ -12,9 +12,10 @@ import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.inlineClassRepresentation
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
|
||||
|
||||
class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
||||
class IrParcelSerializerFactory(private val symbols: AndroidSymbols, private val parcelizeAnnotations: List<FqName>) {
|
||||
private val supportedBySimpleListSerializer = setOf(
|
||||
"kotlin.collections.List", "kotlin.collections.MutableList", "kotlin.collections.ArrayList",
|
||||
"java.util.List", "java.util.ArrayList",
|
||||
@@ -313,7 +314,7 @@ class IrParcelSerializerFactory(private val symbols: AndroidSymbols) {
|
||||
// @Parcelize), we'll have a field in the class itself. Finally, with Parcelable instances which were
|
||||
// manually implemented in Kotlin, we'll instead have an @JvmField property getter in the companion object.
|
||||
return if (classifier.modality == Modality.FINAL && classifier.psiElement != null
|
||||
&& (classifier.isParcelize || classifier.hasCreatorField)
|
||||
&& (classifier.isParcelize(parcelizeAnnotations) || classifier.hasCreatorField)
|
||||
) {
|
||||
wrapNullableSerializerIfNeeded(irType, IrEfficientParcelableParcelSerializer(classifier))
|
||||
} else {
|
||||
|
||||
+3
-2
@@ -8,10 +8,11 @@ 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.name.FqName
|
||||
|
||||
class ParcelizeFirIrGeneratorExtension : IrGenerationExtension {
|
||||
class ParcelizeFirIrGeneratorExtension(private val parcelizeAnnotations: List<FqName>) : IrGenerationExtension {
|
||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
||||
ParcelizeFirIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
||||
ParcelizeFirIrTransformer(pluginContext, androidSymbols, parcelizeAnnotations).transform(moduleFragment)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -14,13 +14,15 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
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.name.FqName
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_FQN
|
||||
import org.jetbrains.kotlin.parcelize.fir.ParcelizePluginKey
|
||||
|
||||
class ParcelizeFirIrTransformer(
|
||||
context: IrPluginContext,
|
||||
androidSymbols: AndroidSymbols
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols) {
|
||||
androidSymbols: AndroidSymbols,
|
||||
parcelizeAnnotations: List<FqName>
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols, parcelizeAnnotations) {
|
||||
|
||||
fun transform(moduleFragment: IrModuleFragment) {
|
||||
moduleFragment.accept(this, null)
|
||||
@@ -34,7 +36,7 @@ class ParcelizeFirIrTransformer(
|
||||
|
||||
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
||||
// should process their immediate subclasses.
|
||||
if (!declaration.isParcelize || declaration.modality == Modality.SEALED)
|
||||
if (!declaration.isParcelize(parcelizeAnnotations) || declaration.modality == Modality.SEALED)
|
||||
return
|
||||
|
||||
val parcelableProperties = declaration.parcelableProperties
|
||||
|
||||
+4
-2
@@ -8,10 +8,12 @@ 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.name.FqName
|
||||
|
||||
class ParcelizeIrGeneratorExtension : IrGenerationExtension {
|
||||
// This class is open so that the IDE integration can create a subclass with a fixed set of annotations.
|
||||
open class ParcelizeIrGeneratorExtension(private val parcelizeAnnotations: List<FqName>) : IrGenerationExtension {
|
||||
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
||||
ParcelizeIrTransformer(pluginContext, androidSymbols).transform(moduleFragment)
|
||||
ParcelizeIrTransformer(pluginContext, androidSymbols, parcelizeAnnotations).transform(moduleFragment)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -36,8 +36,9 @@ import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class ParcelizeIrTransformer(
|
||||
context: IrPluginContext,
|
||||
androidSymbols: AndroidSymbols
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols) {
|
||||
androidSymbols: AndroidSymbols,
|
||||
parcelizeAnnotations: List<FqName>
|
||||
) : ParcelizeIrTransformerBase(context, androidSymbols, parcelizeAnnotations) {
|
||||
private val symbolMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
|
||||
fun transform(moduleFragment: IrModuleFragment) {
|
||||
@@ -101,7 +102,7 @@ class ParcelizeIrTransformer(
|
||||
|
||||
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
||||
// should process their immediate subclasses.
|
||||
if (!declaration.isParcelize || declaration.modality == Modality.SEALED)
|
||||
if (!declaration.isParcelize(parcelizeAnnotations) || declaration.modality == Modality.SEALED)
|
||||
return
|
||||
|
||||
val parcelableProperties = declaration.parcelableProperties
|
||||
|
||||
+4
-2
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
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_NAME
|
||||
@@ -27,7 +28,8 @@ import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
|
||||
|
||||
abstract class ParcelizeIrTransformerBase(
|
||||
protected val context: IrPluginContext,
|
||||
protected val androidSymbols: AndroidSymbols
|
||||
protected val androidSymbols: AndroidSymbols,
|
||||
protected val parcelizeAnnotations: List<FqName>
|
||||
) : ParcelizeExtensionBase, IrElementVisitorVoid {
|
||||
private val irFactory: IrFactory = IrFactoryImpl
|
||||
|
||||
@@ -173,7 +175,7 @@ abstract class ParcelizeIrTransformerBase(
|
||||
val parceler by lazy(parcelerThunk)
|
||||
}
|
||||
|
||||
private val serializerFactory = IrParcelSerializerFactory(androidSymbols)
|
||||
private val serializerFactory = IrParcelSerializerFactory(androidSymbols, parcelizeAnnotations)
|
||||
|
||||
protected val IrClass.parcelableProperties: List<ParcelableProperty?>
|
||||
get() {
|
||||
|
||||
+4
-5
@@ -27,17 +27,16 @@ 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.types.Variance
|
||||
|
||||
// true if the class should be processed by the parcelize plugin
|
||||
val IrClass.isParcelize: Boolean
|
||||
get() = kind in ParcelizeExtensionBase.ALLOWED_CLASS_KINDS &&
|
||||
(hasAnyAnnotation(PARCELIZE_CLASS_FQ_NAMES) || superTypes.any { superType ->
|
||||
fun IrClass.isParcelize(parcelizeAnnotations: List<FqName>): Boolean =
|
||||
kind in ParcelizeExtensionBase.ALLOWED_CLASS_KINDS &&
|
||||
(hasAnyAnnotation(parcelizeAnnotations) || superTypes.any { superType ->
|
||||
superType.classOrNull?.owner?.let {
|
||||
it.modality == Modality.SEALED && it.hasAnyAnnotation(PARCELIZE_CLASS_FQ_NAMES)
|
||||
it.modality == Modality.SEALED && it.hasAnyAnnotation(parcelizeAnnotations)
|
||||
} == true
|
||||
})
|
||||
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.parcelize.ParcelizeCommandLineProcessor
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2024 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.compiler.plugin.AbstractCliOption
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
|
||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
|
||||
class ParcelizeCommandLineProcessor : CommandLineProcessor {
|
||||
companion object {
|
||||
const val COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.parcelize"
|
||||
|
||||
val ADDITIONAL_ANNOTATION_OPTION: CliOption =
|
||||
CliOption(
|
||||
"additionalAnnotation",
|
||||
"<fully qualified name>",
|
||||
"Additional annotation to trigger parcelize processing.",
|
||||
required = false,
|
||||
allowMultipleOccurrences = true
|
||||
)
|
||||
}
|
||||
|
||||
override val pluginId: String
|
||||
get() = COMPILER_PLUGIN_ID
|
||||
|
||||
override val pluginOptions: Collection<AbstractCliOption>
|
||||
get() = listOf(ADDITIONAL_ANNOTATION_OPTION)
|
||||
|
||||
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
|
||||
when (option) {
|
||||
ADDITIONAL_ANNOTATION_OPTION -> configuration.appendList(ParcelizeConfigurationKeys.ADDITIONAL_ANNOTATION, value)
|
||||
else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-10
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.parcelize.fir.FirParcelizeExtensionRegistrar
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
@@ -21,35 +22,44 @@ import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
||||
|
||||
class ParcelizeComponentRegistrar : CompilerPluginRegistrar() {
|
||||
companion object {
|
||||
fun registerParcelizeComponents(extensionStorage: ExtensionStorage, useFir: Boolean) = with(extensionStorage) {
|
||||
fun registerParcelizeComponents(
|
||||
extensionStorage: ExtensionStorage,
|
||||
additionalAnnotation: List<String>,
|
||||
useFir: Boolean
|
||||
) = with(extensionStorage) {
|
||||
val parcelizeAnnotations = ParcelizeNames.PARCELIZE_CLASS_FQ_NAMES.toMutableList()
|
||||
additionalAnnotation.mapTo(parcelizeAnnotations) { FqName(it) }
|
||||
if (useFir) {
|
||||
IrGenerationExtension.registerExtension(ParcelizeFirIrGeneratorExtension())
|
||||
IrGenerationExtension.registerExtension(ParcelizeFirIrGeneratorExtension(parcelizeAnnotations))
|
||||
} else {
|
||||
IrGenerationExtension.registerExtension(ParcelizeIrGeneratorExtension())
|
||||
IrGenerationExtension.registerExtension(ParcelizeIrGeneratorExtension(parcelizeAnnotations))
|
||||
}
|
||||
SyntheticResolveExtension.registerExtension(ParcelizeResolveExtension())
|
||||
StorageComponentContainerContributor.registerExtension(ParcelizeDeclarationCheckerComponentContainerContributor())
|
||||
FirExtensionRegistrarAdapter.registerExtension(FirParcelizeExtensionRegistrar())
|
||||
SyntheticResolveExtension.registerExtension(ParcelizeResolveExtension(parcelizeAnnotations))
|
||||
StorageComponentContainerContributor.registerExtension(ParcelizeDeclarationCheckerComponentContainerContributor(parcelizeAnnotations))
|
||||
FirExtensionRegistrarAdapter.registerExtension(FirParcelizeExtensionRegistrar(parcelizeAnnotations))
|
||||
}
|
||||
}
|
||||
|
||||
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
|
||||
registerParcelizeComponents(this, configuration.getBoolean(CommonConfigurationKeys.USE_FIR))
|
||||
val additionalAnnotation = configuration.get(ParcelizeConfigurationKeys.ADDITIONAL_ANNOTATION) ?: emptyList()
|
||||
registerParcelizeComponents(this, additionalAnnotation, configuration.getBoolean(CommonConfigurationKeys.USE_FIR))
|
||||
}
|
||||
|
||||
override val supportsK2: Boolean
|
||||
get() = true
|
||||
}
|
||||
|
||||
class ParcelizeDeclarationCheckerComponentContainerContributor : StorageComponentContainerContributor {
|
||||
class ParcelizeDeclarationCheckerComponentContainerContributor(
|
||||
private val parcelizeAnnotations: List<FqName>
|
||||
) : StorageComponentContainerContributor {
|
||||
override fun registerModuleComponents(
|
||||
container: StorageComponentContainer,
|
||||
platform: TargetPlatform,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
) {
|
||||
if (platform.isJvm()) {
|
||||
container.useInstance(ParcelizeDeclarationChecker())
|
||||
container.useInstance(ParcelizeAnnotationChecker())
|
||||
container.useInstance(ParcelizeDeclarationChecker(parcelizeAnnotations))
|
||||
container.useInstance(ParcelizeAnnotationChecker(parcelizeAnnotations))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2024 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.config.CompilerConfigurationKey
|
||||
|
||||
object ParcelizeConfigurationKeys {
|
||||
val ADDITIONAL_ANNOTATION: CompilerConfigurationKey<List<String>> =
|
||||
CompilerConfigurationKey.create(ParcelizeCommandLineProcessor.ADDITIONAL_ANNOTATION_OPTION.description)
|
||||
}
|
||||
-4
@@ -21,8 +21,6 @@ object ParcelizeNames {
|
||||
|
||||
// -------------------- 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"))
|
||||
@@ -38,8 +36,6 @@ object ParcelizeNames {
|
||||
|
||||
// -------------------- 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()
|
||||
|
||||
|
||||
+4
-4
@@ -23,10 +23,10 @@ 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
|
||||
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
|
||||
open class ParcelizeAnnotationChecker : CallChecker {
|
||||
open class ParcelizeAnnotationChecker(val parcelizeAnnotations : List<FqName>) : CallChecker {
|
||||
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
|
||||
@@ -66,7 +66,7 @@ open class ParcelizeAnnotationChecker : CallChecker {
|
||||
checkDeprecatedAnnotations(resolvedCall, annotationEntry, context, isForbidden = false)
|
||||
}
|
||||
|
||||
if (annotationClass.fqNameSafe in PARCELIZE_CLASS_FQ_NAMES || annotationClass.fqNameSafe in RAW_VALUE_ANNOTATION_FQ_NAMES) {
|
||||
if (annotationClass.fqNameSafe in parcelizeAnnotations || annotationClass.fqNameSafe in RAW_VALUE_ANNOTATION_FQ_NAMES) {
|
||||
checkDeprecatedAnnotations(resolvedCall, annotationEntry, context, isForbidden = false)
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ open class ParcelizeAnnotationChecker : CallChecker {
|
||||
) {
|
||||
if (containingClass != null) {
|
||||
val containingClassDescriptor = context.trace[BindingContext.CLASS, containingClass]
|
||||
if (containingClassDescriptor != null && !containingClassDescriptor.isParcelize) {
|
||||
if (containingClassDescriptor != null && !containingClassDescriptor.isParcelize(parcelizeAnnotations)) {
|
||||
val reportElement = (annotationEntry.typeReference?.typeElement as? KtUserType)?.referenceExpression ?: annotationEntry
|
||||
context.trace.report(ErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE.on(reportElement, containingClass))
|
||||
}
|
||||
|
||||
+5
-5
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
|
||||
open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
open class ParcelizeDeclarationChecker(val parcelizeAnnotations: List<FqName>) : DeclarationChecker {
|
||||
private companion object {
|
||||
private val IGNORED_ON_PARCEL_FQ_NAMES = listOf(
|
||||
FqName("kotlinx.parcelize.IgnoredOnParcel"),
|
||||
@@ -71,7 +71,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
declaration: KtFunction,
|
||||
diagnosticHolder: DiagnosticSink
|
||||
) {
|
||||
if (!containingClass.isParcelize) {
|
||||
if (!containingClass.isParcelize(parcelizeAnnotations)) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
return property.annotations.hasIgnoredOnParcel() || (property.getter?.annotations?.hasIgnoredOnParcel() ?: false)
|
||||
}
|
||||
|
||||
if (containingClass.isParcelize
|
||||
if (containingClass.isParcelize(parcelizeAnnotations)
|
||||
&& (declaration.hasDelegate() || bindingContext[BindingContext.BACKING_FIELD_REQUIRED, property] == true)
|
||||
&& !hasIgnoredOnParcel()
|
||||
&& !containingClass.hasCustomParceler()
|
||||
@@ -109,7 +109,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
// @JvmName is not applicable to property so we can check just the descriptor name
|
||||
if (property.name.asString() == "CREATOR" && property.findJvmFieldAnnotation() != null && containingClass.isCompanionObject) {
|
||||
val outerClass = containingClass.containingDeclaration as? ClassDescriptor
|
||||
if (outerClass != null && outerClass.isParcelize) {
|
||||
if (outerClass != null && outerClass.isParcelize(parcelizeAnnotations)) {
|
||||
val reportElement = declaration.nameIdentifier ?: declaration
|
||||
diagnosticHolder.report(ErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED.on(reportElement))
|
||||
}
|
||||
@@ -141,7 +141,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
||||
bindingContext: BindingContext,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
if (!descriptor.isParcelize) {
|
||||
if (!descriptor.isParcelize(parcelizeAnnotations)) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_NAME
|
||||
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
|
||||
@@ -46,7 +45,7 @@ import org.jetbrains.kotlin.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.error.ErrorTypeKind
|
||||
import org.jetbrains.kotlin.types.error.ErrorUtils
|
||||
|
||||
open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
||||
open class ParcelizeResolveExtension(private val parcelizeAnnotations: List<FqName>) : SyntheticResolveExtension {
|
||||
companion object {
|
||||
fun resolveParcelClassType(module: ModuleDescriptor): SimpleType? {
|
||||
return module.findClassAcrossModuleDependencies(PARCEL_ID)?.defaultType
|
||||
@@ -107,7 +106,7 @@ open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
||||
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? = null
|
||||
|
||||
override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> {
|
||||
return if (thisDescriptor.isParcelize) parcelizeMethodNames else emptyList()
|
||||
return if (thisDescriptor.isParcelize(parcelizeAnnotations)) parcelizeMethodNames else emptyList()
|
||||
}
|
||||
|
||||
override fun generateSyntheticMethods(
|
||||
@@ -123,7 +122,7 @@ open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
||||
}
|
||||
|
||||
if (name.asString() == DESCRIBE_CONTENTS.methodName
|
||||
&& thisDescriptor.isParcelize
|
||||
&& thisDescriptor.isParcelize(parcelizeAnnotations)
|
||||
&& !thisDescriptor.isSealed()
|
||||
&& isParcelizePluginEnabled()
|
||||
&& result.none { it.isDescribeContents() }
|
||||
@@ -131,7 +130,7 @@ open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
||||
) {
|
||||
result += createMethod(thisDescriptor, DESCRIBE_CONTENTS, Modality.OPEN, thisDescriptor.builtIns.intType)
|
||||
} else if (name.asString() == WRITE_TO_PARCEL.methodName
|
||||
&& thisDescriptor.isParcelize
|
||||
&& thisDescriptor.isParcelize(parcelizeAnnotations)
|
||||
&& !thisDescriptor.isSealed()
|
||||
&& isParcelizePluginEnabled()
|
||||
&& result.none { it.isWriteToParcel() }
|
||||
@@ -173,13 +172,13 @@ interface ParcelizeSyntheticComponent {
|
||||
}
|
||||
}
|
||||
|
||||
val ClassDescriptor.hasParcelizeAnnotation: Boolean
|
||||
get() = PARCELIZE_CLASS_FQ_NAMES.any(annotations::hasAnnotation)
|
||||
fun ClassDescriptor.hasParcelizeAnnotation(parcelizeAnnotations: List<FqName>): Boolean =
|
||||
parcelizeAnnotations.any(annotations::hasAnnotation)
|
||||
|
||||
val ClassDescriptor.isParcelize: Boolean
|
||||
get() = hasParcelizeAnnotation
|
||||
|| getSuperClassNotAny()?.takeIf(DescriptorUtils::isSealedClass)?.hasParcelizeAnnotation == true
|
||||
|| getSuperInterfaces().any { DescriptorUtils.isSealedClass(it) && it.hasParcelizeAnnotation }
|
||||
fun ClassDescriptor.isParcelize(parcelizeAnnotations: List<FqName>): Boolean =
|
||||
hasParcelizeAnnotation(parcelizeAnnotations)
|
||||
|| getSuperClassNotAny()?.takeIf(DescriptorUtils::isSealedClass)?.hasParcelizeAnnotation(parcelizeAnnotations) == true
|
||||
|| getSuperInterfaces().any { DescriptorUtils.isSealedClass(it) && it.hasParcelizeAnnotation(parcelizeAnnotations) }
|
||||
|
||||
val KotlinType.isParceler: Boolean
|
||||
get() = constructor.declarationDescriptor?.fqNameSafe == PARCELER_FQN
|
||||
|
||||
+2
-1
@@ -38,6 +38,7 @@ interface ParcelSerializer {
|
||||
fun readValue(v: InstructionAdapter)
|
||||
|
||||
data class ParcelSerializerContext(
|
||||
val parcelizeAnnotations: List<FqName>,
|
||||
val typeMapper: KotlinTypeMapper,
|
||||
val containerClassType: Type,
|
||||
val typeParcelers: List<TypeParcelerMapping>,
|
||||
@@ -344,7 +345,7 @@ interface ParcelSerializer {
|
||||
|
||||
val creatorAsmType = when {
|
||||
creatorVar != null -> typeMapper.mapTypeSafe(creatorVar.type, forceBoxed = true)
|
||||
clazz.isParcelize -> Type.getObjectType(asmType.internalName + "\$Creator")
|
||||
clazz.isParcelize(context.parcelizeAnnotations) -> Type.getObjectType(asmType.internalName + "\$Creator")
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -36,7 +36,8 @@ interface ParcelizeExtensionBase {
|
||||
.isNotEmpty()
|
||||
}
|
||||
|
||||
val ClassDescriptor.isParcelizeClassDescriptor get() = kind in ALLOWED_CLASS_KINDS && isParcelize
|
||||
fun ClassDescriptor.isParcelizeClassDescriptor(parcelizeAnnotations: List<FqName>)
|
||||
= kind in ALLOWED_CLASS_KINDS && isParcelize(parcelizeAnnotations)
|
||||
|
||||
fun ClassDescriptor.hasSyntheticDescribeContents() = hasParcelizeSyntheticMethod(DESCRIBE_CONTENTS)
|
||||
|
||||
|
||||
+10
-6
@@ -10,25 +10,29 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.*
|
||||
|
||||
class FirParcelizeCheckersExtension(session: FirSession) : FirAdditionalCheckersExtension(session) {
|
||||
class FirParcelizeCheckersExtension(
|
||||
session: FirSession,
|
||||
val parcelizeAnnotations: List<ClassId>
|
||||
) : FirAdditionalCheckersExtension(session) {
|
||||
override val expressionCheckers: ExpressionCheckers = object : ExpressionCheckers() {
|
||||
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
||||
get() = setOf(FirParcelizeAnnotationChecker)
|
||||
get() = setOf(FirParcelizeAnnotationChecker(parcelizeAnnotations))
|
||||
}
|
||||
|
||||
override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() {
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(FirParcelizeClassChecker)
|
||||
get() = setOf(FirParcelizeClassChecker(parcelizeAnnotations))
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
get() = setOf(FirParcelizePropertyChecker)
|
||||
get() = setOf(FirParcelizePropertyChecker(parcelizeAnnotations))
|
||||
|
||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||
get() = setOf(FirParcelizeFunctionChecker)
|
||||
get() = setOf(FirParcelizeFunctionChecker(parcelizeAnnotations))
|
||||
|
||||
override val constructorCheckers: Set<FirConstructorChecker>
|
||||
get() = setOf(FirParcelizeConstructorChecker)
|
||||
get() = setOf(FirParcelizeConstructorChecker(parcelizeAnnotations))
|
||||
}
|
||||
}
|
||||
|
||||
+9
-6
@@ -23,25 +23,28 @@ import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
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.parcelize.fir.diagnostics.checkParcelizeClassSymbols
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class FirParcelizeDeclarationGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
class FirParcelizeDeclarationGenerator(
|
||||
session: FirSession,
|
||||
private val annotations: List<FqName>
|
||||
) : FirDeclarationGenerationExtension(session) {
|
||||
companion object {
|
||||
private val PREDICATE = LookupPredicate.create { annotated(PARCELIZE_FQN, OLD_PARCELIZE_FQN) }
|
||||
private val parcelizeMethodsNames = setOf(DESCRIBE_CONTENTS_NAME, WRITE_TO_PARCEL_NAME)
|
||||
}
|
||||
|
||||
private val predicate = LookupPredicate.create { annotated(annotations) }
|
||||
|
||||
private val matchedClasses by lazy {
|
||||
session.predicateBasedProvider.getSymbolsByPredicate(PREDICATE)
|
||||
session.predicateBasedProvider.getSymbolsByPredicate(predicate)
|
||||
.filterIsInstance<FirRegularClassSymbol>()
|
||||
}
|
||||
|
||||
@@ -116,6 +119,6 @@ class FirParcelizeDeclarationGenerator(session: FirSession) : FirDeclarationGene
|
||||
get() = ParcelizePluginKey
|
||||
|
||||
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||
register(PREDICATE)
|
||||
register(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -6,10 +6,12 @@
|
||||
package org.jetbrains.kotlin.parcelize.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class FirParcelizeExtensionRegistrar : FirExtensionRegistrar() {
|
||||
class FirParcelizeExtensionRegistrar(val parcelizeAnnotationFqNames: List<FqName>) : FirExtensionRegistrar() {
|
||||
override fun ExtensionRegistrarContext.configurePlugin() {
|
||||
+::FirParcelizeDeclarationGenerator
|
||||
+::FirParcelizeCheckersExtension
|
||||
+::FirParcelizeDeclarationGenerator.bind(parcelizeAnnotationFqNames)
|
||||
+::FirParcelizeCheckersExtension.bind(parcelizeAnnotationFqNames.map { ClassId.topLevel(it) })
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -23,13 +23,13 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
||||
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
|
||||
|
||||
// TODO: extract common checker for expect interfaces
|
||||
object FirParcelizeAnnotationChecker : FirAnnotationCallChecker(MppCheckerKind.Platform) {
|
||||
class FirParcelizeAnnotationChecker(private val parcelizeAnnotationClassIds: List<ClassId>) :
|
||||
FirAnnotationCallChecker(MppCheckerKind.Platform) {
|
||||
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotationType = expression.annotationTypeRef.coneType.fullyExpandedType(context.session) as? ConeClassLikeType ?: return
|
||||
val resolvedAnnotationSymbol = annotationType.lookupTag.toFirRegularClassSymbol(context.session) ?: return
|
||||
@@ -47,7 +47,7 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker(MppCheckerKind.P
|
||||
in IGNORED_ON_PARCEL_CLASS_IDS -> {
|
||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false)
|
||||
}
|
||||
in PARCELIZE_CLASS_CLASS_IDS, in RAW_VALUE_ANNOTATION_CLASS_IDS -> {
|
||||
in parcelizeAnnotationClassIds, in RAW_VALUE_ANNOTATION_CLASS_IDS -> {
|
||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false)
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,7 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker(MppCheckerKind.P
|
||||
private fun checkIfTheContainingClassIsParcelize(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val enclosingClass = context.findClosestClassOrObject() ?: return
|
||||
|
||||
if (!enclosingClass.symbol.isParcelize(context.session)) {
|
||||
if (!enclosingClass.symbol.isParcelize(context.session, parcelizeAnnotationClassIds)) {
|
||||
val reportElement = annotationCall.calleeReference.source ?: annotationCall.source
|
||||
reporter.reportOn(reportElement, KtErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE, enclosingClass.symbol, context)
|
||||
}
|
||||
|
||||
+5
-5
@@ -21,16 +21,16 @@ import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
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.PARCELER_CLASS_IDS
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELIZE_CLASS_CLASS_IDS
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
object FirParcelizeClassChecker : FirClassChecker(MppCheckerKind.Common) {
|
||||
class FirParcelizeClassChecker(private val parcelizeAnnotations: List<ClassId>) : FirClassChecker(MppCheckerKind.Platform) {
|
||||
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
checkParcelableClass(declaration, context, reporter)
|
||||
checkParcelerClass(declaration, context, reporter)
|
||||
@@ -38,7 +38,7 @@ object FirParcelizeClassChecker : FirClassChecker(MppCheckerKind.Common) {
|
||||
|
||||
private fun checkParcelableClass(klass: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val symbol = klass.symbol
|
||||
if (!symbol.isParcelize(context.session)) return
|
||||
if (!symbol.isParcelize(context.session, parcelizeAnnotations)) return
|
||||
val source = klass.source ?: return
|
||||
val classKind = klass.classKind
|
||||
|
||||
@@ -110,14 +110,14 @@ object FirParcelizeClassChecker : FirClassChecker(MppCheckerKind.Common) {
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun FirClassSymbol<*>?.isParcelize(session: FirSession): Boolean {
|
||||
fun FirClassSymbol<*>?.isParcelize(session: FirSession, parcelizeAnnotations: List<ClassId>): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isParcelize != null)
|
||||
}
|
||||
|
||||
if (this == null) return false
|
||||
return checkParcelizeClassSymbols(this, session) { symbol ->
|
||||
symbol.annotations.any { it.toAnnotationClassId(session) in PARCELIZE_CLASS_CLASS_IDS }
|
||||
symbol.annotations.any { it.toAnnotationClassId(session) in parcelizeAnnotations }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -16,16 +16,20 @@ import org.jetbrains.kotlin.fir.correspondingProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
||||
|
||||
object FirParcelizeConstructorChecker : FirConstructorChecker(MppCheckerKind.Common) {
|
||||
class FirParcelizeConstructorChecker(private val parcelizeAnnotations: List<ClassId>) : FirConstructorChecker(MppCheckerKind.Platform) {
|
||||
override fun check(declaration: FirConstructor, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.isPrimary) return
|
||||
val source = declaration.source ?: return
|
||||
if (source.kind == KtFakeSourceElementKind.ImplicitConstructor) return
|
||||
val containingClass = context.containingDeclarations.last() as? FirRegularClass ?: return
|
||||
val containingClassSymbol = containingClass.symbol
|
||||
if (!containingClassSymbol.isParcelize(context.session) || containingClass.hasCustomParceler(context.session)) return
|
||||
if (!containingClassSymbol.isParcelize(context.session, parcelizeAnnotations)
|
||||
|| containingClass.hasCustomParceler(context.session)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration.valueParameters.isEmpty()) {
|
||||
reporter.reportOn(containingClass.source, KtErrorsParcelize.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY, context)
|
||||
|
||||
+3
-2
@@ -17,11 +17,12 @@ import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isInt
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
object FirParcelizeFunctionChecker : FirSimpleFunctionChecker(MppCheckerKind.Common) {
|
||||
class FirParcelizeFunctionChecker(private val parcelizeAnnotations: List<ClassId>) : FirSimpleFunctionChecker(MppCheckerKind.Platform) {
|
||||
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(context.session)
|
||||
if (!containingClassSymbol.isParcelize(context.session)) return
|
||||
if (!containingClassSymbol.isParcelize(context.session, parcelizeAnnotations)) return
|
||||
if (declaration.origin != FirDeclarationOrigin.Source) return
|
||||
if (declaration.isWriteToParcel() && declaration.isOverride) {
|
||||
reporter.reportOn(declaration.source, KtErrorsParcelize.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED, context)
|
||||
|
||||
+4
-3
@@ -26,18 +26,19 @@ import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.parcelize.BuiltinParcelableTypes
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
||||
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(MppCheckerKind.Common) {
|
||||
class FirParcelizePropertyChecker(private val parcelizeAnnotations: List<ClassId>) : FirPropertyChecker(MppCheckerKind.Platform) {
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val session = context.session
|
||||
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(session) ?: return
|
||||
|
||||
if (containingClassSymbol.isParcelize(session)) {
|
||||
if (containingClassSymbol.isParcelize(session, parcelizeAnnotations)) {
|
||||
val fromPrimaryConstructor = declaration.fromPrimaryConstructor ?: false
|
||||
if (
|
||||
!fromPrimaryConstructor &&
|
||||
@@ -54,7 +55,7 @@ object FirParcelizePropertyChecker : FirPropertyChecker(MppCheckerKind.Common) {
|
||||
|
||||
if (declaration.name == CREATOR_NAME && containingClassSymbol.isCompanion && declaration.hasJvmFieldAnnotation(session)) {
|
||||
val outerClass = context.containingDeclarations.asReversed().getOrNull(1) as? FirRegularClass
|
||||
if (outerClass != null && outerClass.symbol.isParcelize(session)) {
|
||||
if (outerClass != null && outerClass.symbol.isParcelize(session, parcelizeAnnotations)) {
|
||||
reporter.reportOn(declaration.source, KtErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED, context)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeComponentRegistrar
|
||||
import org.jetbrains.kotlin.parcelize.ParcelizeConfigurationKeys
|
||||
import org.jetbrains.kotlin.parcelize.kotlinxImmutable
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
@@ -47,6 +48,11 @@ class ParcelizeEnvironmentConfigurator(testServices: TestServices) : Environment
|
||||
module: TestModule,
|
||||
configuration: CompilerConfiguration
|
||||
) {
|
||||
ParcelizeComponentRegistrar.registerParcelizeComponents(this, useFir = module.frontendKind == FrontendKinds.FIR)
|
||||
val additionalAnnotation = configuration.get(ParcelizeConfigurationKeys.ADDITIONAL_ANNOTATION)
|
||||
ParcelizeComponentRegistrar.registerParcelizeComponents(
|
||||
this,
|
||||
additionalAnnotation,
|
||||
useFir = module.frontendKind == FrontendKinds.FIR
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user