[FIR] Add extension for generating new members for existing classes
This commit is contained in:
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionService
|
||||
import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider
|
||||
import org.jetbrains.kotlin.fir.extensions.FirRegisteredPluginAnnotations
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedNestedClassIndex
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider
|
||||
import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache
|
||||
|
||||
@@ -18,4 +19,5 @@ fun FirSession.registerCommonComponents() {
|
||||
register(FirExtensionService::class, FirExtensionService(this))
|
||||
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.create(this))
|
||||
register(FirPredicateBasedProvider::class, FirPredicateBasedProvider.create(this))
|
||||
register(GeneratedNestedClassIndex::class, GeneratedNestedClassIndex.create())
|
||||
}
|
||||
-44
@@ -1,44 +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.extensions
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - add registration of new files
|
||||
* - check that annotations or meta-annotations is not empty
|
||||
*/
|
||||
abstract class FirClassGenerationExtension(session: FirSession) : FirPredicateBasedExtension(session) {
|
||||
companion object {
|
||||
val NAME = FirExtensionPointName("StatusTransformer")
|
||||
}
|
||||
|
||||
final override val name: FirExtensionPointName
|
||||
get() = NAME
|
||||
|
||||
final override val extensionType: KClass<out FirExtension> = FirClassGenerationExtension::class
|
||||
|
||||
abstract fun <T> generateClass(
|
||||
containingFile: FirFile,
|
||||
annotatedDeclaration: T
|
||||
): List<GeneratedClass> where T : FirDeclaration, T : FirAnnotationContainer
|
||||
|
||||
data class GeneratedClass(val klass: FirRegularClass, val container: FirDeclaration) {
|
||||
init {
|
||||
require(container is FirRegularClass || container is FirFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun interface Factory : FirExtension.Factory<FirClassGenerationExtension>
|
||||
}
|
||||
|
||||
val FirExtensionService.classGenerationExtensions: List<FirClassGenerationExtension> by FirExtensionService.registeredExtensions()
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.extensions
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedNestedClass
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - check that annotations or meta-annotations is not empty
|
||||
*/
|
||||
abstract class FirExistingClassModificationExtension(session: FirSession) : FirPredicateBasedExtension(session) {
|
||||
companion object {
|
||||
val NAME = FirExtensionPointName("ExistingClassModification")
|
||||
}
|
||||
|
||||
final override val name: FirExtensionPointName
|
||||
get() = NAME
|
||||
|
||||
final override val extensionType: KClass<out FirExtension> = FirExistingClassModificationExtension::class
|
||||
|
||||
abstract fun generateNestedClasses(
|
||||
annotatedDeclaration: FirDeclaration,
|
||||
owners: List<FirAnnotatedDeclaration>
|
||||
): List<GeneratedDeclaration<FirRegularClass>>
|
||||
|
||||
abstract fun generateMembersForNestedClasses(generatedNestedClass: GeneratedNestedClass): List<FirDeclaration>
|
||||
|
||||
abstract fun generateMembers(
|
||||
annotatedDeclaration: FirDeclaration,
|
||||
owners: List<FirAnnotatedDeclaration>
|
||||
): List<GeneratedDeclaration<*>>
|
||||
|
||||
data class GeneratedDeclaration<out T : FirDeclaration>(val newDeclaration: T, val owner: FirRegularClass)
|
||||
|
||||
fun interface Factory : FirExtension.Factory<FirExistingClassModificationExtension>
|
||||
}
|
||||
|
||||
val FirExtensionService.existingClassModifiers: List<FirExistingClassModificationExtension> by FirExtensionService.registeredExtensions()
|
||||
+3
-3
@@ -16,7 +16,7 @@ abstract class FirExtensionRegistrar {
|
||||
) {
|
||||
val AVAILABLE_EXTENSIONS = listOf(
|
||||
FirStatusTransformerExtension::class,
|
||||
FirClassGenerationExtension::class,
|
||||
FirExistingClassModificationExtension::class,
|
||||
AbstractFirAdditionalCheckersExtension::class
|
||||
)
|
||||
}
|
||||
@@ -30,8 +30,8 @@ abstract class FirExtensionRegistrar {
|
||||
}
|
||||
|
||||
@JvmName("plusClassGenerationExtension")
|
||||
operator fun ((FirSession) -> FirClassGenerationExtension).unaryPlus() {
|
||||
registerExtension(FirClassGenerationExtension::class, FirClassGenerationExtension.Factory { this.invoke(it) })
|
||||
operator fun ((FirSession) -> FirExistingClassModificationExtension).unaryPlus() {
|
||||
registerExtension(FirExistingClassModificationExtension::class, FirExistingClassModificationExtension.Factory { this.invoke(it) })
|
||||
}
|
||||
|
||||
@JvmName("plusAdditionalCheckersExtension")
|
||||
|
||||
+7
@@ -25,6 +25,9 @@ abstract class FirPredicateBasedProvider : FirSessionComponent {
|
||||
}
|
||||
|
||||
abstract fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirAnnotatedDeclaration>
|
||||
abstract fun getSymbolsWithOwnersByPredicate(
|
||||
predicate: DeclarationPredicate
|
||||
): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>>
|
||||
|
||||
abstract fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>)
|
||||
|
||||
@@ -43,6 +46,10 @@ private class FirPredicateBasedProviderImpl(private val session: FirSession) : F
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSymbolsWithOwnersByPredicate(predicate: DeclarationPredicate): List<Pair<FirAnnotatedDeclaration, List<FirAnnotatedDeclaration>>> {
|
||||
return getSymbolsByPredicate(predicate).map { it to cache.ownersForDeclaration.getValue(it) }
|
||||
}
|
||||
|
||||
override fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) {
|
||||
cache.ownersForDeclaration[declaration] = owners
|
||||
registerOwnersDeclarations(declaration, owners)
|
||||
|
||||
+27
-5
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase.*
|
||||
@@ -12,9 +13,10 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveProcessor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitTypeBodyResolveProcessor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractResolveProcessor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirGlobalExtensionStatusProcessor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirPluginAnnotationsResolveProcessor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirTransformerBasedExtensionStatusProcessor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.*
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.compose
|
||||
|
||||
fun FirResolvePhase.createCompilerProcessorByPhase(
|
||||
session: FirSession,
|
||||
@@ -23,7 +25,7 @@ fun FirResolvePhase.createCompilerProcessorByPhase(
|
||||
return when (this) {
|
||||
RAW_FIR -> throw IllegalStateException("Raw FIR building phase does not have a transformer")
|
||||
ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveProcessor(session, scopeSession)
|
||||
// FIRST_PLUGIN_GENERATION -> FirFirstGenerationTransformer()
|
||||
NESTED_CLASS_GENERATION -> FirGlobalNestedClassGenerationProcessor(session, scopeSession)
|
||||
IMPORTS -> FirImportResolveProcessor(session, scopeSession)
|
||||
SUPER_TYPES -> FirSupertypeResolverProcessor(session, scopeSession)
|
||||
SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsProcessor(session, scopeSession)
|
||||
@@ -31,15 +33,20 @@ fun FirResolvePhase.createCompilerProcessorByPhase(
|
||||
EXTENSION_STATUS_UPDATE -> FirGlobalExtensionStatusProcessor(session, scopeSession)
|
||||
STATUS -> FirStatusResolveProcessor(session, scopeSession)
|
||||
CONTRACTS -> FirContractResolveProcessor(session, scopeSession)
|
||||
NEW_MEMBERS_GENERATION -> FirGlobalNewMemberGenerationProcessor(session, scopeSession)
|
||||
IMPLICIT_TYPES_BODY_RESOLVE -> FirImplicitTypeBodyResolveProcessor(session, scopeSession)
|
||||
BODY_RESOLVE -> FirBodyResolveProcessor(session, scopeSession)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirResolvePhase.createTransformerBasedProcessorByPhase(session: FirSession, scopeSession: ScopeSession): FirTransformerBasedResolveProcessor {
|
||||
fun FirResolvePhase.createTransformerBasedProcessorByPhase(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
): FirTransformerBasedResolveProcessor {
|
||||
return when (this) {
|
||||
RAW_FIR -> throw IllegalStateException("Raw FIR building phase does not have a transformer")
|
||||
ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveProcessor(session, scopeSession)
|
||||
NESTED_CLASS_GENERATION -> FirDummyTransformerBasedProcessor(session, scopeSession) // TODO: remove
|
||||
IMPORTS -> FirImportResolveProcessor(session, scopeSession)
|
||||
SUPER_TYPES -> FirSupertypeResolverProcessor(session, scopeSession)
|
||||
SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsProcessor(session, scopeSession)
|
||||
@@ -47,7 +54,22 @@ fun FirResolvePhase.createTransformerBasedProcessorByPhase(session: FirSession,
|
||||
EXTENSION_STATUS_UPDATE -> FirTransformerBasedExtensionStatusProcessor(session, scopeSession)
|
||||
STATUS -> FirStatusResolveProcessor(session, scopeSession)
|
||||
CONTRACTS -> FirContractResolveProcessor(session, scopeSession)
|
||||
NEW_MEMBERS_GENERATION -> FirDummyTransformerBasedProcessor(session, scopeSession) // TODO: remove
|
||||
IMPLICIT_TYPES_BODY_RESOLVE -> FirImplicitTypeBodyResolveProcessor(session, scopeSession)
|
||||
BODY_RESOLVE -> FirBodyResolveProcessor(session, scopeSession)
|
||||
}
|
||||
}
|
||||
|
||||
private class FirDummyTransformerBasedProcessor(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) : FirTransformerBasedResolveProcessor(session, scopeSession) {
|
||||
override val transformer: FirTransformer<Nothing?>
|
||||
get() = DummyTransformer
|
||||
|
||||
private object DummyTransformer : FirTransformer<Nothing?>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||
return element.compose()
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.FirRegularClass
|
||||
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.transformers.FirGlobalResolveProcessor
|
||||
|
||||
class FirGlobalNestedClassGenerationProcessor(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) : FirGlobalResolveProcessor(session, scopeSession) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.declarations.validate
|
||||
import org.jetbrains.kotlin.fir.extensions.FirExistingClassModificationExtension
|
||||
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.transformers.FirGlobalResolveProcessor
|
||||
|
||||
class FirGlobalNewMemberGenerationProcessor(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) : FirGlobalResolveProcessor(session, scopeSession) {
|
||||
private val index = session.generatedNestedClassIndex
|
||||
private val provider = session.predicateBasedProvider
|
||||
|
||||
override fun process() {
|
||||
val extensions = session.extensionService.existingClassModifiers
|
||||
if (extensions.isEmpty()) return
|
||||
for (extension in extensions) {
|
||||
generateNewMembers(extension)
|
||||
fillGeneratedNestedClasses(extension)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateNewMembers(extension: FirExistingClassModificationExtension) {
|
||||
val declarations = provider.getSymbolsWithOwnersByPredicate(extension.predicate)
|
||||
for ((declaration, owners) in declarations) {
|
||||
val newMembers = extension.generateMembers(declaration, owners)
|
||||
for ((newMember, owner) in newMembers) {
|
||||
newMember.validate()
|
||||
owner.addDeclaration(newMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillGeneratedNestedClasses(extension: FirExistingClassModificationExtension) {
|
||||
for (generatedNestedClass in index[extension.key]) {
|
||||
val nestedClass = generatedNestedClass.nestedClass
|
||||
val newMembers = extension.generateMembersForNestedClasses(generatedNestedClass)
|
||||
for (newMember in newMembers) {
|
||||
newMember.validate()
|
||||
nestedClass.addDeclaration(newMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 com.google.common.collect.ArrayListMultimap
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPluginKey
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
|
||||
data class GeneratedNestedClass(val nestedClass: FirRegularClass, val owner: FirRegularClass)
|
||||
|
||||
abstract class GeneratedNestedClassIndex : FirSessionComponent {
|
||||
companion object {
|
||||
fun create(): GeneratedNestedClassIndex {
|
||||
return GeneratedNestedClassIndexImpl()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun registerNestedClass(klass: FirRegularClass, owner: FirRegularClass)
|
||||
abstract operator fun get(key: FirPluginKey): List<GeneratedNestedClass>
|
||||
}
|
||||
|
||||
val FirSession.generatedNestedClassIndex: GeneratedNestedClassIndex by FirSession.sessionComponentAccessor()
|
||||
|
||||
private class GeneratedNestedClassIndexImpl : GeneratedNestedClassIndex() {
|
||||
private val index: ArrayListMultimap<FirPluginKey, GeneratedNestedClass> = ArrayListMultimap.create()
|
||||
|
||||
override fun registerNestedClass(klass: FirRegularClass, owner: FirRegularClass) {
|
||||
val key = (klass.origin as FirDeclarationOrigin.Plugin).key
|
||||
index.put(key, GeneratedNestedClass(klass, owner))
|
||||
}
|
||||
|
||||
override fun get(key: FirPluginKey): List<GeneratedNestedClass> {
|
||||
return index.get(key)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.fir.declarations
|
||||
enum class FirResolvePhase {
|
||||
RAW_FIR,
|
||||
ANNOTATIONS_FOR_PLUGINS, // run only if some extensions are registered
|
||||
// FIRST_PLUGIN_GENERATION, // plugin phase
|
||||
NESTED_CLASS_GENERATION, // plugin phase
|
||||
IMPORTS,
|
||||
SUPER_TYPES,
|
||||
SEALED_CLASS_INHERITORS,
|
||||
@@ -16,6 +16,7 @@ enum class FirResolvePhase {
|
||||
EXTENSION_STATUS_UPDATE,
|
||||
STATUS,
|
||||
CONTRACTS,
|
||||
NEW_MEMBERS_GENERATION, // plugin
|
||||
IMPLICIT_TYPES_BODY_RESOLVE,
|
||||
BODY_RESOLVE;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user