[FIR] Rework predicates system

Now predicates are split into LookupPredicate and DeclarationPredicate
  hierarchies. First one allows to perform global search for declarations
  and second one allows to check if some declaration matches the predicate.
Predicates with meta annotations are excluded from LookupPredicates,
  because it's impossible to create index of annotations with meta-annotations,
  because they can be located inside binary dependencies (so to achieve
  this we need to scan the whole classpath).
Also only one predicate with meta-annotations is left in DeclarationPredicate
  hierarchy (AnnotatedWithMeta)

^KT-53874 Fixed
^KT-53590 Fixed
This commit is contained in:
Dmitriy Novozhilov
2022-11-23 15:16:44 +02:00
committed by Space Team
parent 7a9a71a089
commit 246dc985a6
41 changed files with 934 additions and 605 deletions
@@ -9,11 +9,13 @@ import org.jetbrains.kotlin.fir.extensions.predicate.*
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 hasMetaAnnotation = metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName)
internal val annotatedWithSerializableOrMeta =
AnnotatedWith(setOf(SerializationAnnotations.serializableAnnotationFqName)) or metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName)
internal val serializerFor = DeclarationPredicate.create {
annotated(setOf(SerializationAnnotations.serializerAnnotationFqName)) // @Serializer(for=...)
}
internal val hasMetaAnnotation = DeclarationPredicate.create {
metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName)
}
internal val annotatedWithSerializableOrMeta = DeclarationPredicate.create {
annotated(setOf(SerializationAnnotations.serializableAnnotationFqName)) or metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName)
}
}
@@ -250,12 +250,6 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
return listOf(copy.symbol)
}
// FIXME: it seems that this list will always be used, why not provide it automatically?
private val matchedClasses by lazy {
session.predicateBasedProvider.getSymbolsByPredicate(FirSerializationPredicates.annotatedWithSerializableOrMeta)
.filterIsInstance<FirRegularClassSymbol>()
}
override fun generateConstructors(context: MemberGenerationContext): List<FirConstructorSymbol> {
val owner = context.owner
val defaultObjectConstructor = buildPrimaryConstructor(
@@ -291,10 +285,15 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
return listOf(defaultObjectConstructor.symbol)
}
fun addSerializerImplClass(
classId: ClassId
): FirClassLikeSymbol<*>? {
val owner = matchedClasses.firstOrNull { it.classId == classId.outerClassId } ?: return null
private fun getClassWithAnnotatedWithSerializableOrMeta(classId: ClassId?): FirRegularClassSymbol? {
if (classId == null) return null
return (session.symbolProvider.getClassLikeSymbolByClassId(classId) as? FirRegularClassSymbol)?.takeIf {
session.predicateBasedProvider.matches(FirSerializationPredicates.annotatedWithSerializableOrMeta, it)
}
}
fun addSerializerImplClass(classId: ClassId): FirClassLikeSymbol<*>? {
val owner = getClassWithAnnotatedWithSerializableOrMeta(classId.outerClassId) ?: return null
val hasTypeParams = owner.typeParameterSymbols.isNotEmpty()
val serializerKind = if (hasTypeParams) ClassKind.CLASS else ClassKind.OBJECT
val serializerFirClass = buildRegularClass {
@@ -332,7 +331,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene
fun generateCompanionDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
if (classId.shortClassName != SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT) return null
val owner = matchedClasses.firstOrNull { it.classId == classId.outerClassId } ?: return null
val owner = getClassWithAnnotatedWithSerializableOrMeta(classId.outerClassId) ?: return null
if (owner.companionObjectSymbol != null) return null
val regularClass = buildRegularClass {
moduleData = session.moduleData