[FIR] Change nested class generation extension to generate top-level classes also

This commit is contained in:
Dmitriy Novozhilov
2020-06-01 17:21:13 +03:00
parent 9cc13c8324
commit eceeacdf61
13 changed files with 186 additions and 98 deletions
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.fir.extensions.FirExtensionService import org.jetbrains.kotlin.fir.extensions.FirExtensionService
import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider
import org.jetbrains.kotlin.fir.extensions.FirRegisteredPluginAnnotations import org.jetbrains.kotlin.fir.extensions.FirRegisteredPluginAnnotations
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedNestedClassIndex import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClassIndex
import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider
import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache
@@ -19,5 +19,5 @@ fun FirSession.registerCommonComponents() {
register(FirExtensionService::class, FirExtensionService(this)) register(FirExtensionService::class, FirExtensionService(this))
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.create(this)) register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.create(this))
register(FirPredicateBasedProvider::class, FirPredicateBasedProvider.create(this)) register(FirPredicateBasedProvider::class, FirPredicateBasedProvider.create(this))
register(GeneratedNestedClassIndex::class, GeneratedNestedClassIndex.create()) register(GeneratedClassIndex::class, GeneratedClassIndex.create())
} }
@@ -9,14 +9,14 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedNestedClass import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClass
import kotlin.reflect.KClass import kotlin.reflect.KClass
/* /*
* TODO: * TODO:
* - check that annotations or meta-annotations is not empty * - check that annotations or meta-annotations is not empty
*/ */
abstract class FirExistingClassModificationExtension(session: FirSession) : FirPredicateBasedExtension(session) { abstract class FirDeclarationGenerationExtension(session: FirSession) : FirPredicateBasedExtension(session) {
companion object { companion object {
val NAME = FirExtensionPointName("ExistingClassModification") val NAME = FirExtensionPointName("ExistingClassModification")
} }
@@ -24,23 +24,23 @@ abstract class FirExistingClassModificationExtension(session: FirSession) : FirP
final override val name: FirExtensionPointName final override val name: FirExtensionPointName
get() = NAME get() = NAME
final override val extensionType: KClass<out FirExtension> = FirExistingClassModificationExtension::class final override val extensionType: KClass<out FirExtension> = FirDeclarationGenerationExtension::class
abstract fun generateNestedClasses( abstract fun generateClasses(
annotatedDeclaration: FirDeclaration, annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration> owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<FirRegularClass>> ): List<GeneratedDeclaration<FirRegularClass>>
abstract fun generateMembersForNestedClasses(generatedNestedClass: GeneratedNestedClass): List<FirDeclaration> abstract fun generateMembersForGeneratedClass(generatedClass: GeneratedClass): List<FirDeclaration>
abstract fun generateMembers( abstract fun generateMembers(
annotatedDeclaration: FirDeclaration, annotatedDeclaration: FirDeclaration,
owners: List<FirAnnotatedDeclaration> owners: List<FirAnnotatedDeclaration>
): List<GeneratedDeclaration<*>> ): List<GeneratedDeclaration<*>>
data class GeneratedDeclaration<out T : FirDeclaration>(val newDeclaration: T, val owner: FirRegularClass) data class GeneratedDeclaration<out T : FirDeclaration>(val newDeclaration: T, val owner: FirAnnotatedDeclaration)
fun interface Factory : FirExtension.Factory<FirExistingClassModificationExtension> fun interface Factory : FirExtension.Factory<FirDeclarationGenerationExtension>
} }
val FirExtensionService.existingClassModifiers: List<FirExistingClassModificationExtension> by FirExtensionService.registeredExtensions() val FirExtensionService.declarationGenerators: List<FirDeclarationGenerationExtension> by FirExtensionService.registeredExtensions()
@@ -16,7 +16,7 @@ abstract class FirExtensionRegistrar {
) { ) {
val AVAILABLE_EXTENSIONS = listOf( val AVAILABLE_EXTENSIONS = listOf(
FirStatusTransformerExtension::class, FirStatusTransformerExtension::class,
FirExistingClassModificationExtension::class, FirDeclarationGenerationExtension::class,
AbstractFirAdditionalCheckersExtension::class AbstractFirAdditionalCheckersExtension::class
) )
} }
@@ -30,8 +30,8 @@ abstract class FirExtensionRegistrar {
} }
@JvmName("plusClassGenerationExtension") @JvmName("plusClassGenerationExtension")
operator fun ((FirSession) -> FirExistingClassModificationExtension).unaryPlus() { operator fun ((FirSession) -> FirDeclarationGenerationExtension).unaryPlus() {
registerExtension(FirExistingClassModificationExtension::class, FirExistingClassModificationExtension.Factory { this.invoke(it) }) registerExtension(FirDeclarationGenerationExtension::class, FirDeclarationGenerationExtension.Factory { this.invoke(it) })
} }
@JvmName("plusAdditionalCheckersExtension") @JvmName("plusAdditionalCheckersExtension")
@@ -25,11 +25,23 @@ abstract class FirPredicateBasedProvider : FirSessionComponent {
} }
abstract fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirAnnotatedDeclaration> abstract fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirAnnotatedDeclaration>
abstract fun getSymbolsByPredicate(
declarations: Collection<FirAnnotatedDeclaration>,
predicate: DeclarationPredicate
): List<FirAnnotatedDeclaration>
abstract fun getSymbolsWithOwnersByPredicate( abstract fun getSymbolsWithOwnersByPredicate(
predicate: DeclarationPredicate predicate: DeclarationPredicate
): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>> ): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>>
abstract fun getSymbolsWithOwnersByPredicate(
declarations: Collection<FirAnnotatedDeclaration>,
predicate: DeclarationPredicate
): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>>
abstract fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) abstract fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>)
abstract fun registerGeneratedDeclaration(declaration: FirAnnotatedDeclaration, owner: FirAnnotatedDeclaration)
abstract fun matches(predicate: DeclarationPredicate, declaration: FirAnnotatedDeclaration): Boolean abstract fun matches(predicate: DeclarationPredicate, declaration: FirAnnotatedDeclaration): Boolean
} }
@@ -41,13 +53,30 @@ private class FirPredicateBasedProviderImpl(private val session: FirSession) : F
override fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirAnnotatedDeclaration> { override fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirAnnotatedDeclaration> {
val annotations = registeredPluginAnnotations.getAnnotationsForPredicate(predicate) val annotations = registeredPluginAnnotations.getAnnotationsForPredicate(predicate)
if (annotations.isEmpty()) return emptyList() if (annotations.isEmpty()) return emptyList()
return annotations.flatMapTo(mutableSetOf()) { cache.declarationByAnnotation[it] + cache.declarationsUnderAnnotated[it] }.filter { val declarations = annotations.flatMapTo(mutableSetOf()) { cache.declarationByAnnotation[it] + cache.declarationsUnderAnnotated[it] }
matches(predicate, it) return getSymbolsByPredicate(declarations, predicate)
} }
override fun getSymbolsByPredicate(
declarations: Collection<FirAnnotatedDeclaration>,
predicate: DeclarationPredicate
): List<FirAnnotatedDeclaration> {
return declarations.filter { matches(predicate, it) }
} }
override fun getSymbolsWithOwnersByPredicate(predicate: DeclarationPredicate): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>> { override fun getSymbolsWithOwnersByPredicate(predicate: DeclarationPredicate): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>> {
return getSymbolsByPredicate(predicate).map { it to cache.ownersForDeclaration.getValue(it) } return getSymbolsByPredicate(predicate).zipWithParents()
}
override fun getSymbolsWithOwnersByPredicate(
declarations: Collection<FirAnnotatedDeclaration>,
predicate: DeclarationPredicate
): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>> {
return getSymbolsByPredicate(declarations, predicate).zipWithParents()
}
private fun List<FirAnnotatedDeclaration>.zipWithParents(): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>> {
return this.map { it to cache.ownersForDeclaration.getValue(it) }
} }
override fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) { override fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) {
@@ -62,6 +91,11 @@ private class FirPredicateBasedProviderImpl(private val session: FirSession) : F
cache.annotationsOfDeclaration.putAll(declaration, matchingAnnotations) cache.annotationsOfDeclaration.putAll(declaration, matchingAnnotations)
} }
override fun registerGeneratedDeclaration(declaration: FirAnnotatedDeclaration, owner: FirAnnotatedDeclaration) {
val owners = cache.ownersForDeclaration.getValue(owner).add(owner)
registerAnnotatedDeclaration(declaration, owners)
}
private fun registerOwnersDeclarations(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) { private fun registerOwnersDeclarations(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) {
val lastOwner = owners.lastOrNull() ?: return val lastOwner = owners.lastOrNull() ?: return
val annotationsFromLastOwner = cache.annotationsOfDeclaration[lastOwner] val annotationsFromLastOwner = cache.annotationsOfDeclaration[lastOwner]
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.providers package org.jetbrains.kotlin.fir.resolve.providers
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
@@ -47,5 +45,8 @@ abstract class FirProvider : FirSymbolProvider() {
abstract fun getFirFilesByPackage(fqName: FqName): List<FirFile> abstract fun getFirFilesByPackage(fqName: FqName): List<FirFile>
@FirProviderInternals @FirProviderInternals
abstract fun recordNestedClass(owner: FirRegularClass, klass: FirRegularClass) abstract fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass)
@FirProviderInternals
abstract fun recordGeneratedMember(owner: FirAnnotatedDeclaration, klass: FirDeclaration)
} }
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -68,11 +67,22 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: KotlinSc
} }
@FirProviderInternals @FirProviderInternals
override fun recordNestedClass(owner: FirRegularClass, klass: FirRegularClass) { override fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass) {
val file = getFirClassifierContainerFile(owner.symbol.classId) klass.accept(FirRecorder, state to owner.file)
klass.accept(FirRecorder, state to file)
} }
@FirProviderInternals
override fun recordGeneratedMember(owner: FirAnnotatedDeclaration, klass: FirDeclaration) {
klass.accept(FirRecorder, state to owner.file)
}
private val FirAnnotatedDeclaration.file: FirFile
get() = when (this) {
is FirFile -> this
is FirRegularClass -> getFirClassifierContainerFile(this.symbol.classId)
else -> error("Should not be here")
}
private fun recordFile(file: FirFile, state: State) { private fun recordFile(file: FirFile, state: State) {
val packageName = file.packageFqName val packageName = file.packageFqName
state.fileMap.merge(packageName, listOf(file)) { a, b -> a + b } state.fileMap.merge(packageName, listOf(file)) { a, b -> a + b }
@@ -25,7 +25,7 @@ fun FirResolvePhase.createCompilerProcessorByPhase(
return when (this) { return when (this) {
RAW_FIR -> throw IllegalStateException("Raw FIR building phase does not have a transformer") RAW_FIR -> throw IllegalStateException("Raw FIR building phase does not have a transformer")
ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveProcessor(session, scopeSession) ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveProcessor(session, scopeSession)
NESTED_CLASS_GENERATION -> FirGlobalNestedClassGenerationProcessor(session, scopeSession) CLASS_GENERATION -> FirGlobalClassGenerationProcessor(session, scopeSession)
IMPORTS -> FirImportResolveProcessor(session, scopeSession) IMPORTS -> FirImportResolveProcessor(session, scopeSession)
SUPER_TYPES -> FirSupertypeResolverProcessor(session, scopeSession) SUPER_TYPES -> FirSupertypeResolverProcessor(session, scopeSession)
SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsProcessor(session, scopeSession) SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsProcessor(session, scopeSession)
@@ -46,7 +46,7 @@ fun FirResolvePhase.createTransformerBasedProcessorByPhase(
return when (this) { return when (this) {
RAW_FIR -> throw IllegalStateException("Raw FIR building phase does not have a transformer") RAW_FIR -> throw IllegalStateException("Raw FIR building phase does not have a transformer")
ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveProcessor(session, scopeSession) ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveProcessor(session, scopeSession)
NESTED_CLASS_GENERATION -> FirDummyTransformerBasedProcessor(session, scopeSession) // TODO: remove CLASS_GENERATION -> FirDummyTransformerBasedProcessor(session, scopeSession) // TODO: remove
IMPORTS -> FirImportResolveProcessor(session, scopeSession) IMPORTS -> FirImportResolveProcessor(session, scopeSession)
SUPER_TYPES -> FirSupertypeResolverProcessor(session, scopeSession) SUPER_TYPES -> FirSupertypeResolverProcessor(session, scopeSession)
SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsProcessor(session, scopeSession) SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsProcessor(session, scopeSession)
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2020 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.fir.resolve.transformers.plugin
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.addDeclaration
import org.jetbrains.kotlin.fir.extensions.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProviderInternals
import org.jetbrains.kotlin.fir.resolve.transformers.FirGlobalResolveProcessor
class FirGlobalClassGenerationProcessor(
session: FirSession,
scopeSession: ScopeSession
) : FirGlobalResolveProcessor(session, scopeSession) {
override fun process() {
val extensions = session.extensionService.declarationGenerators
if (extensions.isEmpty()) return
val provider = session.predicateBasedProvider
for (extension in extensions) {
var annotatedDeclarations = provider.getSymbolsWithOwnersByPredicate(extension.predicate)
while (annotatedDeclarations.isNotEmpty()) {
val newClasses = generateClasses(annotatedDeclarations, extension)
annotatedDeclarations = provider.getSymbolsWithOwnersByPredicate(newClasses, extension.predicate)
}
}
}
private fun generateClasses(
declarations: List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>>,
extension: FirDeclarationGenerationExtension,
): List<FirRegularClass> {
val newClasses = mutableListOf<FirRegularClass>()
for ((declaration, owners) in declarations) {
generateClass(extension, declaration, owners, newClasses)
}
return newClasses
}
@OptIn(FirProviderInternals::class)
private fun generateClass(
extension: FirDeclarationGenerationExtension,
declaration: FirAnnotatedDeclaration,
owners: List<FirAnnotatedDeclaration>,
newClasses: MutableList<FirRegularClass>
) {
val generatedClasses = extension.generateClasses(declaration, owners)
for ((klass, owner) in generatedClasses) {
when (owner) {
is FirRegularClass -> owner.addDeclaration(klass)
is FirFile -> owner.addDeclaration(klass)
}
session.generatedClassIndex.registerClass(klass, owner)
session.predicateBasedProvider.registerGeneratedDeclaration(klass, owner)
session.firProvider.recordGeneratedClass(owner, klass)
newClasses += klass
}
}
}
@@ -1,41 +0,0 @@
/*
* Copyright 2010-2020 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.fir.resolve.transformers.plugin
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.addDeclaration
import org.jetbrains.kotlin.fir.extensions.existingClassModifiers
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProviderInternals
import org.jetbrains.kotlin.fir.resolve.transformers.FirGlobalResolveProcessor
class FirGlobalNestedClassGenerationProcessor(
session: FirSession,
scopeSession: ScopeSession
) : FirGlobalResolveProcessor(session, scopeSession) {
@OptIn(FirProviderInternals::class)
override fun process() {
val extensions = session.extensionService.existingClassModifiers
if (extensions.isEmpty()) return
val provider = session.predicateBasedProvider
val index = session.generatedNestedClassIndex
for (extension in extensions) {
val declarations = provider.getSymbolsWithOwnersByPredicate(extension.predicate)
for ((declaration, owners) in declarations) {
val nestedClasses = extension.generateNestedClasses(declaration, owners)
for ((nestedClass, owner) in nestedClasses) {
owner.addDeclaration(nestedClass)
index.registerNestedClass(nestedClass, owner)
session.firProvider.recordNestedClass(owner, nestedClass)
}
}
}
}
}
@@ -6,49 +6,61 @@
package org.jetbrains.kotlin.fir.resolve.transformers.plugin package org.jetbrains.kotlin.fir.resolve.transformers.plugin
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.addDeclaration import org.jetbrains.kotlin.fir.declarations.addDeclaration
import org.jetbrains.kotlin.fir.declarations.validate import org.jetbrains.kotlin.fir.declarations.validate
import org.jetbrains.kotlin.fir.extensions.FirExistingClassModificationExtension import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.existingClassModifiers import org.jetbrains.kotlin.fir.extensions.declarationGenerators
import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProviderInternals
import org.jetbrains.kotlin.fir.resolve.transformers.FirGlobalResolveProcessor import org.jetbrains.kotlin.fir.resolve.transformers.FirGlobalResolveProcessor
class FirGlobalNewMemberGenerationProcessor( class FirGlobalNewMemberGenerationProcessor(
session: FirSession, session: FirSession,
scopeSession: ScopeSession scopeSession: ScopeSession
) : FirGlobalResolveProcessor(session, scopeSession) { ) : FirGlobalResolveProcessor(session, scopeSession) {
private val index = session.generatedNestedClassIndex private val index = session.generatedClassIndex
private val provider = session.predicateBasedProvider private val provider = session.predicateBasedProvider
override fun process() { override fun process() {
val extensions = session.extensionService.existingClassModifiers val extensions = session.extensionService.declarationGenerators
if (extensions.isEmpty()) return if (extensions.isEmpty()) return
for (extension in extensions) { for (extension in extensions) {
generateNewMembers(extension) generateNewMembers(extension)
fillGeneratedNestedClasses(extension) fillGeneratedClasses(extension)
} }
} }
private fun generateNewMembers(extension: FirExistingClassModificationExtension) { @OptIn(FirProviderInternals::class)
private fun generateNewMembers(extension: FirDeclarationGenerationExtension) {
val declarations = provider.getSymbolsWithOwnersByPredicate(extension.predicate) val declarations = provider.getSymbolsWithOwnersByPredicate(extension.predicate)
for ((declaration, owners) in declarations) { for ((declaration, owners) in declarations) {
val newMembers = extension.generateMembers(declaration, owners) val newMembers = extension.generateMembers(declaration, owners)
for ((newMember, owner) in newMembers) { for ((newMember, owner) in newMembers) {
newMember.validate() newMember.validate()
owner.addDeclaration(newMember) when (owner) {
is FirRegularClass -> owner.addDeclaration(newMember)
is FirFile -> owner.addDeclaration(newMember)
else -> error("Should not be here")
}
session.firProvider.recordGeneratedMember(owner, newMember)
} }
} }
} }
private fun fillGeneratedNestedClasses(extension: FirExistingClassModificationExtension) { @OptIn(FirProviderInternals::class)
for (generatedNestedClass in index[extension.key]) { private fun fillGeneratedClasses(extension: FirDeclarationGenerationExtension) {
val nestedClass = generatedNestedClass.nestedClass for (generatedClass in index[extension.key]) {
val newMembers = extension.generateMembersForNestedClasses(generatedNestedClass) val klass = generatedClass.klass
val newMembers = extension.generateMembersForGeneratedClass(generatedClass)
for (newMember in newMembers) { for (newMember in newMembers) {
newMember.validate() newMember.validate()
nestedClass.addDeclaration(newMember) klass.addDeclaration(newMember)
session.firProvider.recordGeneratedMember(klass, newMember)
} }
} }
} }
@@ -8,34 +8,35 @@ package org.jetbrains.kotlin.fir.resolve.transformers.plugin
import com.google.common.collect.ArrayListMultimap import com.google.common.collect.ArrayListMultimap
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirPluginKey import org.jetbrains.kotlin.fir.declarations.FirPluginKey
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
data class GeneratedNestedClass(val nestedClass: FirRegularClass, val owner: FirRegularClass) data class GeneratedClass(val klass: FirRegularClass, val owner: FirAnnotatedDeclaration)
abstract class GeneratedNestedClassIndex : FirSessionComponent { abstract class GeneratedClassIndex : FirSessionComponent {
companion object { companion object {
fun create(): GeneratedNestedClassIndex { fun create(): GeneratedClassIndex {
return GeneratedNestedClassIndexImpl() return GeneratedClassIndexImpl()
} }
} }
abstract fun registerNestedClass(klass: FirRegularClass, owner: FirRegularClass) abstract fun registerClass(klass: FirRegularClass, owner: FirAnnotatedDeclaration)
abstract operator fun get(key: FirPluginKey): List<GeneratedNestedClass> abstract operator fun get(key: FirPluginKey): List<GeneratedClass>
} }
val FirSession.generatedNestedClassIndex: GeneratedNestedClassIndex by FirSession.sessionComponentAccessor() val FirSession.generatedClassIndex: GeneratedClassIndex by FirSession.sessionComponentAccessor()
private class GeneratedNestedClassIndexImpl : GeneratedNestedClassIndex() { private class GeneratedClassIndexImpl : GeneratedClassIndex() {
private val index: ArrayListMultimap<FirPluginKey, GeneratedNestedClass> = ArrayListMultimap.create() private val index: ArrayListMultimap<FirPluginKey, GeneratedClass> = ArrayListMultimap.create()
override fun registerNestedClass(klass: FirRegularClass, owner: FirRegularClass) { override fun registerClass(klass: FirRegularClass, owner: FirAnnotatedDeclaration) {
val key = (klass.origin as FirDeclarationOrigin.Plugin).key val key = (klass.origin as FirDeclarationOrigin.Plugin).key
index.put(key, GeneratedNestedClass(klass, owner)) index.put(key, GeneratedClass(klass, owner))
} }
override fun get(key: FirPluginKey): List<GeneratedNestedClass> { override fun get(key: FirPluginKey): List<GeneratedClass> {
return index.get(key) return index.get(key)
} }
} }
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.fir.declarations
enum class FirResolvePhase { enum class FirResolvePhase {
RAW_FIR, RAW_FIR,
ANNOTATIONS_FOR_PLUGINS, // run only if some extensions are registered ANNOTATIONS_FOR_PLUGINS, // run only if some extensions are registered
NESTED_CLASS_GENERATION, // plugin phase CLASS_GENERATION, // plugin phase
IMPORTS, IMPORTS,
SUPER_TYPES, SUPER_TYPES,
SEALED_CLASS_INHERITORS, SEALED_CLASS_INHERITORS,
@@ -10,9 +10,7 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.RawFirBuilder import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProviderInternals import org.jetbrains.kotlin.fir.resolve.providers.FirProviderInternals
@@ -153,9 +151,15 @@ class FirIdeProvider(
} }
@FirProviderInternals @FirProviderInternals
override fun recordNestedClass(owner: FirRegularClass, klass: FirRegularClass) { override fun recordGeneratedClass(owner: FirAnnotatedDeclaration, klass: FirRegularClass) {
// TODO: check that this implementation is correct // TODO: check that this implementation is correct
cacheProvider.recordNestedClass(owner, klass) cacheProvider.recordGeneratedClass(owner, klass)
}
@FirProviderInternals
override fun recordGeneratedMember(owner: FirAnnotatedDeclaration, klass: FirDeclaration) {
// TODO: check that this implementation is correct
cacheProvider.recordGeneratedMember(owner, klass)
} }
} }