From 728e0604ac67c8fa7240afc95a8dcc739b64a492 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 29 Apr 2020 11:36:00 +0300 Subject: [PATCH] [FIR] Add prototype of first generation phase --- .../extensions/FirClassGenerationExtension.kt | 43 ++++++++ .../fir/extensions/FirExtensionRegistrar.kt | 16 ++- .../resolve/transformers/ResolvePhaseUtils.kt | 2 + .../plugin/FirFirstGenerationTransformer.kt | 104 ++++++++++++++++++ .../fir/declarations/FirDeclarationUtil.kt | 18 +++ .../fir/declarations/FirResolvePhase.kt | 1 + 6 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirClassGenerationExtension.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirFirstGenerationTransformer.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirClassGenerationExtension.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirClassGenerationExtension.kt new file mode 100644 index 00000000000..d3ca9cc9ed9 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirClassGenerationExtension.kt @@ -0,0 +1,43 @@ +/* + * 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 + +/* + * TODO: + * - add registration of new files + * - check that annotations or meta-annotations is not empty + */ +abstract class FirClassGenerationExtension(session: FirSession) : FirExtensionPoint(session) { + companion object { + val NAME = FirExtensionPointName("StatusTransformer") + } + + final override val name: FirExtensionPointName + get() = NAME + + final override val mode: Mode = Mode.ANNOTATED_ELEMENT + + abstract fun generateClass( + containingFile: FirFile, + annotatedDeclaration: T + ): List 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 : FirExtensionPoint.Factory +} + +val FirExtensionPointService.classGenerationExtensions: FirExtensionPointService.ExtensionsAccessor by FirExtensionPointService.registeredExtensions() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt index 1cd08ca8394..2752c0331f6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionRegistrar.kt @@ -15,9 +15,15 @@ abstract class FirExtensionRegistrar { ) protected inner class ExtensionRegistrarContext { + @JvmName("plusStatusTransformerExtension") operator fun ((FirSession) -> FirStatusTransformerExtension).unaryPlus() { statusTransformerExtensions += FirStatusTransformerExtension.Factory { this.invoke(it) } } + + @JvmName("plusClassGenerationExtension") + operator fun ((FirSession) -> FirClassGenerationExtension).unaryPlus() { + classGenerationExtensions += FirClassGenerationExtension.Factory { this.invoke(it) } + } } protected abstract fun ExtensionRegistrarContext.configurePlugin() @@ -25,21 +31,25 @@ abstract class FirExtensionRegistrar { fun configure(): RegisteredExtensions { ExtensionRegistrarContext().configurePlugin() return RegisteredExtensions( - statusTransformerExtensions + statusTransformerExtensions, + classGenerationExtensions ) } private val statusTransformerExtensions: MutableList = mutableListOf() + private val classGenerationExtensions: MutableList = mutableListOf() class RegisteredExtensions( - val statusTransformerExtensions: List + val statusTransformerExtensions: List, + val classGenerationExtensions: List ) { companion object { - val EMPTY = RegisteredExtensions(emptyList()) + val EMPTY = RegisteredExtensions(emptyList(), emptyList()) } } } fun FirExtensionPointService.registerExtensions(extensions: FirExtensionRegistrar.RegisteredExtensions) { registerExtensions(FirStatusTransformerExtension::class, extensions.statusTransformerExtensions) + registerExtensions(FirClassGenerationExtension::class, extensions.classGenerationExtensions) } \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt index b9f7764a92e..aed0443f86e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformerAdapter import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitTypeBodyResolveTransformerAdapter import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractResolveTransformerAdapter +import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirFirstGenerationTransformer import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirPluginAnnotationsResolveTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer @@ -20,6 +21,7 @@ fun FirResolvePhase.createTransformerByPhase(scopeSession: ScopeSession): FirTra return when (this) { RAW_FIR -> throw AssertionError("Raw FIR building phase does not have a transformer") ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveTransformer(scopeSession) + FIRST_PLUGIN_GENERATION -> FirFirstGenerationTransformer() IMPORTS -> FirImportResolveTransformer() SUPER_TYPES -> FirSupertypeResolverTransformer(scopeSession) SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsTransformer() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirFirstGenerationTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirFirstGenerationTransformer.kt new file mode 100644 index 00000000000..e85000da7db --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirFirstGenerationTransformer.kt @@ -0,0 +1,104 @@ +/* + * 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.FirAnnotationContainer +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.extensions.FirClassGenerationExtension +import org.jetbrains.kotlin.fir.extensions.classGenerationExtensions +import org.jetbrains.kotlin.fir.extensions.extensionPointService +import org.jetbrains.kotlin.fir.extensions.hasExtensions +import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult +import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer +import org.jetbrains.kotlin.fir.visitors.compose + +class FirFirstGenerationTransformer : FirDefaultTransformer() { + private lateinit var session: FirSession + private val generatedDeclarations: MutableList = mutableListOf() + private lateinit var file: FirFile + private val extensionPointService get() = session.extensionPointService + + override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult { + session = file.session + if (!extensionPointService.hasExtensions) return file.compose() + file.replaceResolvePhase(FirResolvePhase.FIRST_PLUGIN_GENERATION) + generatedDeclarations.clear() + this.file = file + + file.transformDeclarations(this, data) + visitAnnotatedDeclaration(file) + addGeneratedClasses() + return file.compose() + } + + private fun addGeneratedClasses() { + for ((generatedClass, owner) in generatedDeclarations) { + when (owner) { + is FirFile -> owner.addDeclaration(generatedClass) + is FirRegularClass -> owner.addDeclaration(generatedClass) + else -> throw IllegalStateException() + } + } + } + + private fun visitAnnotatedDeclaration(declaration: T) where T : FirDeclaration, T : FirAnnotationContainer { + val extensions = extensionPointService.classGenerationExtensions.forDeclaration(declaration, emptyList()) + extensions.flatMapTo(generatedDeclarations) { it.generateClass(file, declaration) } + } + + override fun transformProperty(property: FirProperty, data: Nothing?): CompositeTransformResult { + visitAnnotatedDeclaration(property) + return property.compose() + } + + override fun transformRegularClass( + regularClass: FirRegularClass, + data: Nothing? + ): CompositeTransformResult { + regularClass.transformDeclarations(this, data) + regularClass.transformCompanionObject(this, data) + visitAnnotatedDeclaration(regularClass) + return regularClass.compose() + } + + override fun transformSimpleFunction( + simpleFunction: FirSimpleFunction, + data: Nothing? + ): CompositeTransformResult { + simpleFunction.transformValueParameters(this, data) + visitAnnotatedDeclaration(simpleFunction) + return simpleFunction.compose() + } + + override fun transformConstructor( + constructor: FirConstructor, + data: Nothing? + ): CompositeTransformResult { + constructor.transformValueParameters(this, data) + visitAnnotatedDeclaration(constructor) + return constructor.compose() + } + + override fun transformValueParameter( + valueParameter: FirValueParameter, + data: Nothing? + ): CompositeTransformResult { + visitAnnotatedDeclaration(valueParameter) + return valueParameter.compose() + } + + override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): CompositeTransformResult { + visitAnnotatedDeclaration(typeAlias) + return typeAlias.compose() + } + + override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { + return element.compose() + } +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt index 46931e6add5..1e12565d259 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt @@ -9,6 +9,9 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.declarations.builder.AbstractFirRegularClassBuilder import org.jetbrains.kotlin.fir.declarations.builder.FirTypeParameterBuilder +import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl +import org.jetbrains.kotlin.fir.declarations.impl.FirFileImpl +import org.jetbrains.kotlin.fir.declarations.impl.FirSealedClassImpl import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol @@ -16,6 +19,7 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeFlexibleType import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.coneTypeSafe +import java.lang.IllegalStateException fun FirTypeParameterBuilder.addDefaultBoundIfNecessary(isFlexible: Boolean = false) { if (bounds.isEmpty()) { @@ -89,4 +93,18 @@ val FirClass<*>.superConeTypes get() = superTypeRefs.mapNotNull { it.coneTypeSaf fun FirRegularClass.collectEnumEntries(): Collection { assert(classKind == ClassKind.ENUM_CLASS) return declarations.filterIsInstance() +} + +fun FirFile.addDeclaration(declaration: FirDeclaration) { + require(this is FirFileImpl) + declarations += declaration +} + +fun FirRegularClass.addDeclaration(declaration: FirDeclaration) { + @Suppress("LiftReturnOrAssignment") + when (this) { + is FirClassImpl -> declarations += declaration + is FirSealedClassImpl -> declarations += declaration + else -> throw IllegalStateException() + } } \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt index 092bfdf81f5..b1c170bf7a8 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt @@ -8,6 +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 IMPORTS, SUPER_TYPES, SEALED_CLASS_INHERITORS,