[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.declarations.inlineClassRepresentation
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.RAW_VALUE_ANNOTATION_FQ_NAMES
|
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(
|
private val supportedBySimpleListSerializer = setOf(
|
||||||
"kotlin.collections.List", "kotlin.collections.MutableList", "kotlin.collections.ArrayList",
|
"kotlin.collections.List", "kotlin.collections.MutableList", "kotlin.collections.ArrayList",
|
||||||
"java.util.List", "java.util.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
|
// @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.
|
// 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
|
return if (classifier.modality == Modality.FINAL && classifier.psiElement != null
|
||||||
&& (classifier.isParcelize || classifier.hasCreatorField)
|
&& (classifier.isParcelize(parcelizeAnnotations) || classifier.hasCreatorField)
|
||||||
) {
|
) {
|
||||||
wrapNullableSerializerIfNeeded(irType, IrEfficientParcelableParcelSerializer(classifier))
|
wrapNullableSerializerIfNeeded(irType, IrEfficientParcelableParcelSerializer(classifier))
|
||||||
} else {
|
} 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.IrGenerationExtension
|
||||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
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) {
|
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||||
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
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.companionObject
|
||||||
import org.jetbrains.kotlin.ir.util.functions
|
import org.jetbrains.kotlin.ir.util.functions
|
||||||
import org.jetbrains.kotlin.ir.util.render
|
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.ParcelizeNames.PARCELER_FQN
|
||||||
import org.jetbrains.kotlin.parcelize.fir.ParcelizePluginKey
|
import org.jetbrains.kotlin.parcelize.fir.ParcelizePluginKey
|
||||||
|
|
||||||
class ParcelizeFirIrTransformer(
|
class ParcelizeFirIrTransformer(
|
||||||
context: IrPluginContext,
|
context: IrPluginContext,
|
||||||
androidSymbols: AndroidSymbols
|
androidSymbols: AndroidSymbols,
|
||||||
) : ParcelizeIrTransformerBase(context, androidSymbols) {
|
parcelizeAnnotations: List<FqName>
|
||||||
|
) : ParcelizeIrTransformerBase(context, androidSymbols, parcelizeAnnotations) {
|
||||||
|
|
||||||
fun transform(moduleFragment: IrModuleFragment) {
|
fun transform(moduleFragment: IrModuleFragment) {
|
||||||
moduleFragment.accept(this, null)
|
moduleFragment.accept(this, null)
|
||||||
@@ -34,7 +36,7 @@ class ParcelizeFirIrTransformer(
|
|||||||
|
|
||||||
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
||||||
// should process their immediate subclasses.
|
// should process their immediate subclasses.
|
||||||
if (!declaration.isParcelize || declaration.modality == Modality.SEALED)
|
if (!declaration.isParcelize(parcelizeAnnotations) || declaration.modality == Modality.SEALED)
|
||||||
return
|
return
|
||||||
|
|
||||||
val parcelableProperties = declaration.parcelableProperties
|
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.IrGenerationExtension
|
||||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
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) {
|
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
|
||||||
val androidSymbols = AndroidSymbols(pluginContext, moduleFragment)
|
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)
|
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||||
class ParcelizeIrTransformer(
|
class ParcelizeIrTransformer(
|
||||||
context: IrPluginContext,
|
context: IrPluginContext,
|
||||||
androidSymbols: AndroidSymbols
|
androidSymbols: AndroidSymbols,
|
||||||
) : ParcelizeIrTransformerBase(context, androidSymbols) {
|
parcelizeAnnotations: List<FqName>
|
||||||
|
) : ParcelizeIrTransformerBase(context, androidSymbols, parcelizeAnnotations) {
|
||||||
private val symbolMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
|
private val symbolMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||||
|
|
||||||
fun transform(moduleFragment: IrModuleFragment) {
|
fun transform(moduleFragment: IrModuleFragment) {
|
||||||
@@ -101,7 +102,7 @@ class ParcelizeIrTransformer(
|
|||||||
|
|
||||||
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
// Sealed classes can be annotated with `@Parcelize`, but that only implies that we
|
||||||
// should process their immediate subclasses.
|
// should process their immediate subclasses.
|
||||||
if (!declaration.isParcelize || declaration.modality == Modality.SEALED)
|
if (!declaration.isParcelize(parcelizeAnnotations) || declaration.modality == Modality.SEALED)
|
||||||
return
|
return
|
||||||
|
|
||||||
val parcelableProperties = declaration.parcelableProperties
|
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.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATE_FROM_PARCEL_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.CREATOR_NAME
|
||||||
@@ -27,7 +28,8 @@ import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
|
|||||||
|
|
||||||
abstract class ParcelizeIrTransformerBase(
|
abstract class ParcelizeIrTransformerBase(
|
||||||
protected val context: IrPluginContext,
|
protected val context: IrPluginContext,
|
||||||
protected val androidSymbols: AndroidSymbols
|
protected val androidSymbols: AndroidSymbols,
|
||||||
|
protected val parcelizeAnnotations: List<FqName>
|
||||||
) : ParcelizeExtensionBase, IrElementVisitorVoid {
|
) : ParcelizeExtensionBase, IrElementVisitorVoid {
|
||||||
private val irFactory: IrFactory = IrFactoryImpl
|
private val irFactory: IrFactory = IrFactoryImpl
|
||||||
|
|
||||||
@@ -173,7 +175,7 @@ abstract class ParcelizeIrTransformerBase(
|
|||||||
val parceler by lazy(parcelerThunk)
|
val parceler by lazy(parcelerThunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val serializerFactory = IrParcelSerializerFactory(androidSymbols)
|
private val serializerFactory = IrParcelSerializerFactory(androidSymbols, parcelizeAnnotations)
|
||||||
|
|
||||||
protected val IrClass.parcelableProperties: List<ParcelableProperty?>
|
protected val IrClass.parcelableProperties: List<ParcelableProperty?>
|
||||||
get() {
|
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.NEW_ARRAY_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_FQN
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_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.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
|
import org.jetbrains.kotlin.parcelize.serializers.ParcelizeExtensionBase
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
// true if the class should be processed by the parcelize plugin
|
// true if the class should be processed by the parcelize plugin
|
||||||
val IrClass.isParcelize: Boolean
|
fun IrClass.isParcelize(parcelizeAnnotations: List<FqName>): Boolean =
|
||||||
get() = kind in ParcelizeExtensionBase.ALLOWED_CLASS_KINDS &&
|
kind in ParcelizeExtensionBase.ALLOWED_CLASS_KINDS &&
|
||||||
(hasAnyAnnotation(PARCELIZE_CLASS_FQ_NAMES) || superTypes.any { superType ->
|
(hasAnyAnnotation(parcelizeAnnotations) || superTypes.any { superType ->
|
||||||
superType.classOrNull?.owner?.let {
|
superType.classOrNull?.owner?.let {
|
||||||
it.modality == Modality.SEALED && it.hasAnyAnnotation(PARCELIZE_CLASS_FQ_NAMES)
|
it.modality == Modality.SEALED && it.hasAnyAnnotation(parcelizeAnnotations)
|
||||||
} == true
|
} == 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.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
|
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.parcelize.fir.FirParcelizeExtensionRegistrar
|
import org.jetbrains.kotlin.parcelize.fir.FirParcelizeExtensionRegistrar
|
||||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
@@ -21,35 +22,44 @@ import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
|||||||
|
|
||||||
class ParcelizeComponentRegistrar : CompilerPluginRegistrar() {
|
class ParcelizeComponentRegistrar : CompilerPluginRegistrar() {
|
||||||
companion object {
|
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) {
|
if (useFir) {
|
||||||
IrGenerationExtension.registerExtension(ParcelizeFirIrGeneratorExtension())
|
IrGenerationExtension.registerExtension(ParcelizeFirIrGeneratorExtension(parcelizeAnnotations))
|
||||||
} else {
|
} else {
|
||||||
IrGenerationExtension.registerExtension(ParcelizeIrGeneratorExtension())
|
IrGenerationExtension.registerExtension(ParcelizeIrGeneratorExtension(parcelizeAnnotations))
|
||||||
}
|
}
|
||||||
SyntheticResolveExtension.registerExtension(ParcelizeResolveExtension())
|
SyntheticResolveExtension.registerExtension(ParcelizeResolveExtension(parcelizeAnnotations))
|
||||||
StorageComponentContainerContributor.registerExtension(ParcelizeDeclarationCheckerComponentContainerContributor())
|
StorageComponentContainerContributor.registerExtension(ParcelizeDeclarationCheckerComponentContainerContributor(parcelizeAnnotations))
|
||||||
FirExtensionRegistrarAdapter.registerExtension(FirParcelizeExtensionRegistrar())
|
FirExtensionRegistrarAdapter.registerExtension(FirParcelizeExtensionRegistrar(parcelizeAnnotations))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
|
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
|
override val supportsK2: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParcelizeDeclarationCheckerComponentContainerContributor : StorageComponentContainerContributor {
|
class ParcelizeDeclarationCheckerComponentContainerContributor(
|
||||||
|
private val parcelizeAnnotations: List<FqName>
|
||||||
|
) : StorageComponentContainerContributor {
|
||||||
override fun registerModuleComponents(
|
override fun registerModuleComponents(
|
||||||
container: StorageComponentContainer,
|
container: StorageComponentContainer,
|
||||||
platform: TargetPlatform,
|
platform: TargetPlatform,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor,
|
||||||
) {
|
) {
|
||||||
if (platform.isJvm()) {
|
if (platform.isJvm()) {
|
||||||
container.useInstance(ParcelizeDeclarationChecker())
|
container.useInstance(ParcelizeDeclarationChecker(parcelizeAnnotations))
|
||||||
container.useInstance(ParcelizeAnnotationChecker())
|
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 --------------------
|
// -------------------- 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 PARCEL_ID = ClassId(FqName("android.os"), Name.identifier("Parcel"))
|
||||||
val PARCELABLE_ID = ClassId(FqName("android.os"), Name.identifier("Parcelable"))
|
val PARCELABLE_ID = ClassId(FqName("android.os"), Name.identifier("Parcelable"))
|
||||||
val CREATOR_ID = PARCELABLE_ID.createNestedClassId(Name.identifier("Creator"))
|
val CREATOR_ID = PARCELABLE_ID.createNestedClassId(Name.identifier("Creator"))
|
||||||
@@ -38,8 +36,6 @@ object ParcelizeNames {
|
|||||||
|
|
||||||
// -------------------- FQNs --------------------
|
// -------------------- FQNs --------------------
|
||||||
|
|
||||||
val PARCELIZE_FQN = PARCELIZE_ID.asSingleFqName()
|
|
||||||
val OLD_PARCELIZE_FQN = OLD_PARCELIZE_ID.asSingleFqName()
|
|
||||||
val PARCELABLE_FQN = PARCELABLE_ID.asSingleFqName()
|
val PARCELABLE_FQN = PARCELABLE_ID.asSingleFqName()
|
||||||
val CREATOR_FQN = CREATOR_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.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.containingPackage
|
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.DEPRECATED_RUNTIME_PACKAGE
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.IGNORED_ON_PARCEL_FQ_NAMES
|
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.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.RAW_VALUE_ANNOTATION_FQ_NAMES
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.TYPE_PARCELER_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.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.replaceAnnotations
|
||||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
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) {
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
val constructorDescriptor = resolvedCall.resultingDescriptor as? ClassConstructorDescriptor ?: return
|
val constructorDescriptor = resolvedCall.resultingDescriptor as? ClassConstructorDescriptor ?: return
|
||||||
val annotationClass = constructorDescriptor.constructedClass.takeIf { it.kind == ClassKind.ANNOTATION_CLASS } ?: 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)
|
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)
|
checkDeprecatedAnnotations(resolvedCall, annotationEntry, context, isForbidden = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ open class ParcelizeAnnotationChecker : CallChecker {
|
|||||||
) {
|
) {
|
||||||
if (containingClass != null) {
|
if (containingClass != null) {
|
||||||
val containingClassDescriptor = context.trace[BindingContext.CLASS, containingClass]
|
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
|
val reportElement = (annotationEntry.typeReference?.typeElement as? KtUserType)?.referenceExpression ?: annotationEntry
|
||||||
context.trace.report(ErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE.on(reportElement, containingClass))
|
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.representativeUpperBound
|
||||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||||
|
|
||||||
open class ParcelizeDeclarationChecker : DeclarationChecker {
|
open class ParcelizeDeclarationChecker(val parcelizeAnnotations: List<FqName>) : DeclarationChecker {
|
||||||
private companion object {
|
private companion object {
|
||||||
private val IGNORED_ON_PARCEL_FQ_NAMES = listOf(
|
private val IGNORED_ON_PARCEL_FQ_NAMES = listOf(
|
||||||
FqName("kotlinx.parcelize.IgnoredOnParcel"),
|
FqName("kotlinx.parcelize.IgnoredOnParcel"),
|
||||||
@@ -71,7 +71,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
|||||||
declaration: KtFunction,
|
declaration: KtFunction,
|
||||||
diagnosticHolder: DiagnosticSink
|
diagnosticHolder: DiagnosticSink
|
||||||
) {
|
) {
|
||||||
if (!containingClass.isParcelize) {
|
if (!containingClass.isParcelize(parcelizeAnnotations)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
|||||||
return property.annotations.hasIgnoredOnParcel() || (property.getter?.annotations?.hasIgnoredOnParcel() ?: false)
|
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)
|
&& (declaration.hasDelegate() || bindingContext[BindingContext.BACKING_FIELD_REQUIRED, property] == true)
|
||||||
&& !hasIgnoredOnParcel()
|
&& !hasIgnoredOnParcel()
|
||||||
&& !containingClass.hasCustomParceler()
|
&& !containingClass.hasCustomParceler()
|
||||||
@@ -109,7 +109,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
|||||||
// @JvmName is not applicable to property so we can check just the descriptor name
|
// @JvmName is not applicable to property so we can check just the descriptor name
|
||||||
if (property.name.asString() == "CREATOR" && property.findJvmFieldAnnotation() != null && containingClass.isCompanionObject) {
|
if (property.name.asString() == "CREATOR" && property.findJvmFieldAnnotation() != null && containingClass.isCompanionObject) {
|
||||||
val outerClass = containingClass.containingDeclaration as? ClassDescriptor
|
val outerClass = containingClass.containingDeclaration as? ClassDescriptor
|
||||||
if (outerClass != null && outerClass.isParcelize) {
|
if (outerClass != null && outerClass.isParcelize(parcelizeAnnotations)) {
|
||||||
val reportElement = declaration.nameIdentifier ?: declaration
|
val reportElement = declaration.nameIdentifier ?: declaration
|
||||||
diagnosticHolder.report(ErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED.on(reportElement))
|
diagnosticHolder.report(ErrorsParcelize.CREATOR_DEFINITION_IS_NOT_ALLOWED.on(reportElement))
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@ open class ParcelizeDeclarationChecker : DeclarationChecker {
|
|||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
if (!descriptor.isParcelize) {
|
if (!descriptor.isParcelize(parcelizeAnnotations)) {
|
||||||
return
|
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.DESCRIBE_CONTENTS_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.NEW_ARRAY_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_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.PARCEL_ID
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCEL_ID
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
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.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.ErrorTypeKind
|
||||||
import org.jetbrains.kotlin.types.error.ErrorUtils
|
import org.jetbrains.kotlin.types.error.ErrorUtils
|
||||||
|
|
||||||
open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
open class ParcelizeResolveExtension(private val parcelizeAnnotations: List<FqName>) : SyntheticResolveExtension {
|
||||||
companion object {
|
companion object {
|
||||||
fun resolveParcelClassType(module: ModuleDescriptor): SimpleType? {
|
fun resolveParcelClassType(module: ModuleDescriptor): SimpleType? {
|
||||||
return module.findClassAcrossModuleDependencies(PARCEL_ID)?.defaultType
|
return module.findClassAcrossModuleDependencies(PARCEL_ID)?.defaultType
|
||||||
@@ -107,7 +106,7 @@ open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
|||||||
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? = null
|
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? = null
|
||||||
|
|
||||||
override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> {
|
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(
|
override fun generateSyntheticMethods(
|
||||||
@@ -123,7 +122,7 @@ open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name.asString() == DESCRIBE_CONTENTS.methodName
|
if (name.asString() == DESCRIBE_CONTENTS.methodName
|
||||||
&& thisDescriptor.isParcelize
|
&& thisDescriptor.isParcelize(parcelizeAnnotations)
|
||||||
&& !thisDescriptor.isSealed()
|
&& !thisDescriptor.isSealed()
|
||||||
&& isParcelizePluginEnabled()
|
&& isParcelizePluginEnabled()
|
||||||
&& result.none { it.isDescribeContents() }
|
&& result.none { it.isDescribeContents() }
|
||||||
@@ -131,7 +130,7 @@ open class ParcelizeResolveExtension : SyntheticResolveExtension {
|
|||||||
) {
|
) {
|
||||||
result += createMethod(thisDescriptor, DESCRIBE_CONTENTS, Modality.OPEN, thisDescriptor.builtIns.intType)
|
result += createMethod(thisDescriptor, DESCRIBE_CONTENTS, Modality.OPEN, thisDescriptor.builtIns.intType)
|
||||||
} else if (name.asString() == WRITE_TO_PARCEL.methodName
|
} else if (name.asString() == WRITE_TO_PARCEL.methodName
|
||||||
&& thisDescriptor.isParcelize
|
&& thisDescriptor.isParcelize(parcelizeAnnotations)
|
||||||
&& !thisDescriptor.isSealed()
|
&& !thisDescriptor.isSealed()
|
||||||
&& isParcelizePluginEnabled()
|
&& isParcelizePluginEnabled()
|
||||||
&& result.none { it.isWriteToParcel() }
|
&& result.none { it.isWriteToParcel() }
|
||||||
@@ -173,13 +172,13 @@ interface ParcelizeSyntheticComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ClassDescriptor.hasParcelizeAnnotation: Boolean
|
fun ClassDescriptor.hasParcelizeAnnotation(parcelizeAnnotations: List<FqName>): Boolean =
|
||||||
get() = PARCELIZE_CLASS_FQ_NAMES.any(annotations::hasAnnotation)
|
parcelizeAnnotations.any(annotations::hasAnnotation)
|
||||||
|
|
||||||
val ClassDescriptor.isParcelize: Boolean
|
fun ClassDescriptor.isParcelize(parcelizeAnnotations: List<FqName>): Boolean =
|
||||||
get() = hasParcelizeAnnotation
|
hasParcelizeAnnotation(parcelizeAnnotations)
|
||||||
|| getSuperClassNotAny()?.takeIf(DescriptorUtils::isSealedClass)?.hasParcelizeAnnotation == true
|
|| getSuperClassNotAny()?.takeIf(DescriptorUtils::isSealedClass)?.hasParcelizeAnnotation(parcelizeAnnotations) == true
|
||||||
|| getSuperInterfaces().any { DescriptorUtils.isSealedClass(it) && it.hasParcelizeAnnotation }
|
|| getSuperInterfaces().any { DescriptorUtils.isSealedClass(it) && it.hasParcelizeAnnotation(parcelizeAnnotations) }
|
||||||
|
|
||||||
val KotlinType.isParceler: Boolean
|
val KotlinType.isParceler: Boolean
|
||||||
get() = constructor.declarationDescriptor?.fqNameSafe == PARCELER_FQN
|
get() = constructor.declarationDescriptor?.fqNameSafe == PARCELER_FQN
|
||||||
|
|||||||
+2
-1
@@ -38,6 +38,7 @@ interface ParcelSerializer {
|
|||||||
fun readValue(v: InstructionAdapter)
|
fun readValue(v: InstructionAdapter)
|
||||||
|
|
||||||
data class ParcelSerializerContext(
|
data class ParcelSerializerContext(
|
||||||
|
val parcelizeAnnotations: List<FqName>,
|
||||||
val typeMapper: KotlinTypeMapper,
|
val typeMapper: KotlinTypeMapper,
|
||||||
val containerClassType: Type,
|
val containerClassType: Type,
|
||||||
val typeParcelers: List<TypeParcelerMapping>,
|
val typeParcelers: List<TypeParcelerMapping>,
|
||||||
@@ -344,7 +345,7 @@ interface ParcelSerializer {
|
|||||||
|
|
||||||
val creatorAsmType = when {
|
val creatorAsmType = when {
|
||||||
creatorVar != null -> typeMapper.mapTypeSafe(creatorVar.type, forceBoxed = true)
|
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
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -36,7 +36,8 @@ interface ParcelizeExtensionBase {
|
|||||||
.isNotEmpty()
|
.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)
|
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.ExpressionCheckers
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
|
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.*
|
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 expressionCheckers: ExpressionCheckers = object : ExpressionCheckers() {
|
||||||
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
||||||
get() = setOf(FirParcelizeAnnotationChecker)
|
get() = setOf(FirParcelizeAnnotationChecker(parcelizeAnnotations))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() {
|
override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() {
|
||||||
override val classCheckers: Set<FirClassChecker>
|
override val classCheckers: Set<FirClassChecker>
|
||||||
get() = setOf(FirParcelizeClassChecker)
|
get() = setOf(FirParcelizeClassChecker(parcelizeAnnotations))
|
||||||
|
|
||||||
override val propertyCheckers: Set<FirPropertyChecker>
|
override val propertyCheckers: Set<FirPropertyChecker>
|
||||||
get() = setOf(FirParcelizePropertyChecker)
|
get() = setOf(FirParcelizePropertyChecker(parcelizeAnnotations))
|
||||||
|
|
||||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||||
get() = setOf(FirParcelizeFunctionChecker)
|
get() = setOf(FirParcelizeFunctionChecker(parcelizeAnnotations))
|
||||||
|
|
||||||
override val constructorCheckers: Set<FirConstructorChecker>
|
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.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DESCRIBE_CONTENTS_NAME
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DESCRIBE_CONTENTS_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DEST_NAME
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DEST_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.FLAGS_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.PARCEL_ID
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_TO_PARCEL_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.fir.diagnostics.checkParcelizeClassSymbols
|
import org.jetbrains.kotlin.parcelize.fir.diagnostics.checkParcelizeClassSymbols
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
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 {
|
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 parcelizeMethodsNames = setOf(DESCRIBE_CONTENTS_NAME, WRITE_TO_PARCEL_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val predicate = LookupPredicate.create { annotated(annotations) }
|
||||||
|
|
||||||
private val matchedClasses by lazy {
|
private val matchedClasses by lazy {
|
||||||
session.predicateBasedProvider.getSymbolsByPredicate(PREDICATE)
|
session.predicateBasedProvider.getSymbolsByPredicate(predicate)
|
||||||
.filterIsInstance<FirRegularClassSymbol>()
|
.filterIsInstance<FirRegularClassSymbol>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +119,6 @@ class FirParcelizeDeclarationGenerator(session: FirSession) : FirDeclarationGene
|
|||||||
get() = ParcelizePluginKey
|
get() = ParcelizePluginKey
|
||||||
|
|
||||||
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||||
register(PREDICATE)
|
register(predicate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -6,10 +6,12 @@
|
|||||||
package org.jetbrains.kotlin.parcelize.fir
|
package org.jetbrains.kotlin.parcelize.fir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
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() {
|
override fun ExtensionRegistrarContext.configurePlugin() {
|
||||||
+::FirParcelizeDeclarationGenerator
|
+::FirParcelizeDeclarationGenerator.bind(parcelizeAnnotationFqNames)
|
||||||
+::FirParcelizeCheckersExtension
|
+::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
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.DEPRECATED_RUNTIME_PACKAGE
|
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.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.RAW_VALUE_ANNOTATION_CLASS_IDS
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.TYPE_PARCELER_CLASS_IDS
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.TYPE_PARCELER_CLASS_IDS
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_WITH_CLASS_IDS
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.WRITE_WITH_CLASS_IDS
|
||||||
|
|
||||||
// TODO: extract common checker for expect interfaces
|
// 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) {
|
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val annotationType = expression.annotationTypeRef.coneType.fullyExpandedType(context.session) as? ConeClassLikeType ?: return
|
val annotationType = expression.annotationTypeRef.coneType.fullyExpandedType(context.session) as? ConeClassLikeType ?: return
|
||||||
val resolvedAnnotationSymbol = annotationType.lookupTag.toFirRegularClassSymbol(context.session) ?: return
|
val resolvedAnnotationSymbol = annotationType.lookupTag.toFirRegularClassSymbol(context.session) ?: return
|
||||||
@@ -47,7 +47,7 @@ object FirParcelizeAnnotationChecker : FirAnnotationCallChecker(MppCheckerKind.P
|
|||||||
in IGNORED_ON_PARCEL_CLASS_IDS -> {
|
in IGNORED_ON_PARCEL_CLASS_IDS -> {
|
||||||
checkDeprecatedAnnotations(expression, annotationClassId, context, reporter, isForbidden = false)
|
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)
|
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) {
|
private fun checkIfTheContainingClassIsParcelize(annotationCall: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val enclosingClass = context.findClosestClassOrObject() ?: return
|
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
|
val reportElement = annotationCall.calleeReference.source ?: annotationCall.source
|
||||||
reporter.reportOn(reportElement, KtErrorsParcelize.CLASS_SHOULD_BE_PARCELIZE, enclosingClass.symbol, context)
|
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.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_ID
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.OLD_PARCELER_ID
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_ID
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELABLE_ID
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_CLASS_IDS
|
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.ExperimentalContracts
|
||||||
import kotlin.contracts.contract
|
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) {
|
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
checkParcelableClass(declaration, context, reporter)
|
checkParcelableClass(declaration, context, reporter)
|
||||||
checkParcelerClass(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) {
|
private fun checkParcelableClass(klass: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val symbol = klass.symbol
|
val symbol = klass.symbol
|
||||||
if (!symbol.isParcelize(context.session)) return
|
if (!symbol.isParcelize(context.session, parcelizeAnnotations)) return
|
||||||
val source = klass.source ?: return
|
val source = klass.source ?: return
|
||||||
val classKind = klass.classKind
|
val classKind = klass.classKind
|
||||||
|
|
||||||
@@ -110,14 +110,14 @@ object FirParcelizeClassChecker : FirClassChecker(MppCheckerKind.Common) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalContracts::class)
|
@OptIn(ExperimentalContracts::class)
|
||||||
fun FirClassSymbol<*>?.isParcelize(session: FirSession): Boolean {
|
fun FirClassSymbol<*>?.isParcelize(session: FirSession, parcelizeAnnotations: List<ClassId>): Boolean {
|
||||||
contract {
|
contract {
|
||||||
returns(true) implies (this@isParcelize != null)
|
returns(true) implies (this@isParcelize != null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this == null) return false
|
if (this == null) return false
|
||||||
return checkParcelizeClassSymbols(this, session) { symbol ->
|
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.FirConstructor
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
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) {
|
override fun check(declaration: FirConstructor, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (!declaration.isPrimary) return
|
if (!declaration.isPrimary) return
|
||||||
val source = declaration.source ?: return
|
val source = declaration.source ?: return
|
||||||
if (source.kind == KtFakeSourceElementKind.ImplicitConstructor) return
|
if (source.kind == KtFakeSourceElementKind.ImplicitConstructor) return
|
||||||
val containingClass = context.containingDeclarations.last() as? FirRegularClass ?: return
|
val containingClass = context.containingDeclarations.last() as? FirRegularClass ?: return
|
||||||
val containingClassSymbol = containingClass.symbol
|
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()) {
|
if (declaration.valueParameters.isEmpty()) {
|
||||||
reporter.reportOn(containingClass.source, KtErrorsParcelize.PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY, context)
|
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.isInt
|
||||||
import org.jetbrains.kotlin.fir.types.isUnit
|
import org.jetbrains.kotlin.fir.types.isUnit
|
||||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
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) {
|
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(context.session)
|
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.origin != FirDeclarationOrigin.Source) return
|
||||||
if (declaration.isWriteToParcel() && declaration.isOverride) {
|
if (declaration.isWriteToParcel() && declaration.isOverride) {
|
||||||
reporter.reportOn(declaration.source, KtErrorsParcelize.OVERRIDING_WRITE_TO_PARCEL_IS_NOT_ALLOWED, context)
|
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.resolve.lookupSuperTypes
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.parcelize.BuiltinParcelableTypes
|
import org.jetbrains.kotlin.parcelize.BuiltinParcelableTypes
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
import org.jetbrains.kotlin.parcelize.ParcelizeNames
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.CREATOR_NAME
|
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.IGNORED_ON_PARCEL_CLASS_IDS
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeNames.PARCELER_ID
|
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) {
|
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val session = context.session
|
val session = context.session
|
||||||
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(session) ?: return
|
val containingClassSymbol = declaration.dispatchReceiverType?.toRegularClassSymbol(session) ?: return
|
||||||
|
|
||||||
if (containingClassSymbol.isParcelize(session)) {
|
if (containingClassSymbol.isParcelize(session, parcelizeAnnotations)) {
|
||||||
val fromPrimaryConstructor = declaration.fromPrimaryConstructor ?: false
|
val fromPrimaryConstructor = declaration.fromPrimaryConstructor ?: false
|
||||||
if (
|
if (
|
||||||
!fromPrimaryConstructor &&
|
!fromPrimaryConstructor &&
|
||||||
@@ -54,7 +55,7 @@ object FirParcelizePropertyChecker : FirPropertyChecker(MppCheckerKind.Common) {
|
|||||||
|
|
||||||
if (declaration.name == CREATOR_NAME && containingClassSymbol.isCompanion && declaration.hasJvmFieldAnnotation(session)) {
|
if (declaration.name == CREATOR_NAME && containingClassSymbol.isCompanion && declaration.hasJvmFieldAnnotation(session)) {
|
||||||
val outerClass = context.containingDeclarations.asReversed().getOrNull(1) as? FirRegularClass
|
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)
|
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.compiler.plugin.CompilerPluginRegistrar
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.parcelize.ParcelizeComponentRegistrar
|
import org.jetbrains.kotlin.parcelize.ParcelizeComponentRegistrar
|
||||||
|
import org.jetbrains.kotlin.parcelize.ParcelizeConfigurationKeys
|
||||||
import org.jetbrains.kotlin.parcelize.kotlinxImmutable
|
import org.jetbrains.kotlin.parcelize.kotlinxImmutable
|
||||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||||
import org.jetbrains.kotlin.test.model.TestModule
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
@@ -47,6 +48,11 @@ class ParcelizeEnvironmentConfigurator(testServices: TestServices) : Environment
|
|||||||
module: TestModule,
|
module: TestModule,
|
||||||
configuration: CompilerConfiguration
|
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