Extract predicates to separate file, apply other review suggestions
This commit is contained in:
+1
-1
@@ -121,7 +121,7 @@ private class AndroidIrTransformer(val extension: AndroidIrExtension, val plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: sparse array version intentionally not implemented; this plugin is deprecated
|
// NOTE: sparse array version intentionally not implemented; this plugin is deprecated
|
||||||
@OptIn(FirIncompatiblePluginAPI::class) // TODO: check that it still works with FIR
|
@OptIn(FirIncompatiblePluginAPI::class)
|
||||||
private val mapFactory = pluginContext.referenceFunctions(FqName("kotlin.collections.mutableMapOf"))
|
private val mapFactory = pluginContext.referenceFunctions(FqName("kotlin.collections.mutableMapOf"))
|
||||||
.single { it.owner.valueParameters.isEmpty() }
|
.single { it.owner.valueParameters.isEmpty() }
|
||||||
private val mapGet = pluginContext.irBuiltIns.mapClass.owner.functions
|
private val mapGet = pluginContext.irBuiltIns.mapClass.owner.functions
|
||||||
|
|||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.predicate.AnnotatedWith
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.predicate.ancestorAnnotated
|
||||||
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
|
|
||||||
|
object FirSerializationPredicates {
|
||||||
|
internal val serializerFor: DeclarationPredicate =
|
||||||
|
AnnotatedWith(setOf(SerializationAnnotations.serializerAnnotationFqName)) // @Serializer(for=...)
|
||||||
|
internal val generatedSerializer: DeclarationPredicate =
|
||||||
|
ancestorAnnotated(SerializationAnnotations.serializableAnnotationFqName) // @Serializable X.$serializer
|
||||||
|
internal val annotatedWithSerializable = AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName))
|
||||||
|
}
|
||||||
+9
-39
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.moduleData
|
|||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.typeWithStarProjections
|
||||||
import org.jetbrains.kotlin.fir.scopes.*
|
import org.jetbrains.kotlin.fir.scopes.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
@@ -56,7 +57,6 @@ val kSerializerClassId = ClassId(SerializationPackages.packageFqName, SerialEnti
|
|||||||
|
|
||||||
class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||||
|
|
||||||
// FIXME: I can't check status here
|
|
||||||
override fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> {
|
override fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||||
val result = mutableSetOf<Name>()
|
val result = mutableSetOf<Name>()
|
||||||
if (classSymbol.shouldHaveGeneratedMethodsInCompanion && !classSymbol.isSerializableObject)
|
if (classSymbol.shouldHaveGeneratedMethodsInCompanion && !classSymbol.isSerializableObject)
|
||||||
@@ -65,22 +65,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
result += SerialEntityNames.SERIALIZER_CLASS_NAME
|
result += SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* It's not documented how these classes relate with getCallableNamesForClass
|
|
||||||
* Document says:
|
|
||||||
* 1.> If you generate some class using generateClassLikeDeclaration then you don't need to fill it's declarations.
|
|
||||||
* Q: Don't need or MUSTN'T?
|
|
||||||
*
|
|
||||||
* 2. > Instead of that you need to generate members via generateProperties/Functions/Constructors methods
|
|
||||||
* of same generation extension (this is important note if you have multiple generation extensions in your plugin)
|
|
||||||
*
|
|
||||||
* Q: Does this mean that for e.g. generated companion `generateFunctions` will be called regardless of provided predicate?
|
|
||||||
*
|
|
||||||
* 3. This method is stated to be called on SUPERTYPES, but getNestedClassifiersNames stated to be called after SUPERTYPES. How is this possible?
|
|
||||||
*
|
|
||||||
* 4. It is should be mentioned that supertypes for generated class should be added here,
|
|
||||||
* while supertypes for exisiting classes — in separate extension
|
|
||||||
*/
|
|
||||||
override fun generateClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
|
override fun generateClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||||
return when (classId.shortClassName) {
|
return when (classId.shortClassName) {
|
||||||
SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT -> {
|
SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT -> {
|
||||||
@@ -93,17 +78,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. It is unclear that for `generateConstructors` to work, one need to return SpecialNames.INIT from here
|
|
||||||
* 1a. Also it is unclear that objects need constructors too.
|
|
||||||
*
|
|
||||||
* 2. If it is a user-written companion object, will I get here? Why?
|
|
||||||
*
|
|
||||||
* 3. Is it supposed to check that classSymbol does not already have same Name? How to add a generated overload?
|
|
||||||
*
|
|
||||||
* 4. It is unclear what to do with properties
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||||
val classId = classSymbol.classId
|
val classId = classSymbol.classId
|
||||||
val result = mutableSetOf<Name>()
|
val result = mutableSetOf<Name>()
|
||||||
@@ -124,7 +99,6 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
SpecialNames.INIT,
|
SpecialNames.INIT,
|
||||||
SerialEntityNames.SAVE_NAME,
|
SerialEntityNames.SAVE_NAME,
|
||||||
SerialEntityNames.LOAD_NAME,
|
SerialEntityNames.LOAD_NAME,
|
||||||
// FIXME: correctly create property?
|
|
||||||
SerialEntityNames.SERIAL_DESC_FIELD_NAME
|
SerialEntityNames.SERIAL_DESC_FIELD_NAME
|
||||||
)
|
)
|
||||||
if (classSymbol.superConeTypes.any {
|
if (classSymbol.superConeTypes.any {
|
||||||
@@ -147,7 +121,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
@OptIn(SymbolInternals::class)
|
||||||
private fun <T> getFromSupertype(callableId: CallableId, owner: FirClassSymbol<*>, extractor: (FirTypeScope) -> List<T>): T {
|
private fun <T> getFromSupertype(callableId: CallableId, owner: FirClassSymbol<*>, extractor: (FirTypeScope) -> List<T>): T {
|
||||||
val scopeSession = ScopeSession() // ????????
|
val scopeSession = ScopeSession()
|
||||||
val scopes = lookupSuperTypes(
|
val scopes = lookupSuperTypes(
|
||||||
owner, lookupInterfaces = true, deep = false, useSiteSession = session
|
owner, lookupInterfaces = true, deep = false, useSiteSession = session
|
||||||
).mapNotNull { useSiteSuperType ->
|
).mapNotNull { useSiteSuperType ->
|
||||||
@@ -240,7 +214,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
|
|
||||||
// FIXME: it seems that this list will always be used, why not provide it automatically?
|
// FIXME: it seems that this list will always be used, why not provide it automatically?
|
||||||
private val matchedClasses by lazy {
|
private val matchedClasses by lazy {
|
||||||
session.predicateBasedProvider.getSymbolsByPredicate(AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName)))
|
session.predicateBasedProvider.getSymbolsByPredicate(FirSerializationPredicates.annotatedWithSerializable)
|
||||||
.filterIsInstance<FirRegularClassSymbol>()
|
.filterIsInstance<FirRegularClassSymbol>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +241,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
EffectiveVisibility.Public
|
EffectiveVisibility.Public
|
||||||
)
|
)
|
||||||
// FIXME: how to create annotations?
|
// TODO: add deprecate hidden
|
||||||
// annotations = listOf(Annotations.create(listOf(KSerializerDescriptorResolver.createDeprecatedHiddenAnnotation(thisDescriptor.module))))
|
// annotations = listOf(Annotations.create(listOf(KSerializerDescriptorResolver.createDeprecatedHiddenAnnotation(thisDescriptor.module))))
|
||||||
|
|
||||||
|
|
||||||
@@ -286,11 +260,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
})
|
})
|
||||||
|
|
||||||
superTypeRefs += buildResolvedTypeRef {
|
superTypeRefs += buildResolvedTypeRef {
|
||||||
// FIXME: document how one gets type ref from FirClass
|
@OptIn(SymbolInternals::class)
|
||||||
// is this a correct one or should I go with buildTypeProjectionWithVariance ?
|
type = generatedSerializerClassId.constructClassLikeType(arrayOf(owner.fir.typeWithStarProjections()), isNullable = false)
|
||||||
// is this a correct place to add supertypes to synthetic declarations? Looks like FirSupertypesExtension does not see class.
|
|
||||||
// It seems that this code generates KSerializer<Box<[declared type param of Box]>> instead of KSerializer<Box<*>>, but it didn't matter for old FE
|
|
||||||
type = generatedSerializerClassId.constructClassLikeType(arrayOf(owner.defaultType().toTypeProjection(Variance.INVARIANT)), isNullable = false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: add typed constructor
|
// TODO: add typed constructor
|
||||||
@@ -333,7 +304,6 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||||
// No predicate on final/open etc
|
register(FirSerializationPredicates.annotatedWithSerializable)
|
||||||
register(AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-37
@@ -7,44 +7,23 @@ package org.jetbrains.kotlinx.serialization.compiler.fir
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
|
||||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
|
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
|
||||||
import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension
|
import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension
|
||||||
import org.jetbrains.kotlin.fir.extensions.predicate.*
|
|
||||||
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
|
|
||||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
|
|
||||||
import org.jetbrains.kotlin.fir.types.classId
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
import org.jetbrains.kotlin.fir.types.constructClassLikeType
|
|
||||||
import org.jetbrains.kotlin.fir.types.toTypeProjection
|
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlinx.serialization.compiler.fir.FirSerializationPredicates.serializerFor
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||||
|
|
||||||
class SerializationFirSupertypesExtension(session: FirSession) : FirSupertypeGenerationExtension(session) {
|
class SerializationFirSupertypesExtension(session: FirSession) : FirSupertypeGenerationExtension(session) {
|
||||||
companion object {
|
|
||||||
private val serializerFor: DeclarationPredicate =
|
|
||||||
AnnotatedWith(setOf(SerializationAnnotations.serializerAnnotationFqName)) // @Serializer(for=...)
|
|
||||||
private val generatedSerializer: DeclarationPredicate =
|
|
||||||
ancestorAnnotated(SerializationAnnotations.serializableAnnotationFqName) // @Serializable X.$serializer
|
|
||||||
private val PREDICATE = serializerFor or generatedSerializer
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun needTransformSupertypes(declaration: FirClassLikeDeclaration): Boolean =
|
override fun needTransformSupertypes(declaration: FirClassLikeDeclaration): Boolean =
|
||||||
session.predicateBasedProvider.matches(serializerFor, declaration)
|
session.predicateBasedProvider.matches(serializerFor, declaration)
|
||||||
|| ( // TODO: this part is not working
|
|
||||||
session.predicateBasedProvider.matches(generatedSerializer, declaration)
|
|
||||||
&& declaration is FirRegularClass
|
|
||||||
&& declaration.name == SerialEntityNames.SERIALIZER_CLASS_NAME
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||||
register(PREDICATE)
|
register(serializerFor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun computeAdditionalSupertypes(
|
override fun computeAdditionalSupertypes(
|
||||||
@@ -56,20 +35,8 @@ class SerializationFirSupertypesExtension(session: FirSession) : FirSupertypeGen
|
|||||||
if (resolvedSupertypes.any { it.type.classId == kSerializerClassId || it.type.classId == generatedSerializerClassId }) return emptyList()
|
if (resolvedSupertypes.any { it.type.classId == kSerializerClassId || it.type.classId == generatedSerializerClassId }) return emptyList()
|
||||||
|
|
||||||
|
|
||||||
if (session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration)) {
|
return if (session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration)) {
|
||||||
TODO("Support @Serializer(for=...) supertype generation")
|
TODO("Support @Serializer(for=...) supertype generation")
|
||||||
} else {
|
} else emptyList()
|
||||||
// TODO: Remove this section as it is not working because one should add supertype for generated class where this class is created.
|
|
||||||
// @Serializable X.$serializer
|
|
||||||
val parent = (classLikeDeclaration.getContainingDeclaration(session) as? FirRegularClass)
|
|
||||||
?: error("Generated serializer $classLikeDeclaration is not contained in any class")
|
|
||||||
|
|
||||||
return listOf(buildResolvedTypeRef {
|
|
||||||
// FIXME: document how one gets type ref from FirClass
|
|
||||||
// FIXME: is this a correct one or should I go with buildTypeProjectionWithVariance ?
|
|
||||||
// It seems that this code generates KSerializer<Box<[declared type param]>> instead of KSerializer<Box<*>>, but it didn't matter for old FE
|
|
||||||
type = generatedSerializerClassId.constructClassLikeType(arrayOf(parent.defaultType().toTypeProjection(Variance.INVARIANT)), isNullable = false)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-3
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||||
|
|
||||||
// FIXME: why FirAnnotation.classId.asSingleFqName is available, but FirAnnotation.fqName() requires FirSession?
|
|
||||||
internal val FirClassSymbol<*>.hasSerializableAnnotation
|
internal val FirClassSymbol<*>.hasSerializableAnnotation
|
||||||
get() = this.annotations.any {
|
get() = this.annotations.any {
|
||||||
it.classId?.asSingleFqName()?.asString() == SerializationAnnotations.serializableAnnotationFqName.asString()
|
it.classId?.asSingleFqName()?.asString() == SerializationAnnotations.serializableAnnotationFqName.asString()
|
||||||
@@ -56,9 +55,8 @@ internal fun FirClassSymbol<*>.isInternallySerializableEnum(): Boolean =
|
|||||||
internal val FirClassSymbol<*>.shouldHaveGeneratedSerializer: Boolean
|
internal val FirClassSymbol<*>.shouldHaveGeneratedSerializer: Boolean
|
||||||
get() = (isInternalSerializable && isFinalOrOpen()) || isInternallySerializableEnum()
|
get() = (isInternalSerializable && isFinalOrOpen()) || isInternallySerializableEnum()
|
||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
|
||||||
private fun FirClassSymbol<*>.isFinalOrOpen(): Boolean {
|
private fun FirClassSymbol<*>.isFinalOrOpen(): Boolean {
|
||||||
val modality = fir.status.modality
|
val modality = rawStatus.modality
|
||||||
// null means default modality, final
|
// null means default modality, final
|
||||||
return (modality == null || modality == Modality.FINAL || modality == Modality.OPEN)
|
return (modality == null || modality == Modality.FINAL || modality == Modality.OPEN)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user