[IR generator] Don't use kotlinpoet for auto-generating IR tree classes

KT-61970 Fixed
KT-61703 Fixed
This commit is contained in:
Sergej Jaskiewicz
2023-10-27 18:55:48 +02:00
committed by Space Team
parent 63e9dd588c
commit ed28923282
52 changed files with 392 additions and 646 deletions
@@ -24,7 +24,6 @@ fun Builder.generateCode(generationPath: File): GeneratedFile =
typeName, typeName,
fileSuppressions = listOf("DuplicatedCode", "unused"), fileSuppressions = listOf("DuplicatedCode", "unused"),
) { ) {
println()
addAllImports(usedTypes) addAllImports(usedTypes)
printBuilder(this@generateCode) printBuilder(this@generateCode)
} }
@@ -88,6 +88,5 @@ private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter<Ele
fun Element.generateCode(generationPath: File): GeneratedFile = fun Element.generateCode(generationPath: File): GeneratedFile =
printGeneratedType(generationPath, TREE_GENERATOR_README, packageName, typeName) { printGeneratedType(generationPath, TREE_GENERATOR_README, packageName, typeName) {
println()
ElementPrinter(this).printElement(element) ElementPrinter(this).printElement(element)
} }
@@ -24,7 +24,6 @@ fun Implementation.generateCode(generationPath: File): GeneratedFile =
this.typeName, this.typeName,
fileSuppressions = listOf("DuplicatedCode", "unused"), fileSuppressions = listOf("DuplicatedCode", "unused"),
) { ) {
println()
addAllImports(usedTypes) addAllImports(usedTypes)
printImplementation(this@generateCode) printImplementation(this@generateCode)
} }
@@ -106,6 +106,5 @@ fun printTransformer(elements: List<Element>, generationPath: File): GeneratedFi
firTransformerType.packageName, firTransformerType.packageName,
firTransformerType.simpleName, firTransformerType.simpleName,
) { ) {
println()
TransformerPrinter(this).printVisitor(elements) TransformerPrinter(this).printVisitor(elements)
} }
@@ -120,6 +120,5 @@ private fun printVisitorCommon(
makePrinter: (SmartPrinter, ClassRef<*>) -> AbstractVisitorPrinter<Element, Field>, makePrinter: (SmartPrinter, ClassRef<*>) -> AbstractVisitorPrinter<Element, Field>,
): GeneratedFile = ): GeneratedFile =
printGeneratedType(generationPath, TREE_GENERATOR_README, visitorType.packageName, visitorType.simpleName) { printGeneratedType(generationPath, TREE_GENERATOR_README, visitorType.packageName, visitorType.simpleName) {
println()
makePrinter(this, visitorType).printVisitor(elements) makePrinter(this, visitorType).printVisitor(elements)
} }
@@ -19,10 +19,8 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrElement { interface IrElement {
/** /**
* The start offset of the syntax node from which this IR node was generated, * The start offset of the syntax node from which this IR node was generated,
* in number of characters from the start of the source file. If there is no source information * in number of characters from the start of the source file. If there is no source information for this IR node,
* for this IR node, * the [UNDEFINED_OFFSET] constant is used. In order to get the line number and the column number from this offset,
* the [UNDEFINED_OFFSET] constant is used. In order to get the line number and the column
* number from this offset,
* [IrFileEntry.getLineNumber] and [IrFileEntry.getColumnNumber] can be used. * [IrFileEntry.getLineNumber] and [IrFileEntry.getColumnNumber] can be used.
* *
* @see IrFileEntry.getSourceRangeInfo * @see IrFileEntry.getSourceRangeInfo
@@ -31,10 +29,8 @@ interface IrElement {
/** /**
* The end offset of the syntax node from which this IR node was generated, * The end offset of the syntax node from which this IR node was generated,
* in number of characters from the start of the source file. If there is no source information * in number of characters from the start of the source file. If there is no source information for this IR node,
* for this IR node, * the [UNDEFINED_OFFSET] constant is used. In order to get the line number and the column number from this offset,
* the [UNDEFINED_OFFSET] constant is used. In order to get the line number and the column
* number from this offset,
* [IrFileEntry.getLineNumber] and [IrFileEntry.getColumnNumber] can be used. * [IrFileEntry.getLineNumber] and [IrFileEntry.getColumnNumber] can be used.
* *
* @see IrFileEntry.getSourceRangeInfo * @see IrFileEntry.getSourceRangeInfo
@@ -74,8 +70,7 @@ interface IrElement {
/** /**
* Recursively transforms this node's children *in place* using [transformer]. * Recursively transforms this node's children *in place* using [transformer].
* *
* Basically, executes `this.child = this.child.transform(transformer, data)` for each child * Basically, executes `this.child = this.child.transform(transformer, data)` for each child of this node.
* of this node.
* *
* Does **not** run [transformer] on this node itself. * Does **not** run [transformer] on this node itself.
* *
@@ -8,11 +8,7 @@
package org.jetbrains.kotlin.ir.declarations package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.ValueClassRepresentation
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
@@ -27,9 +23,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.class] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.class]
*/ */
abstract class IrClass : IrDeclarationBase(), IrPossiblyExternalDeclaration, abstract class IrClass : IrDeclarationBase(), IrPossiblyExternalDeclaration, IrDeclarationWithVisibility, IrTypeParametersContainer, IrDeclarationContainer, IrAttributeContainer, IrMetadataSourceOwner {
IrDeclarationWithVisibility, IrTypeParametersContainer, IrDeclarationContainer,
IrAttributeContainer, IrMetadataSourceOwner {
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
abstract override val descriptor: ClassDescriptor abstract override val descriptor: ClassDescriptor
@@ -52,12 +46,9 @@ abstract class IrClass : IrDeclarationBase(), IrPossiblyExternalDeclaration,
abstract var isFun: Boolean abstract var isFun: Boolean
/** /**
* Returns true iff this is a class loaded from dependencies which has the `HAS_ENUM_ENTRIES` * Returns true iff this is a class loaded from dependencies which has the `HAS_ENUM_ENTRIES` metadata flag set.
* metadata flag set. * This flag is useful for Kotlin/JVM to determine whether an enum class from dependency actually has the `entries` property
* This flag is useful for Kotlin/JVM to determine whether an enum class from dependency * in its bytecode, as opposed to whether it has it in its member scope, which is true even for enum classes compiled by
* actually has the `entries` property
* in its bytecode, as opposed to whether it has it in its member scope, which is true even for
* enum classes compiled by
* old versions of Kotlin which did not support the EnumEntries language feature. * old versions of Kotlin which did not support the EnumEntries language feature.
*/ */
abstract var hasEnumEntries: Boolean abstract var hasEnumEntries: Boolean
@@ -71,8 +62,7 @@ abstract class IrClass : IrDeclarationBase(), IrPossiblyExternalDeclaration,
abstract var valueClassRepresentation: ValueClassRepresentation<IrSimpleType>? abstract var valueClassRepresentation: ValueClassRepresentation<IrSimpleType>?
/** /**
* If this is a sealed class or interface, this list contains symbols of all its immediate * If this is a sealed class or interface, this list contains symbols of all its immediate subclasses.
* subclasses.
* Otherwise, this is an empty list. * Otherwise, this is an empty list.
* *
* NOTE: If this [IrClass] was deserialized from a klib, this list will always be empty! * NOTE: If this [IrClass] was deserialized from a klib, this list will always be empty!
@@ -22,8 +22,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.field] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.field]
*/ */
abstract class IrField : IrDeclarationBase(), IrPossiblyExternalDeclaration, abstract class IrField : IrDeclarationBase(), IrPossiblyExternalDeclaration, IrDeclarationWithVisibility, IrDeclarationParent, IrMetadataSourceOwner {
IrDeclarationWithVisibility, IrDeclarationParent, IrMetadataSourceOwner {
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
abstract override val descriptor: PropertyDescriptor abstract override val descriptor: PropertyDescriptor
@@ -19,8 +19,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.file] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.file]
*/ */
abstract class IrFile : IrPackageFragment(), IrMetadataSourceOwner, abstract class IrFile : IrPackageFragment(), IrMetadataSourceOwner, IrMutableAnnotationContainer {
IrMutableAnnotationContainer {
abstract override val symbol: IrFileSymbol abstract override val symbol: IrFileSymbol
abstract var module: IrModuleFragment abstract var module: IrModuleFragment
@@ -22,9 +22,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.function] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.function]
*/ */
abstract class IrFunction : IrDeclarationBase(), IrPossiblyExternalDeclaration, abstract class IrFunction : IrDeclarationBase(), IrPossiblyExternalDeclaration, IrDeclarationWithVisibility, IrTypeParametersContainer, IrSymbolOwner, IrDeclarationParent, IrReturnTarget, IrMemberWithContainerSource, IrMetadataSourceOwner {
IrDeclarationWithVisibility, IrTypeParametersContainer, IrSymbolOwner, IrDeclarationParent,
IrReturnTarget, IrMemberWithContainerSource, IrMetadataSourceOwner {
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
abstract override val descriptor: FunctionDescriptor abstract override val descriptor: FunctionDescriptor
@@ -20,8 +20,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.localDelegatedProperty] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.localDelegatedProperty]
*/ */
abstract class IrLocalDelegatedProperty : IrDeclarationBase(), IrDeclarationWithName, abstract class IrLocalDelegatedProperty : IrDeclarationBase(), IrDeclarationWithName, IrSymbolOwner, IrMetadataSourceOwner {
IrSymbolOwner, IrMetadataSourceOwner {
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
abstract override val descriptor: VariableDescriptorWithAccessors abstract override val descriptor: VariableDescriptorWithAccessors
@@ -14,11 +14,9 @@ import org.jetbrains.kotlin.ir.IrElement
* An [IrElement] capable of holding something which backends can use to write * An [IrElement] capable of holding something which backends can use to write
* as the metadata for the declaration. * as the metadata for the declaration.
* *
* Technically, it can even be ± an array of bytes, but right now it's usually the frontend * Technically, it can even be ± an array of bytes, but right now it's usually the frontend representation of the declaration,
* representation of the declaration,
* so a descriptor in case of K1, and [org.jetbrains.kotlin.fir.FirElement] in case of K2, * so a descriptor in case of K1, and [org.jetbrains.kotlin.fir.FirElement] in case of K2,
* and the backend invokes a metadata serializer on it to obtain metadata and write it, for example, * and the backend invokes a metadata serializer on it to obtain metadata and write it, for example, to `@kotlin.Metadata`
* to `@kotlin.Metadata`
* on JVM. * on JVM.
* *
* In Kotlin/Native, [metadata] is used to store some LLVM-related stuff in an IR declaration, * In Kotlin/Native, [metadata] is used to store some LLVM-related stuff in an IR declaration,
@@ -41,8 +41,8 @@ abstract class IrModuleFragment : IrElementBase(), IrElement {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitModuleFragment(this, data) visitor.visitModuleFragment(this, data)
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrModuleFragment =
IrModuleFragment = accept(transformer, data) as IrModuleFragment accept(transformer, data) as IrModuleFragment
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) { override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
files.forEach { it.accept(visitor, data) } files.forEach { it.accept(visitor, data) }
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.descriptors.Modality
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.overridableMember] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.overridableMember]
*/ */
interface IrOverridableMember : IrDeclaration, IrDeclarationWithVisibility, interface IrOverridableMember : IrDeclaration, IrDeclarationWithVisibility, IrDeclarationWithName, IrSymbolOwner {
IrDeclarationWithName, IrSymbolOwner {
var modality: Modality var modality: Modality
} }
@@ -28,9 +28,8 @@ abstract class IrPackageFragment : IrElementBase(), IrDeclarationContainer, IrSy
/** /**
* This should be a link to [IrModuleFragment] instead. * This should be a link to [IrModuleFragment] instead.
* *
* Unfortunately, some package fragments (e.g. some synthetic ones and * Unfortunately, some package fragments (e.g. some synthetic ones and [IrExternalPackageFragment])
* [IrExternalPackageFragment])
* are not located in any IR module, but still have a module descriptor. * are not located in any IR module, but still have a module descriptor.
*/ */
abstract val moduleDescriptor: ModuleDescriptor abstract val moduleDescriptor: ModuleDescriptor
@@ -8,7 +8,6 @@
package org.jetbrains.kotlin.ir.declarations package org.jetbrains.kotlin.ir.declarations
/** /**
* A non-leaf IR tree element. * A non-leaf IR tree element.
* *
@@ -19,9 +19,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.property] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.property]
*/ */
abstract class IrProperty : IrDeclarationBase(), IrPossiblyExternalDeclaration, abstract class IrProperty : IrDeclarationBase(), IrPossiblyExternalDeclaration, IrOverridableDeclaration<IrPropertySymbol>, IrMetadataSourceOwner, IrAttributeContainer, IrMemberWithContainerSource {
IrOverridableDeclaration<IrPropertySymbol>, IrMetadataSourceOwner, IrAttributeContainer,
IrMemberWithContainerSource {
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
abstract override val descriptor: PropertyDescriptor abstract override val descriptor: PropertyDescriptor
@@ -23,8 +23,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.script] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.script]
*/ */
abstract class IrScript : IrDeclarationBase(), IrDeclarationWithName, IrDeclarationParent, abstract class IrScript : IrDeclarationBase(), IrDeclarationWithName, IrDeclarationParent, IrStatementContainer, IrMetadataSourceOwner {
IrStatementContainer, IrMetadataSourceOwner {
abstract override val symbol: IrScriptSymbol abstract override val symbol: IrScriptSymbol
abstract var thisReceiver: IrValueParameter? abstract var thisReceiver: IrValueParameter?
@@ -67,10 +66,8 @@ abstract class IrScript : IrDeclarationBase(), IrDeclarationWithName, IrDeclarat
statements.transformInPlace(transformer, data) statements.transformInPlace(transformer, data)
thisReceiver = thisReceiver?.transform(transformer, data) thisReceiver = thisReceiver?.transform(transformer, data)
explicitCallParameters = explicitCallParameters.transformIfNeeded(transformer, data) explicitCallParameters = explicitCallParameters.transformIfNeeded(transformer, data)
implicitReceiversParameters = implicitReceiversParameters.transformIfNeeded(transformer, implicitReceiversParameters = implicitReceiversParameters.transformIfNeeded(transformer, data)
data) providedPropertiesParameters = providedPropertiesParameters.transformIfNeeded(transformer, data)
providedPropertiesParameters = providedPropertiesParameters.transformIfNeeded(transformer,
data)
earlierScriptsParameter = earlierScriptsParameter?.transform(transformer, data) earlierScriptsParameter = earlierScriptsParameter?.transform(transformer, data)
} }
} }
@@ -17,8 +17,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.simpleFunction] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.simpleFunction]
*/ */
abstract class IrSimpleFunction : IrFunction(), abstract class IrSimpleFunction : IrFunction(), IrOverridableDeclaration<IrSimpleFunctionSymbol>, IrAttributeContainer {
IrOverridableDeclaration<IrSimpleFunctionSymbol>, IrAttributeContainer {
abstract override val symbol: IrSimpleFunctionSymbol abstract override val symbol: IrSimpleFunctionSymbol
abstract var isTailrec: Boolean abstract var isTailrec: Boolean
@@ -21,8 +21,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.typeAlias] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.typeAlias]
*/ */
abstract class IrTypeAlias : IrDeclarationBase(), IrDeclarationWithName, abstract class IrTypeAlias : IrDeclarationBase(), IrDeclarationWithName, IrDeclarationWithVisibility, IrTypeParametersContainer {
IrDeclarationWithVisibility, IrTypeParametersContainer {
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
abstract override val descriptor: TypeAliasDescriptor abstract override val descriptor: TypeAliasDescriptor
@@ -38,6 +38,6 @@ abstract class IrTypeParameter : IrDeclarationBase(), IrDeclarationWithName {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitTypeParameter(this, data) visitor.visitTypeParameter(this, data)
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrTypeParameter =
IrTypeParameter = accept(transformer, data) as IrTypeParameter accept(transformer, data) as IrTypeParameter
} }
@@ -8,7 +8,6 @@
package org.jetbrains.kotlin.ir.declarations package org.jetbrains.kotlin.ir.declarations
/** /**
* A non-leaf IR tree element. * A non-leaf IR tree element.
* *
@@ -40,8 +40,7 @@ abstract class IrValueParameter : IrDeclarationBase(), IrValueDeclaration {
* If `true`, the value parameter does not participate in [IdSignature] computation. * If `true`, the value parameter does not participate in [IdSignature] computation.
* *
* This is a workaround that is needed for better support of compiler plugins. * This is a workaround that is needed for better support of compiler plugins.
* Suppose you have the following code and some IR plugin that adds a value parameter to * Suppose you have the following code and some IR plugin that adds a value parameter to functions
* functions
* marked with the `@PluginMarker` annotation. * marked with the `@PluginMarker` annotation.
* ```kotlin * ```kotlin
* @PluginMarker * @PluginMarker
@@ -55,11 +54,9 @@ abstract class IrValueParameter : IrDeclarationBase(), IrValueDeclaration {
* ``` * ```
* *
* If a compiler plugin adds parameters to an [IrFunction], * If a compiler plugin adds parameters to an [IrFunction],
* the representations of the function in the frontend and in the backend may diverge, * the representations of the function in the frontend and in the backend may diverge, potentially causing signature mismatch and
* potentially causing signature mismatch and
* linkage errors (see [KT-40980](https://youtrack.jetbrains.com/issue/KT-40980)). * linkage errors (see [KT-40980](https://youtrack.jetbrains.com/issue/KT-40980)).
* We wouldn't want IR plugins to affect the frontend representation, since in an IDE you'd want * We wouldn't want IR plugins to affect the frontend representation, since in an IDE you'd want to be able to see those
* to be able to see those
* declarations in their original form (without the `$extra` parameter). * declarations in their original form (without the `$extra` parameter).
* *
* To fix this problem, [isHidden] was introduced. * To fix this problem, [isHidden] was introduced.
@@ -73,8 +70,8 @@ abstract class IrValueParameter : IrDeclarationBase(), IrValueDeclaration {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitValueParameter(this, data) visitor.visitValueParameter(this, data)
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrValueParameter =
IrValueParameter = accept(transformer, data) as IrValueParameter accept(transformer, data) as IrValueParameter
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) { override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
defaultValue?.accept(visitor, data) defaultValue?.accept(visitor, data)
@@ -8,7 +8,6 @@
package org.jetbrains.kotlin.ir.expressions package org.jetbrains.kotlin.ir.expressions
/** /**
* A non-leaf IR tree element. * A non-leaf IR tree element.
* *
@@ -8,7 +8,6 @@
package org.jetbrains.kotlin.ir.expressions package org.jetbrains.kotlin.ir.expressions
/** /**
* A non-leaf IR tree element. * A non-leaf IR tree element.
* *
@@ -20,6 +20,6 @@ abstract class IrElseBranch : IrBranch() {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitElseBranch(this, data) visitor.visitElseBranch(this, data)
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrElseBranch override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrElseBranch =
= accept(transformer, data) as IrElseBranch accept(transformer, data) as IrElseBranch
} }
@@ -19,14 +19,13 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.expression] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.expression]
*/ */
abstract class IrExpression : IrElementBase(), IrStatement, IrVarargElement, abstract class IrExpression : IrElementBase(), IrStatement, IrVarargElement, IrAttributeContainer {
IrAttributeContainer {
override var attributeOwnerId: IrAttributeContainer = this override var attributeOwnerId: IrAttributeContainer = this
override var originalBeforeInline: IrAttributeContainer? = null override var originalBeforeInline: IrAttributeContainer? = null
abstract var type: IrType abstract var type: IrType
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrExpression override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrExpression =
= accept(transformer, data) as IrExpression accept(transformer, data) as IrExpression
} }
@@ -25,8 +25,8 @@ abstract class IrExpressionBody : IrBody() {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitExpressionBody(this, data) visitor.visitExpressionBody(this, data)
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrExpressionBody =
IrExpressionBody = accept(transformer, data) as IrExpressionBody accept(transformer, data) as IrExpressionBody
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) { override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
expression.accept(visitor, data) expression.accept(visitor, data)
@@ -18,8 +18,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
* *
* Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.localDelegatedPropertyReference] * Generated from: [org.jetbrains.kotlin.ir.generator.IrTree.localDelegatedPropertyReference]
*/ */
abstract class IrLocalDelegatedPropertyReference : abstract class IrLocalDelegatedPropertyReference : IrCallableReference<IrLocalDelegatedPropertySymbol>() {
IrCallableReference<IrLocalDelegatedPropertySymbol>() {
abstract var delegate: IrVariableSymbol abstract var delegate: IrVariableSymbol
abstract var getter: IrSimpleFunctionSymbol abstract var getter: IrSimpleFunctionSymbol
@@ -8,7 +8,6 @@
package org.jetbrains.kotlin.ir.expressions package org.jetbrains.kotlin.ir.expressions
/** /**
* A non-leaf IR tree element. * A non-leaf IR tree element.
* *
@@ -38,18 +38,6 @@ abstract class IrMemberAccessExpression<S : IrSymbol> : IrDeclarationReference()
val typeArgumentsCount: Int val typeArgumentsCount: Int
get() = typeArguments.size get() = typeArguments.size
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
dispatchReceiver?.accept(visitor, data)
extensionReceiver?.accept(visitor, data)
valueArguments.forEach { it?.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
dispatchReceiver = dispatchReceiver?.transform(transformer, data)
extensionReceiver = extensionReceiver?.transform(transformer, data)
valueArguments.transformInPlace(transformer, data)
}
fun getValueArgument(index: Int): IrExpression? { fun getValueArgument(index: Int): IrExpression? {
checkArgumentSlotAccess("value", index, valueArguments.size) checkArgumentSlotAccess("value", index, valueArguments.size)
return valueArguments[index] return valueArguments[index]
@@ -69,4 +57,16 @@ abstract class IrMemberAccessExpression<S : IrSymbol> : IrDeclarationReference()
checkArgumentSlotAccess("type", index, typeArguments.size) checkArgumentSlotAccess("type", index, typeArguments.size)
typeArguments[index] = type typeArguments[index] = type
} }
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
dispatchReceiver?.accept(visitor, data)
extensionReceiver?.accept(visitor, data)
valueArguments.forEach { it?.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
dispatchReceiver = dispatchReceiver?.transform(transformer, data)
extensionReceiver = extensionReceiver?.transform(transformer, data)
valueArguments.transformInPlace(transformer, data)
}
} }
@@ -23,8 +23,8 @@ abstract class IrSpreadElement : IrElementBase(), IrVarargElement {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R = override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitSpreadElement(this, data) visitor.visitSpreadElement(this, data)
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrSpreadElement =
IrSpreadElement = accept(transformer, data) as IrSpreadElement accept(transformer, data) as IrSpreadElement
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) { override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
expression.accept(visitor, data) expression.accept(visitor, data)
@@ -34,8 +34,7 @@ abstract class IrSuspensionPoint : IrExpression() {
} }
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) { override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
suspensionPointIdParameter = suspensionPointIdParameter.transform(transformer, data) as suspensionPointIdParameter = suspensionPointIdParameter.transform(transformer, data) as IrVariable
IrVariable
result = result.transform(transformer, data) result = result.transform(transformer, data)
resumeResult = resumeResult.transform(transformer, data) resumeResult = resumeResult.transform(transformer, data)
} }
@@ -12,7 +12,6 @@ dependencies {
implementation(project(":generators")) implementation(project(":generators"))
implementation(project(":generators:tree-generator-common")) implementation(project(":generators:tree-generator-common"))
implementation(project(":compiler:util")) implementation(project(":compiler:util"))
implementation("com.squareup:kotlinpoet:1.11.0")
compileOnly(intellijCore()) compileOnly(intellijCore())
compileOnly(commonDependency("org.jetbrains.intellij.deps:trove4j")) compileOnly(commonDependency("org.jetbrains.intellij.deps:trove4j"))
@@ -6,13 +6,14 @@
package org.jetbrains.kotlin.ir.generator package org.jetbrains.kotlin.ir.generator
import org.jetbrains.kotlin.generators.tree.TypeKind import org.jetbrains.kotlin.generators.tree.TypeKind
import org.jetbrains.kotlin.generators.tree.type
import org.jetbrains.kotlin.ir.generator.Packages.declarations import org.jetbrains.kotlin.ir.generator.Packages.declarations
import org.jetbrains.kotlin.ir.generator.Packages.exprs import org.jetbrains.kotlin.ir.generator.Packages.exprs
import org.jetbrains.kotlin.ir.generator.Packages.symbols import org.jetbrains.kotlin.ir.generator.Packages.symbols
import org.jetbrains.kotlin.ir.generator.Packages.tree import org.jetbrains.kotlin.ir.generator.Packages.tree
import org.jetbrains.kotlin.ir.generator.Packages.types import org.jetbrains.kotlin.ir.generator.Packages.types
import org.jetbrains.kotlin.ir.generator.Packages.util
import org.jetbrains.kotlin.ir.generator.Packages.visitors import org.jetbrains.kotlin.ir.generator.Packages.visitors
import org.jetbrains.kotlin.generators.tree.type
object Packages { object Packages {
const val tree = "org.jetbrains.kotlin.ir" const val tree = "org.jetbrains.kotlin.ir"
@@ -22,6 +23,7 @@ object Packages {
const val types = "org.jetbrains.kotlin.ir.types" const val types = "org.jetbrains.kotlin.ir.types"
const val visitors = "org.jetbrains.kotlin.ir.visitors" const val visitors = "org.jetbrains.kotlin.ir.visitors"
const val descriptors = "org.jetbrains.kotlin.descriptors" const val descriptors = "org.jetbrains.kotlin.descriptors"
const val util = "org.jetbrains.kotlin.ir.util"
} }
val elementBaseType = type(tree, "IrElementBase", TypeKind.Class) val elementBaseType = type(tree, "IrElementBase", TypeKind.Class)
@@ -34,6 +36,7 @@ val mutableAnnotationContainerType = type(declarations, "IrMutableAnnotationCont
val irTypeType = type(types, "IrType") val irTypeType = type(types, "IrType")
val irFactoryType = type(declarations, "IrFactory") val irFactoryType = type(declarations, "IrFactory")
val stageControllerType = type(declarations, "StageController", TypeKind.Class) val stageControllerType = type(declarations, "StageController", TypeKind.Class)
val idSignatureType = type(util, "IdSignature", TypeKind.Class)
val symbolType = type(symbols, "IrSymbol") val symbolType = type(symbols, "IrSymbol")
val packageFragmentSymbolType = type(symbols, "IrPackageFragmentSymbol") val packageFragmentSymbolType = type(symbols, "IrPackageFragmentSymbol")
@@ -57,3 +60,6 @@ val returnableBlockSymbolType = type(symbols, "IrReturnableBlockSymbol")
val propertySymbolType = type(symbols, "IrPropertySymbol") val propertySymbolType = type(symbols, "IrPropertySymbol")
val localDelegatedPropertySymbolType = type(symbols, "IrLocalDelegatedPropertySymbol") val localDelegatedPropertySymbolType = type(symbols, "IrLocalDelegatedPropertySymbol")
val typeAliasSymbolType = type(symbols, "IrTypeAliasSymbol") val typeAliasSymbolType = type(symbols, "IrTypeAliasSymbol")
val obsoleteDescriptorBasedApiAnnotation = type(BASE_PACKAGE, "ObsoleteDescriptorBasedAPI", TypeKind.Class)
val unsafeDuringIrConstructionApiAnnotation = type(symbols, "UnsafeDuringIrConstructionAPI", TypeKind.Class)
@@ -5,27 +5,26 @@
package org.jetbrains.kotlin.ir.generator package org.jetbrains.kotlin.ir.generator
import com.squareup.kotlinpoet.*
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.ValueClassRepresentation import org.jetbrains.kotlin.descriptors.ValueClassRepresentation
import org.jetbrains.kotlin.generators.tree.* import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.generators.tree.printer.FunctionParameter
import org.jetbrains.kotlin.generators.tree.printer.printFunctionDeclaration
import org.jetbrains.kotlin.ir.generator.config.AbstractTreeBuilder import org.jetbrains.kotlin.ir.generator.config.AbstractTreeBuilder
import org.jetbrains.kotlin.ir.generator.config.ElementConfig import org.jetbrains.kotlin.ir.generator.config.ElementConfig
import org.jetbrains.kotlin.ir.generator.config.ElementConfig.Category.* import org.jetbrains.kotlin.ir.generator.config.ElementConfig.Category.*
import org.jetbrains.kotlin.ir.generator.config.ListFieldConfig.Mutability.*
import org.jetbrains.kotlin.ir.generator.config.ListFieldConfig.Mutability.Array import org.jetbrains.kotlin.ir.generator.config.ListFieldConfig.Mutability.Array
import org.jetbrains.kotlin.ir.generator.config.ListFieldConfig.Mutability.List import org.jetbrains.kotlin.ir.generator.config.ListFieldConfig.Mutability.List
import org.jetbrains.kotlin.ir.generator.config.ListFieldConfig.Mutability.Var
import org.jetbrains.kotlin.ir.generator.config.SimpleFieldConfig import org.jetbrains.kotlin.ir.generator.config.SimpleFieldConfig
import org.jetbrains.kotlin.ir.generator.model.Element.Companion.elementName2typeName import org.jetbrains.kotlin.ir.generator.model.Element.Companion.elementName2typeName
import org.jetbrains.kotlin.ir.generator.print.toPoet
import org.jetbrains.kotlin.ir.generator.util.*
import org.jetbrains.kotlin.ir.generator.util.Import
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.withIndent
// Note the style of the DSL to describe IR elements, which is these things in the following order: // Note the style of the DSL to describe IR elements, which is these things in the following order:
// 1) config (see properties of ElementConfig) // 1) config (see properties of ElementConfig)
@@ -38,10 +37,11 @@ object IrTree : AbstractTreeBuilder() {
private fun descriptor(typeName: String, nullable: Boolean = false): SimpleFieldConfig = private fun descriptor(typeName: String, nullable: Boolean = false): SimpleFieldConfig =
field( field(
name = "descriptor", name = "descriptor",
type = ClassRef<TypeParameterRef>(TypeKind.Interface, Packages.descriptors, typeName), type = type(Packages.descriptors, typeName),
mutable = false, mutable = false,
nullable = nullable, nullable = nullable,
) { ) {
optInAnnotation = obsoleteDescriptorBasedApiAnnotation
skipInIrFactory() skipInIrFactory()
} }
@@ -55,16 +55,15 @@ object IrTree : AbstractTreeBuilder() {
skipInIrFactory() skipInIrFactory()
} }
val oldCallback = generationCallback
generationCallback = { generationCallback = {
oldCallback?.invoke(this) println()
addFunction( printFunctionDeclaration(
FunSpec.builder("acquireSymbol") name = "acquireSymbol",
.addModifiers(KModifier.ABSTRACT) parameters = listOf(FunctionParameter("symbol", symbol)),
.addParameter("symbol", symbol.toPoet()) returnType = this@element,
.returns(this@element.toPoet()) modality = Modality.ABSTRACT,
.build(),
) )
println()
} }
} }
@@ -208,7 +207,7 @@ object IrTree : AbstractTreeBuilder() {
+field("isCrossinline", boolean) +field("isCrossinline", boolean)
+field("isNoinline", boolean) +field("isNoinline", boolean)
+field("isHidden", boolean) { +field("isHidden", boolean) {
additionalImports.add(Import("org.jetbrains.kotlin.ir.util", "IdSignature")) usedTypes.add(idSignatureType)
kDoc = """ kDoc = """
If `true`, the value parameter does not participate in [IdSignature] computation. If `true`, the value parameter does not participate in [IdSignature] computation.
@@ -349,9 +348,7 @@ object IrTree : AbstractTreeBuilder() {
before IR for all sources is built (because fake-overrides of lazy classes may depend on before IR for all sources is built (because fake-overrides of lazy classes may depend on
declaration of source classes, e.g. for java source classes) declaration of source classes, e.g. for java source classes)
""".trimIndent() """.trimIndent()
generationCallback = { optInAnnotation = unsafeDuringIrConstructionApiAnnotation
addAnnotation(ClassName("org.jetbrains.kotlin.ir.symbols", "UnsafeDuringIrConstructionAPI"))
}
} }
} }
val typeParametersContainer: ElementConfig by element(Declaration) { val typeParametersContainer: ElementConfig by element(Declaration) {
@@ -446,7 +443,7 @@ object IrTree : AbstractTreeBuilder() {
fieldsToSkipInIrFactoryMethod.add("origin") fieldsToSkipInIrFactoryMethod.add("origin")
+field("symbol", symbolType, mutable = false) { +field("symbol", symbolType, mutable = false) {
baseGetter = code("error(\"Should never be called\")") baseGetter = "error(\"Should never be called\")"
skipInIrFactory() skipInIrFactory()
} }
} }
@@ -497,16 +494,18 @@ object IrTree : AbstractTreeBuilder() {
transformByChildren = true transformByChildren = true
generateIrFactoryMethod = false generateIrFactoryMethod = false
+descriptor("ModuleDescriptor") +descriptor("ModuleDescriptor").apply {
optInAnnotation = null
}
+field("name", type<Name>(), mutable = false) +field("name", type<Name>(), mutable = false)
+field("irBuiltins", type(Packages.tree, "IrBuiltIns"), mutable = false) +field("irBuiltins", type(Packages.tree, "IrBuiltIns"), mutable = false)
+listField("files", file, mutability = List, isChild = true) +listField("files", file, mutability = List, isChild = true)
val undefinedOffset = MemberName(Packages.tree, "UNDEFINED_OFFSET") usedTypes += ArbitraryImportable(Packages.tree, "UNDEFINED_OFFSET")
+field("startOffset", int, mutable = false) { +field("startOffset", int, mutable = false) {
baseGetter = code("%M", undefinedOffset) baseGetter = "UNDEFINED_OFFSET"
} }
+field("endOffset", int, mutable = false) { +field("endOffset", int, mutable = false) {
baseGetter = code("%M", undefinedOffset) baseGetter = "UNDEFINED_OFFSET"
} }
} }
val property: ElementConfig by element(Declaration) { val property: ElementConfig by element(Declaration) {
@@ -621,7 +620,9 @@ object IrTree : AbstractTreeBuilder() {
parent(symbolOwner) parent(symbolOwner)
+symbol(packageFragmentSymbolType) +symbol(packageFragmentSymbolType)
+field("packageFragmentDescriptor", type(Packages.descriptors, "PackageFragmentDescriptor"), mutable = false) +field("packageFragmentDescriptor", type(Packages.descriptors, "PackageFragmentDescriptor"), mutable = false) {
optInAnnotation = obsoleteDescriptorBasedApiAnnotation
}
+field("moduleDescriptor", type(Packages.descriptors, "ModuleDescriptor"), mutable = false) { +field("moduleDescriptor", type(Packages.descriptors, "ModuleDescriptor"), mutable = false) {
kDoc = """ kDoc = """
This should be a link to [IrModuleFragment] instead. This should be a link to [IrModuleFragment] instead.
@@ -632,16 +633,13 @@ object IrTree : AbstractTreeBuilder() {
} }
+field("packageFqName", type<FqName>()) +field("packageFqName", type<FqName>())
+field("fqName", type<FqName>()) { +field("fqName", type<FqName>()) {
baseGetter = code("packageFqName") baseGetter = "packageFqName"
generationCallback = { customSetter = "packageFqName = value"
val deprecatedAnnotation = AnnotationSpec.builder(Deprecated::class) deprecation = Deprecated(
.addMember(code("message = \"Please use `packageFqName` instead\"")) "Please use `packageFqName` instead",
.addMember(code("replaceWith = ReplaceWith(\"packageFqName\")")) ReplaceWith("packageFqName"),
.addMember(code("level = DeprecationLevel.ERROR")) DeprecationLevel.ERROR,
.build() )
addAnnotation(deprecatedAnnotation)
setter(FunSpec.setterBuilder().addParameter("value", FqName::class).addCode(code("packageFqName = value")).build())
}
} }
} }
val externalPackageFragment: ElementConfig by element(Declaration) { val externalPackageFragment: ElementConfig by element(Declaration) {
@@ -679,11 +677,11 @@ object IrTree : AbstractTreeBuilder() {
parent(attributeContainer) parent(attributeContainer)
+field("attributeOwnerId", attributeContainer) { +field("attributeOwnerId", attributeContainer) {
baseDefaultValue = code("this") baseDefaultValue = "this"
skipInIrFactory() skipInIrFactory()
} }
+field("originalBeforeInline", attributeContainer, nullable = true) { +field("originalBeforeInline", attributeContainer, nullable = true) {
baseDefaultValue = code("null") baseDefaultValue = "null"
skipInIrFactory() skipInIrFactory()
} }
+field("type", irTypeType) +field("type", irTypeType)
@@ -740,67 +738,79 @@ object IrTree : AbstractTreeBuilder() {
parent(declarationReference) parent(declarationReference)
+field("dispatchReceiver", expression, nullable = true, isChild = true) { +field("dispatchReceiver", expression, nullable = true, isChild = true) {
baseDefaultValue = code("null") baseDefaultValue = "null"
} }
+field("extensionReceiver", expression, nullable = true, isChild = true) { +field("extensionReceiver", expression, nullable = true, isChild = true) {
baseDefaultValue = code("null") baseDefaultValue = "null"
} }
+symbol(s) +symbol(s)
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
+listField("valueArguments", expression.copy(nullable = true), mutability = Array, isChild = true) { +listField("valueArguments", expression.copy(nullable = true), mutability = Array, isChild = true) {
generationCallback = { visibility = Visibility.PROTECTED
addModifiers(KModifier.PROTECTED)
}
} }
+listField("typeArguments", irTypeType.copy(nullable = true), mutability = Array) { +listField("typeArguments", irTypeType.copy(nullable = true), mutability = Array) {
generationCallback = { visibility = Visibility.PROTECTED
addModifiers(KModifier.PROTECTED)
}
} }
val checkArgumentSlotAccess = MemberName("org.jetbrains.kotlin.ir.expressions", "checkArgumentSlotAccess", true) usedTypes += ArbitraryImportable(Packages.exprs, "checkArgumentSlotAccess")
generationCallback = { generationCallback = {
addFunction( val indexParam = FunctionParameter("index", StandardTypes.int)
FunSpec.builder("getValueArgument") val valueArgumentParam = FunctionParameter("valueArgument", expression.copy(nullable = true))
.addParameter("index", int.toPoet()) val typeArgumentParam = FunctionParameter("type", irTypeType.copy(nullable = true))
.returns(expression.toPoet().copy(nullable = true))
.addCode("%M(\"value\", index, valueArguments.size)\n", checkArgumentSlotAccess) fun printSizeProperty(listName: String) {
.addCode("return valueArguments[index]") println()
.build() println("val ", listName, "Count: Int")
withIndent {
println("get() = ", listName, ".size")
}
}
printSizeProperty("valueArguments")
printSizeProperty("typeArguments")
fun printFunction(
name: String,
additionalParameter: FunctionParameter?,
returnType: TypeRefWithNullability,
vararg statements: String,
) {
println()
printFunctionDeclaration(name, listOf(indexParam) + listOfNotNull(additionalParameter), returnType)
println(" {")
withIndent {
statements.forEach { println(it) }
}
println("}")
}
printFunction(
"getValueArgument",
null,
expression.copy(nullable = true),
"checkArgumentSlotAccess(\"value\", index, valueArguments.size)",
"return valueArguments[index]",
) )
addFunction( printFunction(
FunSpec.builder("getTypeArgument") "getTypeArgument",
.addParameter("index", int.toPoet()) null,
.returns(irTypeType.toPoet().copy(nullable = true)) irTypeType.copy(nullable = true),
.addCode("%M(\"type\", index, typeArguments.size)\n", checkArgumentSlotAccess) "checkArgumentSlotAccess(\"type\", index, typeArguments.size)",
.addCode("return typeArguments[index]") "return typeArguments[index]",
.build()
) )
addFunction( printFunction(
FunSpec.builder("putValueArgument") "putValueArgument",
.addParameter("index", int.toPoet()) valueArgumentParam,
.addParameter("valueArgument", expression.toPoet().copy(nullable = true)) StandardTypes.unit,
.addCode("%M(\"value\", index, valueArguments.size)\n", checkArgumentSlotAccess) "checkArgumentSlotAccess(\"value\", index, valueArguments.size)",
.addCode("valueArguments[index] = valueArgument") "valueArguments[index] = valueArgument",
.build()
) )
addFunction( printFunction(
FunSpec.builder("putTypeArgument") "putTypeArgument",
.addParameter("index", int.toPoet()) typeArgumentParam,
.addParameter("type", irTypeType.toPoet().copy(nullable = true)) StandardTypes.unit,
.addCode("%M(\"type\", index, typeArguments.size)\n", checkArgumentSlotAccess) "checkArgumentSlotAccess(\"type\", index, typeArguments.size)",
.addCode("typeArguments[index] = type") "typeArguments[index] = type",
.build()
)
addProperty(
PropertySpec.builder("valueArgumentsCount", int.toPoet())
.getter(FunSpec.getterBuilder().addCode("return valueArguments.size").build())
.build()
)
addProperty(
PropertySpec.builder("typeArgumentsCount", int.toPoet())
.getter(FunSpec.getterBuilder().addCode("return typeArguments.size").build())
.build()
) )
} }
} }
@@ -867,10 +877,7 @@ object IrTree : AbstractTreeBuilder() {
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
+listField("statements", statement, mutability = List, isChild = true) { +listField("statements", statement, mutability = List, isChild = true) {
generationCallback = { baseDefaultValue = "ArrayList(2)"
addModifiers(KModifier.OVERRIDE)
}
baseDefaultValue = code("ArrayList(2)")
} }
} }
val block: ElementConfig by element(Expression) { val block: ElementConfig by element(Expression) {
@@ -913,7 +920,7 @@ object IrTree : AbstractTreeBuilder() {
+field("loop", loop) +field("loop", loop)
+field("label", string, nullable = true) { +field("label", string, nullable = true) {
baseDefaultValue = code("null") baseDefaultValue = "null"
} }
} }
val `break` by element(Expression) { val `break` by element(Expression) {
@@ -993,19 +1000,22 @@ object IrTree : AbstractTreeBuilder() {
parent(expression) parent(expression)
generationCallback = { generationCallback = {
addFunction( println()
FunSpec.builder("contentEquals") printFunctionDeclaration(
.addModifiers(KModifier.ABSTRACT) name = "contentEquals",
.addParameter("other", constantValue.toPoet()) parameters = listOf(FunctionParameter("other", constantValue)),
.returns(boolean.toPoet()) returnType = StandardTypes.boolean,
.build() modality = Modality.ABSTRACT,
) )
addFunction( println()
FunSpec.builder("contentHashCode") println()
.addModifiers(KModifier.ABSTRACT) printFunctionDeclaration(
.returns(int.toPoet()) name = "contentHashCode",
.build() parameters = emptyList(),
returnType = StandardTypes.int,
modality = Modality.ABSTRACT,
) )
println()
} }
} }
val constantPrimitive: ElementConfig by element(Expression) { val constantPrimitive: ElementConfig by element(Expression) {
@@ -1093,7 +1103,7 @@ object IrTree : AbstractTreeBuilder() {
+symbol(fieldSymbolType, mutable = true) +symbol(fieldSymbolType, mutable = true)
+field("superQualifierSymbol", classSymbolType, nullable = true) +field("superQualifierSymbol", classSymbolType, nullable = true)
+field("receiver", expression, nullable = true, isChild = true) { +field("receiver", expression, nullable = true, isChild = true) {
baseDefaultValue = code("null") baseDefaultValue = "null"
} }
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
} }
@@ -1141,11 +1151,11 @@ object IrTree : AbstractTreeBuilder() {
+field("origin", statementOriginType, nullable = true) +field("origin", statementOriginType, nullable = true)
+field("body", expression, nullable = true, isChild = true) { +field("body", expression, nullable = true, isChild = true) {
baseDefaultValue = code("null") baseDefaultValue = "null"
} }
+field("condition", expression, isChild = true) +field("condition", expression, isChild = true)
+field("label", string, nullable = true) { +field("label", string, nullable = true) {
baseDefaultValue = code("null") baseDefaultValue = "null"
} }
} }
val whileLoop: ElementConfig by element(Expression) { val whileLoop: ElementConfig by element(Expression) {
@@ -13,7 +13,8 @@ import org.jetbrains.kotlin.ir.generator.print.*
import java.io.File import java.io.File
const val BASE_PACKAGE = "org.jetbrains.kotlin.ir" const val BASE_PACKAGE = "org.jetbrains.kotlin.ir"
const val VISITOR_PACKAGE = "$BASE_PACKAGE.visitors"
internal const val TREE_GENERATOR_README = "compiler/ir/ir.tree/tree-generator/ReadMe.md"
fun main(args: Array<String>) { fun main(args: Array<String>) {
val generationPath = args.firstOrNull()?.let { File(it) } val generationPath = args.firstOrNull()?.let { File(it) }
@@ -5,13 +5,10 @@
package org.jetbrains.kotlin.ir.generator.config package org.jetbrains.kotlin.ir.generator.config
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeSpec
import org.jetbrains.kotlin.generators.tree.* import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.BASE_PACKAGE import org.jetbrains.kotlin.ir.generator.BASE_PACKAGE
import org.jetbrains.kotlin.ir.generator.model.Element import org.jetbrains.kotlin.ir.generator.model.Element
import org.jetbrains.kotlin.ir.generator.util.* import org.jetbrains.kotlin.utils.SmartPrinter
class Config( class Config(
val elements: List<ElementConfig>, val elements: List<ElementConfig>,
@@ -26,7 +23,7 @@ class ElementConfig(
val params = mutableListOf<TypeVariable>() val params = mutableListOf<TypeVariable>()
val parents = mutableListOf<TypeRef>() val parents = mutableListOf<TypeRef>()
val fields = mutableListOf<FieldConfig>() val fields = mutableListOf<FieldConfig>()
val additionalImports = mutableListOf<Import>() val usedTypes = mutableListOf<Importable>()
var visitorName: String? = null var visitorName: String? = null
var visitorParent: ElementConfig? = null var visitorParent: ElementConfig? = null
@@ -53,7 +50,7 @@ class ElementConfig(
var typeKind: TypeKind? = null var typeKind: TypeKind? = null
var generationCallback: (TypeSpec.Builder.() -> Unit)? = null var generationCallback: (context(ImportCollector) SmartPrinter.() -> Unit)? = null
var kDoc: String? = null var kDoc: String? = null
override val element get() = this override val element get() = this
@@ -139,10 +136,14 @@ sealed class FieldConfig(
val name: String, val name: String,
val isChild: Boolean, val isChild: Boolean,
) { ) {
var baseDefaultValue: CodeBlock? = null var baseDefaultValue: String? = null
var baseGetter: CodeBlock? = null var baseGetter: String? = null
var printProperty = true var customSetter: String? = null
var strictCastInTransformChildren = false var optInAnnotation: ClassRef<*>? = null
var deprecation: Deprecated? = null
var visibility = Visibility.PUBLIC
internal var useFieldInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy = internal var useFieldInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy =
if (isChild) UseFieldAsParameterInIrFactoryStrategy.No else UseFieldAsParameterInIrFactoryStrategy.Yes(null) if (isChild) UseFieldAsParameterInIrFactoryStrategy.No else UseFieldAsParameterInIrFactoryStrategy.Yes(null)
@@ -157,8 +158,6 @@ sealed class FieldConfig(
var kDoc: String? = null var kDoc: String? = null
var generationCallback: (PropertySpec.Builder.() -> Unit)? = null
override fun toString() = name override fun toString() = name
} }
@@ -5,11 +5,9 @@
package org.jetbrains.kotlin.ir.generator.model package org.jetbrains.kotlin.ir.generator.model
import com.squareup.kotlinpoet.CodeBlock
import org.jetbrains.kotlin.generators.tree.* import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.config.ElementConfig import org.jetbrains.kotlin.ir.generator.config.ElementConfig
import org.jetbrains.kotlin.ir.generator.config.FieldConfig import org.jetbrains.kotlin.ir.generator.config.FieldConfig
import org.jetbrains.kotlin.ir.generator.util.*
import org.jetbrains.kotlin.utils.topologicalSort import org.jetbrains.kotlin.utils.topologicalSort
import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
@@ -77,7 +75,7 @@ class Element(
override val kDoc = config.kDoc override val kDoc = config.kDoc
val additionalImports: List<Import> = config.additionalImports val usedTypes: List<Importable> = config.usedTypes
override fun toString() = name override fun toString() = name
@@ -112,25 +110,33 @@ class Element(
typealias ElementRef = GenericElementRef<Element, Field> typealias ElementRef = GenericElementRef<Element, Field>
typealias ElementOrRef = GenericElementOrRef<Element, Field> typealias ElementOrRef = GenericElementOrRef<Element, Field>
@Suppress("LeakingThis")
sealed class Field( sealed class Field(
config: FieldConfig, config: FieldConfig,
override val name: String, override val name: String,
override var isMutable: Boolean, override var isMutable: Boolean,
val isChild: Boolean, val isChild: Boolean,
) : AbstractField() { ) : AbstractField() {
abstract val baseDefaultValue: CodeBlock? abstract val baseDefaultValue: String?
abstract val baseGetter: CodeBlock? abstract val baseGetter: String?
var isOverride = false
var needsDescriptorApiAnnotation = false
abstract val transformable: Boolean abstract val transformable: Boolean
val useInIrFactoryStrategy = config.useFieldInIrFactoryStrategy val useInIrFactoryStrategy = config.useFieldInIrFactoryStrategy
init { init {
kDoc = config.kDoc kDoc = config.kDoc
optInAnnotation = config.optInAnnotation
deprecation = config.deprecation
visibility = config.visibility
} }
val printProperty = config.printProperty override val withGetter: Boolean
val generationCallback = config.generationCallback get() = baseGetter != null
override val defaultValueInImplementation: String?
get() = baseGetter ?: baseDefaultValue
override val customSetter: String? = config.customSetter
override fun toString() = "$name: $typeRef" override fun toString() = "$name: $typeRef"
@@ -138,7 +144,7 @@ sealed class Field(
get() = false get() = false
override val isFinal: Boolean override val isFinal: Boolean
get() = false get() = defaultValueInImplementation != null
override val isLateinit: Boolean override val isLateinit: Boolean
get() = false get() = false
@@ -153,8 +159,8 @@ class SingleField(
override var typeRef: TypeRefWithNullability, override var typeRef: TypeRefWithNullability,
mutable: Boolean, mutable: Boolean,
isChild: Boolean, isChild: Boolean,
override val baseDefaultValue: CodeBlock?, override val baseDefaultValue: String?,
override val baseGetter: CodeBlock?, override val baseGetter: String?,
) : Field(config, name, mutable, isChild) { ) : Field(config, name, mutable, isChild) {
override val transformable: Boolean override val transformable: Boolean
get() = isMutable get() = isMutable
@@ -168,8 +174,8 @@ class ListField(
mutable: Boolean, mutable: Boolean,
isChild: Boolean, isChild: Boolean,
override val transformable: Boolean, override val transformable: Boolean,
override val baseDefaultValue: CodeBlock?, override val baseDefaultValue: String?,
override val baseGetter: CodeBlock?, override val baseGetter: String?,
) : Field(config, name, mutable, isChild) { ) : Field(config, name, mutable, isChild) {
override val typeRef: TypeRefWithNullability override val typeRef: TypeRefWithNullability
get() = listType.withArgs(elementType) get() = listType.withArgs(elementType)
@@ -50,7 +50,6 @@ fun config2model(config: Config): Model {
configureInterfacesAndAbstractClasses(elements) configureInterfacesAndAbstractClasses(elements)
addPureAbstractElement(elements, elementBaseType) addPureAbstractElement(elements, elementBaseType)
markLeaves(elements) markLeaves(elements)
configureDescriptorApiAnnotation(elements)
processFieldOverrides(elements) processFieldOverrides(elements)
addWalkableChildren(elements) addWalkableChildren(elements)
@@ -160,19 +159,6 @@ private fun markLeaves(elements: List<Element>) {
} }
} }
private fun configureDescriptorApiAnnotation(elements: List<Element>) {
for (el in elements) {
for (field in el.fields) {
val type = field.typeRef
if (type is ClassRef<*> && type.packageName.startsWith("org.jetbrains.kotlin.descriptors") &&
type.simpleName.endsWith("Descriptor") && type.simpleName != "ModuleDescriptor"
) {
field.needsDescriptorApiAnnotation = true
}
}
}
}
private fun processFieldOverrides(elements: List<Element>) { private fun processFieldOverrides(elements: List<Element>) {
for (element in iterateElementsParentFirst(elements)) { for (element in iterateElementsParentFirst(elements)) {
for (field in element.fields) { for (field in element.fields) {
@@ -180,9 +166,8 @@ private fun processFieldOverrides(elements: List<Element>) {
for (parent in visited.elementParents) { for (parent in visited.elementParents) {
val overriddenField = parent.element.fields.singleOrNull { it.name == field.name } val overriddenField = parent.element.fields.singleOrNull { it.name == field.name }
if (overriddenField != null) { if (overriddenField != null) {
field.isOverride = true field.fromParent = true
field.needsDescriptorApiAnnotation = field.optInAnnotation = field.optInAnnotation ?: overriddenField.optInAnnotation
field.needsDescriptorApiAnnotation || overriddenField.needsDescriptorApiAnnotation
fun transformInferredType(type: TypeRef, overriddenType: TypeRef) = fun transformInferredType(type: TypeRef, overriddenType: TypeRef) =
type.takeUnless { it is InferredOverriddenType } ?: overriddenType type.takeUnless { it is InferredOverriddenType } ?: overriddenType
@@ -1,48 +0,0 @@
/*
* Copyright 2010-2021 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.ir.generator.print
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.TypeSpec
import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
import org.jetbrains.kotlin.ir.generator.util.Import
import java.io.File
internal const val TREE_GENERATOR_README = "compiler/ir/ir.tree/tree-generator/ReadMe.md"
fun printTypeCommon(
generationPath: File,
packageName: String,
type: TypeSpec,
additionalImports: List<Import> = emptyList(),
): GeneratedFile = printGeneratedType(generationPath, TREE_GENERATOR_README, packageName, type.name!!) {
val code = FileSpec.builder(packageName, type.name!!)
.apply {
additionalImports.forEach { addImport(it.packageName, it.className) }
}
.indent(" ")
.addType(type)
.build()
.toString()
.replace("package $packageName\n\n", "")
.unbacktickIdentifiers("data", "value", "operator", "constructor", "delegate", "receiver", "field")
.replace("public ", "")
.replace(":\\s*Unit".toRegex(), "")
.replace("import kotlin\\..*\\n".toRegex(), "")
// Half-baked attempt to remove double indent generated by KotlinPoet, which is not idiomatic according to the Kotlin style guide
.replace(" visitor.visit", " visitor.visit")
.replace(" accept(transformer, data)", " accept(transformer, data)")
print(code)
}
private fun String.unbacktickIdentifiers(vararg identifiers: String): String {
var result = this
for (identifier in identifiers) {
result = result.replace("`$identifier`", identifier)
}
return result
}
@@ -5,278 +5,172 @@
package org.jetbrains.kotlin.ir.generator.print package org.jetbrains.kotlin.ir.generator.print
import com.squareup.kotlinpoet.* import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.generators.tree.ImplementationKind import org.jetbrains.kotlin.generators.tree.printer.*
import org.jetbrains.kotlin.generators.tree.TypeKind
import org.jetbrains.kotlin.ir.generator.BASE_PACKAGE import org.jetbrains.kotlin.ir.generator.BASE_PACKAGE
import org.jetbrains.kotlin.ir.generator.TREE_GENERATOR_README
import org.jetbrains.kotlin.ir.generator.elementTransformerType import org.jetbrains.kotlin.ir.generator.elementTransformerType
import org.jetbrains.kotlin.ir.generator.elementVisitorType import org.jetbrains.kotlin.ir.generator.elementVisitorType
import org.jetbrains.kotlin.ir.generator.model.* import org.jetbrains.kotlin.ir.generator.model.*
import org.jetbrains.kotlin.generators.tree.TypeRefWithNullability import org.jetbrains.kotlin.utils.SmartPrinter
import org.jetbrains.kotlin.generators.tree.typeKind import org.jetbrains.kotlin.utils.withIndent
import org.jetbrains.kotlin.generators.tree.printer.extendedKDoc
import org.jetbrains.kotlin.ir.generator.util.tryParameterizedBy
import java.io.File import java.io.File
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
fun printElements(generationPath: File, model: Model) = sequence { private val transformIfNeeded = ArbitraryImportable("$BASE_PACKAGE.util", "transformIfNeeded")
for (element in model.elements) { private val transformInPlace = ArbitraryImportable("$BASE_PACKAGE.util", "transformInPlace")
val elementName = element.toPoet() private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter<Element, Field>(printer) {
val selfParametrizedElementName = element.toPoetSelfParameterized()
val elementType = when (element.kind?.typeKind) { override fun makeFieldPrinter(printer: SmartPrinter) = object : AbstractFieldPrinter<Field>(printer) {
null -> error("Element's category not configured") override fun forceMutable(field: Field) = field.isMutable
TypeKind.Class -> TypeSpec.classBuilder(elementName) }
TypeKind.Interface -> TypeSpec.interfaceBuilder(elementName)
}.apply { override fun defaultElementKDoc(element: Element) =
addModifiers( "A ${if (element.isLeaf) "leaf" else "non-leaf"} IR tree element."
when (element.kind) {
ImplementationKind.SealedClass -> listOf(KModifier.SEALED) override val separateFieldsWithBlankLine: Boolean
ImplementationKind.SealedInterface -> listOf(KModifier.SEALED) get() = true
ImplementationKind.AbstractClass -> listOf(KModifier.ABSTRACT)
ImplementationKind.FinalClass -> listOf(KModifier.FINAL) context(ImportCollector)
ImplementationKind.OpenClass -> listOf(KModifier.OPEN) override fun SmartPrinter.printAdditionalMethods(element: Element) {
else -> emptyList() element.generationCallback?.invoke(this@ImportCollector, this)
}
if (element.hasAcceptMethod) {
printAcceptMethod(
element = element,
visitorClass = elementVisitorType,
hasImplementation = !element.isRootElement,
kDoc = """
Runs the provided [visitor] on the IR subtree with the root at this node.
@param visitor The visitor to accept.
@param data An arbitrary context to pass to each invocation of [visitor]'s methods.
@return The value returned by the topmost `visit*` invocation.
""".trimIndent().takeIf { element.isRootElement }
) )
addTypeVariables(element.params.map { it.toPoet() }) }
val (classes, interfaces) = element.parentRefs.partition { it.typeKind == TypeKind.Class } if (element.hasTransformMethod) {
classes.singleOrNull()?.let { printTransformMethod(
superclass(it.toPoet()) element = element,
} transformerClass = elementTransformerType,
addSuperinterfaces(interfaces.map { it.toPoet() }) implementation = "accept(transformer, data)".takeIf { !element.isRootElement },
returnType = element,
kDoc = """
Runs the provided [transformer] on the IR subtree with the root at this node.
@param transformer The transformer to use.
@param data An arbitrary context to pass to each invocation of [transformer]'s methods.
@return The transformed node.
""".trimIndent().takeIf { element.isRootElement }
)
}
for (field in element.fields) { if (element.hasAcceptChildrenMethod) {
if (!field.printProperty) continue printAcceptChildrenMethod(
val poetType = field.typeRef.toPoet().copy(nullable = field.nullable) element = element,
addProperty(PropertySpec.builder(field.name, poetType).apply { visitorClass = elementVisitorType,
mutable(field.isMutable) visitorResultType = StandardTypes.unit,
if (field.isOverride) { override = !element.isRootElement,
addModifiers(KModifier.OVERRIDE) kDoc = """
} Runs the provided [visitor] on subtrees with roots in this node's children.
if (field.baseDefaultValue == null && field.baseGetter == null) {
addModifiers(KModifier.ABSTRACT) Basically, calls `accept(visitor, data)` on each child of this node.
}
Does **not** run [visitor] on this node itself.
field.baseDefaultValue?.let {
initializer(it) @param visitor The visitor for children to accept.
} @param data An arbitrary context to pass to each invocation of [visitor]'s methods.
field.baseGetter?.let { """.trimIndent().takeIf { element.isRootElement }
getter(FunSpec.getterBuilder().addCode("return ").addCode(it).build()) )
}
if (field.needsDescriptorApiAnnotation) {
addAnnotation(descriptorApiAnnotation)
}
field.kDoc?.let {
addKdoc(it)
}
field.generationCallback?.invoke(this)
}.build())
}
val isRootElement = element.isRootElement
val acceptMethodName = "accept"
val transformMethodName = "transform"
if (element.hasAcceptMethod) {
addFunction(FunSpec.builder(acceptMethodName).apply {
addModifiers(if (isRootElement) KModifier.ABSTRACT else KModifier.OVERRIDE)
val r = TypeVariableName("R")
val d = TypeVariableName("D")
addTypeVariable(r)
addTypeVariable(d)
val visitorParam = ParameterSpec.builder("visitor", elementVisitorType.toPoet().tryParameterizedBy(r, d))
.build()
.also(::addParameter)
val dataParam = ParameterSpec.builder("data", d)
.build()
.also(::addParameter)
returns(r)
if (!isRootElement) {
addStatement("return %N.%N(this, %N)", visitorParam, element.visitFunctionName, dataParam)
}
if (isRootElement) {
addKdoc(
"""
Runs the provided [%1N] on the IR subtree with the root at this node.
@param %1N The visitor to accept.
@param %2N An arbitrary context to pass to each invocation of [%1N]'s methods.
@return The value returned by the topmost `visit*` invocation.
""".trimIndent(),
visitorParam,
dataParam,
)
}
}.build())
}
if (element.hasTransformMethod) {
addFunction(FunSpec.builder(transformMethodName).apply {
addModifiers(if (isRootElement) KModifier.ABSTRACT else KModifier.OVERRIDE)
val d = TypeVariableName("D")
addTypeVariable(d)
val transformerParam = ParameterSpec.builder("transformer", elementTransformerType.toPoet().tryParameterizedBy(d))
.build()
.also(::addParameter)
val dataParam = ParameterSpec.builder("data", d)
.build()
.also(::addParameter)
returns(selfParametrizedElementName)
if (!isRootElement) {
addStatement("return %N(%N, %N) as %T", acceptMethodName, transformerParam, dataParam, selfParametrizedElementName)
}
if (isRootElement) {
addKdoc(
"""
Runs the provided [%1N] on the IR subtree with the root at this node.
@param %1N The transformer to use.
@param %2N An arbitrary context to pass to each invocation of [%1N]'s methods.
@return The transformed node.
""".trimIndent(),
transformerParam,
dataParam,
)
}
}.build())
}
if (element.hasAcceptChildrenMethod) {
addFunction(FunSpec.builder("acceptChildren").apply {
addModifiers(if (isRootElement) KModifier.ABSTRACT else KModifier.OVERRIDE)
val d = TypeVariableName("D")
addTypeVariable(d)
val visitorParam = ParameterSpec
.builder("visitor", elementVisitorType.toPoet().tryParameterizedBy(UNIT, d)).build()
.also(::addParameter)
val dataParam = ParameterSpec
.builder("data", d).build()
.also(::addParameter)
if (!element.isRootElement) {
println(" {")
withIndent {
for (child in element.walkableChildren) { for (child in element.walkableChildren) {
addStatement(buildString { print(child.name)
append("%N") if (child.nullable) {
if (child.nullable) append("?") print("?")
when (child) { }
is SingleField -> append(".%N(%N, %N)") when (child) {
is ListField -> { is SingleField -> println(".accept(visitor, data)")
append(".forEach { it") is ListField -> {
if ((child.elementType as? TypeRefWithNullability)?.nullable == true) append("?") print(".forEach { it")
append(".%N(%N, %N) }") if (child.elementType.nullable) {
print("?")
} }
println(".accept(visitor, data) }")
} }
}, child.name, acceptMethodName, visitorParam, dataParam) }
} }
}
if (isRootElement) { print("}")
addKdoc(
"""
Runs the provided [%1N] on subtrees with roots in this node's children.
Basically, calls `%3N(%1N, %2N)` on each child of this node.
Does **not** run [%1N] on this node itself.
@param %1N The visitor for children to accept.
@param %2N An arbitrary context to pass to each invocation of [%1N]'s methods.
""".trimIndent(),
visitorParam,
dataParam,
acceptMethodName,
)
}
}.build())
} }
println()
}
if (element.hasTransformChildrenMethod) { if (element.hasTransformChildrenMethod) {
addFunction(FunSpec.builder("transformChildren").apply { printTransformChildrenMethod(
addModifiers(if (isRootElement) KModifier.ABSTRACT else KModifier.OVERRIDE) element = element,
val d = TypeVariableName("D") transformerClass = elementTransformerType,
addTypeVariable(d) returnType = StandardTypes.unit,
val transformerParam = override = !element.isRootElement,
ParameterSpec.builder("transformer", elementTransformerType.toPoet().tryParameterizedBy(d)).build() kDoc = """
.also(::addParameter) Recursively transforms this node's children *in place* using [transformer].
val dataParam = ParameterSpec.builder("data", d).build().also(::addParameter)
Basically, executes `this.child = this.child.transform(transformer, data)` for each child of this node.
Does **not** run [transformer] on this node itself.
@param transformer The transformer to use for transforming the children.
@param data An arbitrary context to pass to each invocation of [transformer]'s methods.
""".trimIndent().takeIf { element.isRootElement }
)
if (!element.isRootElement) {
println(" {")
withIndent {
for (child in element.transformableChildren) { for (child in element.transformableChildren) {
val args = mutableListOf<Any>() print(child.name)
val code = buildString { when (child) {
append("%N") is SingleField -> {
args.add(child.name) print(" = ", child.name)
when (child) { if (child.nullable) {
is SingleField -> { print("?")
append(" = %N")
args.add(child.name)
if (child.nullable) append("?")
append(".%N(%N, %N)")
args.add(transformMethodName)
} }
is ListField -> { print(".transform(transformer, data)")
if (child.isMutable) { val elementRef = child.typeRef as GenericElementRef<*, *>
append(" = ") if (!elementRef.element.hasTransformMethod) {
append(child.name) print(" as ", elementRef.render())
if (child.nullable) append("?")
}
append(".%M(%N, %N)")
args.add(if (child.isMutable) transformIfNeeded else transformInPlace)
} }
println()
} }
is ListField -> {
args.add(transformerParam) if (child.isMutable) {
args.add(dataParam) print(" = ", child.name)
if (child.nullable) {
if (child is SingleField) { print("?")
@Suppress("UNCHECKED_CAST") }
val elRef = child.typeRef as GenericElementRef<Element, Field> addImport(transformIfNeeded)
if (!elRef.element.hasTransformMethod) { println(".transformIfNeeded(transformer, data)")
append(" as %T") } else {
args.add(elRef.toPoet()) addImport(transformInPlace)
println(".transformInPlace(transformer, data)")
} }
} }
} }
addStatement(code, *args.toTypedArray())
} }
}
if (isRootElement) { print("}")
addKdoc(
"""
Recursively transforms this node's children *in place* using [%1N].
Basically, executes `this.child = this.child.%3N(%1N, %2N)` for each child of this node.
Does **not** run [%1N] on this node itself.
@param %1N The transformer to use for transforming the children.
@param %2N An arbitrary context to pass to each invocation of [%1N]'s methods.
""".trimIndent(),
transformerParam,
dataParam,
transformMethodName,
)
}
}.build())
} }
println()
generateElementKDoc(element) }
element.generationCallback?.invoke(this)
}.build()
yield(printTypeCommon(generationPath, elementName.packageName, elementType, element.additionalImports))
} }
} }
private fun TypeSpec.Builder.generateElementKDoc(element: Element) { fun printElements(generationPath: File, model: Model) = model.elements.map { element ->
addKdoc(element.extendedKDoc("A ${if (element.isLeaf) "leaf" else "non-leaf"} IR tree element.")) printGeneratedType(generationPath, TREE_GENERATOR_README, element.packageName, element.typeName) {
addAllImports(element.usedTypes)
ElementPrinter(this).printElement(element)
}
} }
private val descriptorApiAnnotation = ClassName("org.jetbrains.kotlin.ir", "ObsoleteDescriptorBasedAPI")
private val transformIfNeeded = MemberName("$BASE_PACKAGE.util", "transformIfNeeded", true)
private val transformInPlace = MemberName("$BASE_PACKAGE.util", "transformInPlace", true)
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
import org.jetbrains.kotlin.generators.tree.printer.printFunctionDeclaration import org.jetbrains.kotlin.generators.tree.printer.printFunctionDeclaration
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
import org.jetbrains.kotlin.ir.generator.IrTree import org.jetbrains.kotlin.ir.generator.IrTree
import org.jetbrains.kotlin.ir.generator.TREE_GENERATOR_README
import org.jetbrains.kotlin.ir.generator.config.UseFieldAsParameterInIrFactoryStrategy import org.jetbrains.kotlin.ir.generator.config.UseFieldAsParameterInIrFactoryStrategy
import org.jetbrains.kotlin.ir.generator.irFactoryType import org.jetbrains.kotlin.ir.generator.irFactoryType
import org.jetbrains.kotlin.ir.generator.model.Element import org.jetbrains.kotlin.ir.generator.model.Element
@@ -28,7 +29,6 @@ internal fun printFactory(generationPath: File, model: Model): GeneratedFile = p
irFactoryType.packageName, irFactoryType.packageName,
irFactoryType.simpleName, irFactoryType.simpleName,
) { ) {
println()
println("interface ", irFactoryType.simpleName, " {") println("interface ", irFactoryType.simpleName, " {")
withIndent { withIndent {
println("val stageController: ", stageControllerType.render()) println("val stageController: ", stageControllerType.render())
@@ -1,68 +0,0 @@
/*
* Copyright 2010-2021 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.ir.generator.print
import com.squareup.kotlinpoet.*
import org.jetbrains.kotlin.generators.tree.*
import org.jetbrains.kotlin.ir.generator.config.ElementConfigOrRef
import org.jetbrains.kotlin.ir.generator.model.Element
import org.jetbrains.kotlin.ir.generator.model.Element.Companion.elementName2typeName
import org.jetbrains.kotlin.ir.generator.util.*
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
fun Element.toPoet() = ClassName(packageName, this.typeName)
fun Element.toPoetSelfParameterized() = toPoet().parameterizedByIfAny(poetTypeVariables)
fun Element.toPoetStarParameterized() = toPoet().parameterizedByIfAny(List(params.size) { STAR })
val Element.poetTypeVariables get() = params.map { TypeVariableName(it.name) }
fun TypeRef.toPoet(): TypeName {
return when (this) {
is GenericElementRef<*, *> -> ClassName(element.packageName, element.typeName).parameterizedByIfAny(typeArgsToPoet())
is ClassRef<*> -> ClassName(packageName, simpleNames).parameterizedByIfAny(typeArgsToPoet())
is NamedTypeParameterRef -> TypeVariableName(name)
is ElementConfigOrRef -> ClassName(this.element.category.packageName, elementName2typeName(element.name)).parameterizedByIfAny(
typeArgsToPoet()
) // ad-hoc solution
is TypeRef.Star -> STAR
else -> error("Unexpected type reference: $this")
}.let {
if (this is TypeRefWithNullability) it.copy(nullable = nullable) else it
}
}
private fun ParametrizedTypeRef<*, *>.typeArgsToPoet(): List<TypeName> {
if (args.isEmpty()) {
return emptyList()
}
fun fromPositional(args: Map<PositionTypeParameterRef, TypeRef>): List<TypeName> {
val num = args.keys.maxOfOrNull { it.index }!!
return (0..num).map { i -> args[PositionTypeParameterRef(i)]?.toPoet() ?: STAR }
}
val positional = args.keys.filterIsInstance<PositionTypeParameterRef>()
if (positional.size == args.size) {
@Suppress("UNCHECKED_CAST")
return fromPositional(args as Map<PositionTypeParameterRef, TypeRef>)
} else {
check(positional.isEmpty()) { "Can't yet handle mixed index-name args" }
this as GenericElementRef<*, *> // Named args must only be used with generated elements (for now)
val args = args.entries
.associate { p -> PositionTypeParameterRef(element.params.withIndex().single { it.value.name == p.key.name }.index) to p.value }
return fromPositional(args)
}
}
fun TypeVariable.toPoet() = TypeVariableName(
name, bounds.map { it.toPoet() }, when (variance) {
Variance.INVARIANT -> null
Variance.IN_VARIANCE -> KModifier.IN
Variance.OUT_VARIANCE -> KModifier.OUT
}
)
@@ -22,7 +22,6 @@ private fun printVisitorCommon(
makePrinter: (SmartPrinter, ClassRef<*>) -> AbstractVisitorPrinter<Element, Field>, makePrinter: (SmartPrinter, ClassRef<*>) -> AbstractVisitorPrinter<Element, Field>,
): GeneratedFile = ): GeneratedFile =
printGeneratedType(generationPath, TREE_GENERATOR_README, visitorType.packageName, visitorType.simpleName) { printGeneratedType(generationPath, TREE_GENERATOR_README, visitorType.packageName, visitorType.simpleName) {
println()
makePrinter(this, visitorType).printVisitor(model.elements) makePrinter(this, visitorType).printVisitor(model.elements)
} }
@@ -1,29 +0,0 @@
/*
* Copyright 2010-2021 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.ir.generator.util
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.ParameterizedTypeName
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.TypeName
class Import(val packageName: String, val className: String)
fun ClassName.parameterizedByIfAny(typeArguments: List<TypeName>) =
if (typeArguments.isNotEmpty()) parameterizedBy(typeArguments) else this
fun TypeName.tryParameterizedBy(vararg typeArguments: TypeName) = when (this) {
is ClassName -> parameterizedBy(*typeArguments)
is ParameterizedTypeName -> this.rawType.parameterizedBy(*typeArguments)
else -> {
if (typeArguments.isNotEmpty())
error("Type $this cannot be parameterized")
else this
}
}
fun code(code: String, vararg args: Any?) = CodeBlock.of(code, *args)
@@ -69,7 +69,7 @@ abstract class AbstractElementPrinter<Element : AbstractElement<Element, Field>,
if (body.isNotEmpty()) { if (body.isNotEmpty()) {
println(" {") println(" {")
print(body) print(body.trimStart('\n'))
print("}") print("}")
} }
println() println()
@@ -32,6 +32,10 @@ abstract class AbstractField {
open val withGetter: Boolean get() = false open val withGetter: Boolean get() = false
open val customSetter: String? get() = null open val customSetter: String? get() = null
var deprecation: Deprecated? = null
var visibility: Visibility = Visibility.PUBLIC
var fromParent: Boolean = false var fromParent: Boolean = false
open val defaultValueInImplementation: String? get() = null open val defaultValueInImplementation: String? get() = null
@@ -35,6 +35,17 @@ abstract class AbstractFieldPrinter<Field : AbstractField>(
) { ) {
printer.run { printer.run {
printKDoc(field.kDoc) printKDoc(field.kDoc)
field.deprecation?.let {
println("@Deprecated(")
withIndent {
println("message = \"", it.message, "\",")
println("replaceWith = ReplaceWith(\"", it.replaceWith.expression, "\"),")
println("level = DeprecationLevel.", it.level.name, ",")
}
println(")")
}
if (field.isVolatile) { if (field.isVolatile) {
println("@", type<Volatile>().render()) println("@", type<Volatile>().render())
} }
@@ -50,6 +61,10 @@ abstract class AbstractFieldPrinter<Field : AbstractField>(
} }
} }
if (field.visibility != Visibility.PUBLIC) {
print(field.visibility.name.toLowerCaseAsciiOnly(), " ")
}
modality?.let { modality?.let {
print(it.name.toLowerCaseAsciiOnly(), " ") print(it.name.toLowerCaseAsciiOnly(), " ")
} }
@@ -68,12 +68,20 @@ class ImportCollector(currentPackage: String) {
addImport(packageName, "*") addImport(packageName, "*")
} }
fun printAllImports(printer: Appendable) { /**
* Prints all the collected imports in alphabetical order.
*
* @return `true` if at least one import was printed, `false` if no imports were printed.
*/
fun printAllImports(printer: Appendable): Boolean {
var atLeastOneImport = false
for ((packageName, entities) in imports) { for ((packageName, entities) in imports) {
for (entity in entities) { for (entity in entities) {
atLeastOneImport = true
printer.append("import ", packageName, ".", entity, "\n") printer.append("import ", packageName, ".", entity, "\n")
} }
} }
return atLeastOneImport
} }
fun addAllImports(importables: Collection<Importable>) { fun addAllImports(importables: Collection<Importable>) {
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2023 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.generators.tree
enum class Visibility {
PUBLIC, PROTECTED, INTERNAL, PRIVATE
}
@@ -45,7 +45,9 @@ fun printGeneratedType(
} }
appendLine("package $packageName") appendLine("package $packageName")
appendLine() appendLine()
importCollector.printAllImports(this) if (importCollector.printAllImports(this)) {
appendLine()
}
append(stringBuilder) append(stringBuilder)
} }
) )