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
|
||||
@OptIn(FirIncompatiblePluginAPI::class) // TODO: check that it still works with FIR
|
||||
@OptIn(FirIncompatiblePluginAPI::class)
|
||||
private val mapFactory = pluginContext.referenceFunctions(FqName("kotlin.collections.mutableMapOf"))
|
||||
.single { it.owner.valueParameters.isEmpty() }
|
||||
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.defaultType
|
||||
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.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
@@ -56,7 +57,6 @@ val kSerializerClassId = ClassId(SerializationPackages.packageFqName, SerialEnti
|
||||
|
||||
class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
|
||||
// FIXME: I can't check status here
|
||||
override fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
val result = mutableSetOf<Name>()
|
||||
if (classSymbol.shouldHaveGeneratedMethodsInCompanion && !classSymbol.isSerializableObject)
|
||||
@@ -65,22 +65,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
result += SerialEntityNames.SERIALIZER_CLASS_NAME
|
||||
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<*>? {
|
||||
return when (classId.shortClassName) {
|
||||
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> {
|
||||
val classId = classSymbol.classId
|
||||
val result = mutableSetOf<Name>()
|
||||
@@ -124,7 +99,6 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
SpecialNames.INIT,
|
||||
SerialEntityNames.SAVE_NAME,
|
||||
SerialEntityNames.LOAD_NAME,
|
||||
// FIXME: correctly create property?
|
||||
SerialEntityNames.SERIAL_DESC_FIELD_NAME
|
||||
)
|
||||
if (classSymbol.superConeTypes.any {
|
||||
@@ -147,7 +121,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
private fun <T> getFromSupertype(callableId: CallableId, owner: FirClassSymbol<*>, extractor: (FirTypeScope) -> List<T>): T {
|
||||
val scopeSession = ScopeSession() // ????????
|
||||
val scopeSession = ScopeSession()
|
||||
val scopes = lookupSuperTypes(
|
||||
owner, lookupInterfaces = true, deep = false, useSiteSession = session
|
||||
).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?
|
||||
private val matchedClasses by lazy {
|
||||
session.predicateBasedProvider.getSymbolsByPredicate(AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName)))
|
||||
session.predicateBasedProvider.getSymbolsByPredicate(FirSerializationPredicates.annotatedWithSerializable)
|
||||
.filterIsInstance<FirRegularClassSymbol>()
|
||||
}
|
||||
|
||||
@@ -267,7 +241,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
Modality.FINAL,
|
||||
EffectiveVisibility.Public
|
||||
)
|
||||
// FIXME: how to create annotations?
|
||||
// TODO: add deprecate hidden
|
||||
// annotations = listOf(Annotations.create(listOf(KSerializerDescriptorResolver.createDeprecatedHiddenAnnotation(thisDescriptor.module))))
|
||||
|
||||
|
||||
@@ -286,11 +260,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
})
|
||||
|
||||
superTypeRefs += buildResolvedTypeRef {
|
||||
// FIXME: document how one gets type ref from FirClass
|
||||
// is this a correct one or should I go with buildTypeProjectionWithVariance ?
|
||||
// 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)
|
||||
@OptIn(SymbolInternals::class)
|
||||
type = generatedSerializerClassId.constructClassLikeType(arrayOf(owner.fir.typeWithStarProjections()), isNullable = false)
|
||||
}
|
||||
}
|
||||
// TODO: add typed constructor
|
||||
@@ -333,7 +304,6 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
|
||||
}
|
||||
|
||||
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
|
||||
// No predicate on final/open etc
|
||||
register(AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName)))
|
||||
register(FirSerializationPredicates.annotatedWithSerializable)
|
||||
}
|
||||
}
|
||||
+4
-37
@@ -7,44 +7,23 @@ package org.jetbrains.kotlinx.serialization.compiler.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
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.FirSupertypeGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.predicate.*
|
||||
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.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
|
||||
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.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.SerializationAnnotations
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages
|
||||
|
||||
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 =
|
||||
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() {
|
||||
register(PREDICATE)
|
||||
register(serializerFor)
|
||||
}
|
||||
|
||||
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 (session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration)) {
|
||||
return if (session.predicateBasedProvider.matches(serializerFor, classLikeDeclaration)) {
|
||||
TODO("Support @Serializer(for=...) supertype generation")
|
||||
} else {
|
||||
// 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)
|
||||
})
|
||||
}
|
||||
} else emptyList()
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations
|
||||
|
||||
// FIXME: why FirAnnotation.classId.asSingleFqName is available, but FirAnnotation.fqName() requires FirSession?
|
||||
internal val FirClassSymbol<*>.hasSerializableAnnotation
|
||||
get() = this.annotations.any {
|
||||
it.classId?.asSingleFqName()?.asString() == SerializationAnnotations.serializableAnnotationFqName.asString()
|
||||
@@ -56,9 +55,8 @@ internal fun FirClassSymbol<*>.isInternallySerializableEnum(): Boolean =
|
||||
internal val FirClassSymbol<*>.shouldHaveGeneratedSerializer: Boolean
|
||||
get() = (isInternalSerializable && isFinalOrOpen()) || isInternallySerializableEnum()
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
private fun FirClassSymbol<*>.isFinalOrOpen(): Boolean {
|
||||
val modality = fir.status.modality
|
||||
val modality = rawStatus.modality
|
||||
// null means default modality, final
|
||||
return (modality == null || modality == Modality.FINAL || modality == Modality.OPEN)
|
||||
}
|
||||
Reference in New Issue
Block a user