[IR] Automatically generate IrFactory interface

^KT-59308 Fixed
This commit is contained in:
Sergej Jaskiewicz
2023-07-18 17:54:59 +02:00
committed by Space Team
parent c2a8d46867
commit 8aa0b6a562
8 changed files with 650 additions and 124 deletions
@@ -1,16 +1,33 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
// This file was generated automatically. See compiler/ir/ir.tree/tree-generator/ReadMe.md.
// DO NOT MODIFY IT MANUALLY.
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrAnonymousInitializerSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrLocalDelegatedPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeAliasSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
@@ -57,8 +74,8 @@ interface IrFactory {
returnType: IrType,
symbol: IrConstructorSymbol,
isPrimary: Boolean,
isExternal: Boolean,
containerSource: DeserializedContainerSource? = null
isExternal: Boolean = false,
containerSource: DeserializedContainerSource? = null,
): IrConstructor
fun createEnumEntry(
@@ -85,29 +102,9 @@ interface IrFactory {
type: IrType,
isFinal: Boolean,
isStatic: Boolean,
isExternal: Boolean,
isExternal: Boolean = false,
): IrField
fun createSimpleFunction(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
name: Name,
visibility: DescriptorVisibility,
isInline: Boolean,
isExpect: Boolean,
returnType: IrType,
modality: Modality,
symbol: IrSimpleFunctionSymbol,
isTailrec: Boolean,
isSuspend: Boolean,
isOperator: Boolean,
isInfix: Boolean,
isExternal: Boolean,
containerSource: DeserializedContainerSource? = null,
isFakeOverride: Boolean = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
): IrSimpleFunction
fun createFunctionWithLateBinding(
startOffset: Int,
endOffset: Int,
@@ -148,10 +145,10 @@ interface IrFactory {
isConst: Boolean,
isLateinit: Boolean,
isDelegated: Boolean,
isExternal: Boolean,
isExternal: Boolean = false,
containerSource: DeserializedContainerSource? = null,
isExpect: Boolean = false,
isFakeOverride: Boolean = origin == IrDeclarationOrigin.FAKE_OVERRIDE
isFakeOverride: Boolean = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
): IrProperty
fun createPropertyWithLateBinding(
@@ -170,6 +167,26 @@ interface IrFactory {
isFakeOverride: Boolean = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
): IrPropertyWithLateBinding
fun createSimpleFunction(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
name: Name,
visibility: DescriptorVisibility,
isInline: Boolean,
isExpect: Boolean,
returnType: IrType,
modality: Modality,
symbol: IrSimpleFunctionSymbol,
isTailrec: Boolean,
isSuspend: Boolean,
isOperator: Boolean,
isInfix: Boolean,
isExternal: Boolean = false,
containerSource: DeserializedContainerSource? = null,
isFakeOverride: Boolean = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
): IrSimpleFunction
fun createTypeAlias(
startOffset: Int,
endOffset: Int,
@@ -204,10 +221,10 @@ interface IrFactory {
varargElementType: IrType?,
isCrossinline: Boolean,
isNoinline: Boolean,
isHidden: Boolean
isHidden: Boolean,
): IrValueParameter
// Bodies
fun createBlockBody(startOffset: Int, endOffset: Int): IrBlockBody
fun createExpressionBody(
startOffset: Int,
@@ -215,12 +232,6 @@ interface IrFactory {
expression: IrExpression,
): IrExpressionBody
fun createBlockBody(
startOffset: Int,
endOffset: Int,
): IrBlockBody
@Deprecated(
message = "This method was moved to an extension." +
" This variant of the method will be removed when the 2024.2 IntelliJ platform is shipped (see KTIJ-26314).",
@@ -417,9 +428,9 @@ interface IrFactory {
level = DeprecationLevel.HIDDEN,
)
fun createExpressionBody(expression: IrExpression): IrExpressionBody =
createExpressionBody(
expression,
)
createExpressionBody(
expression,
)
@Deprecated(
message = "The method's parameters were reordered." +
@@ -11,6 +11,7 @@ runtimeOnly.extendsFrom(compileOnly)
dependencies {
implementation(project(":generators"))
implementation(project(":core:compiler.common"))
implementation(project(":compiler:util"))
implementation("com.squareup:kotlinpoet:1.11.0")
compileOnly(intellijCore())
@@ -18,6 +18,7 @@ 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.model.Element.Companion.elementName2typeName
import org.jetbrains.kotlin.ir.generator.print.IR_FACTORY_TYPE
import org.jetbrains.kotlin.ir.generator.print.toPoet
import org.jetbrains.kotlin.ir.generator.util.*
import org.jetbrains.kotlin.ir.generator.util.Import
@@ -33,13 +34,26 @@ import org.jetbrains.kotlin.types.Variance
object IrTree : AbstractTreeBuilder() {
private fun symbol(type: TypeRef, mutable: Boolean = false): SimpleFieldConfig =
field("symbol", type, mutable = mutable)
private fun descriptor(typeName: String): SimpleFieldConfig =
field("descriptor", ClassRef<TypeParameterRef>(TypeKind.Interface, "org.jetbrains.kotlin.descriptors", typeName), mutable = false)
private fun descriptor(typeName: String, nullable: Boolean = false): SimpleFieldConfig =
field(
name = "descriptor",
type = ClassRef<TypeParameterRef>(TypeKind.Interface, Packages.descriptors, typeName),
mutable = false,
nullable = nullable,
) {
skipInIrFactory()
}
private fun declarationWithLateBinding(symbol: ClassRef<*>, initializer: ElementConfig.() -> Unit) = element(Declaration) {
initializer()
+field("isBound", boolean, mutable = false)
fieldsToSkipInIrFactoryMethod.add("symbol")
fieldsToSkipInIrFactoryMethod.add("containerSource")
+field("isBound", boolean, mutable = false) {
skipInIrFactory()
}
val oldCallback = generationCallback
generationCallback = {
@@ -54,7 +68,9 @@ object IrTree : AbstractTreeBuilder() {
}
}
private val factory: SimpleFieldConfig = field("factory", type(Packages.declarations, "IrFactory"), mutable = false)
private val factory: SimpleFieldConfig = field("factory", IR_FACTORY_TYPE, mutable = false) {
skipInIrFactory()
}
override val rootElement: ElementConfig by element(Other, name = "element") {
accept = true
@@ -86,7 +102,9 @@ object IrTree : AbstractTreeBuilder() {
+descriptor("DeclarationDescriptor")
+field("origin", type(Packages.declarations, "IrDeclarationOrigin"))
+field("parent", declarationParent)
+field("parent", declarationParent) {
skipInIrFactory()
}
+factory
}
val declarationBase: ElementConfig by element(Declaration) {
@@ -112,13 +130,16 @@ object IrTree : AbstractTreeBuilder() {
val possiblyExternalDeclaration: ElementConfig by element(Declaration) {
parent(declarationWithName)
+field("isExternal", boolean)
+field("isExternal", boolean) {
useFieldInIrFactory(false)
}
}
val symbolOwner: ElementConfig by element(Declaration) {
+symbol(symbolType)
}
val metadataSourceOwner: ElementConfig by element(Declaration) {
val metadataField = +field("metadata", type(Packages.declarations, "MetadataSource"), nullable = true) {
skipInIrFactory()
kdoc = """
The arbitrary metadata associated with this IR node.
@@ -152,13 +173,17 @@ object IrTree : AbstractTreeBuilder() {
parent(overridableMember)
+field("symbol", s, mutable = false)
+field("isFakeOverride", boolean)
+listField("overriddenSymbols", s, mutability = Var)
+isFakeOverrideField()
+listField("overriddenSymbols", s, mutability = Var) {
skipInIrFactory()
}
}
val memberWithContainerSource: ElementConfig by element(Declaration) {
parent(declarationWithName)
+field("containerSource", type<DeserializedContainerSource>(), nullable = true, mutable = false)
+field("containerSource", type<DeserializedContainerSource>(), nullable = true, mutable = false) {
useFieldInIrFactory(defaultValue = code("null"))
}
}
val valueDeclaration: ElementConfig by element(Declaration) {
parent(declarationWithName)
@@ -229,21 +254,40 @@ object IrTree : AbstractTreeBuilder() {
+symbol(classSymbolType)
+field("kind", type<ClassKind>())
+field("modality", type<Modality>())
+field("isCompanion", boolean)
+field("isInner", boolean)
+field("isData", boolean)
+field("isValue", boolean)
+field("isExpect", boolean)
+field("isFun", boolean)
+field("source", type<SourceElement>(), mutable = false)
+listField("superTypes", irTypeType, mutability = Var)
+field("isCompanion", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+field("isInner", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+field("isData", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+field("isValue", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+field("isExpect", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+field("isFun", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+field("source", type<SourceElement>(), mutable = false) {
useFieldInIrFactory(defaultValue = code("%T.NO_SOURCE", SourceElement::class))
}
+listField("superTypes", irTypeType, mutability = Var) {
skipInIrFactory()
}
+field("thisReceiver", valueParameter, nullable = true, isChild = true)
+field(
"valueClassRepresentation",
type<ValueClassRepresentation<*>>().withArgs(type(Packages.types, "IrSimpleType")),
nullable = true,
)
) {
skipInIrFactory()
}
+listField("sealedSubclasses", classSymbolType, mutability = Var) {
skipInIrFactory()
kdoc = """
If this is a sealed class or interface, this list contains symbols of all its immediate subclasses.
Otherwise, this is an empty list.
@@ -264,8 +308,13 @@ object IrTree : AbstractTreeBuilder() {
idempotence invariant and can contain a chain of declarations.
""".trimIndent()
+field("attributeOwnerId", attributeContainer)
+field("originalBeforeInline", attributeContainer, nullable = true) // null <=> this element wasn't inlined
+field("attributeOwnerId", attributeContainer) {
skipInIrFactory()
}
// null <=> this element wasn't inlined
+field("originalBeforeInline", attributeContainer, nullable = true) {
skipInIrFactory()
}
}
val anonymousInitializer: ElementConfig by element(Declaration) {
visitorParent = declarationBase
@@ -274,7 +323,9 @@ object IrTree : AbstractTreeBuilder() {
+descriptor("ClassDescriptor") // TODO special descriptor for anonymous initializer blocks
+symbol(anonymousInitializerSymbolType)
+field("isStatic", boolean)
+field("isStatic", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+field("body", blockBody, isChild = true)
}
val declarationContainer: ElementConfig by element(Declaration) {
@@ -304,7 +355,9 @@ object IrTree : AbstractTreeBuilder() {
+field("variance", type<Variance>())
+field("index", int)
+field("isReified", boolean)
+listField("superTypes", irTypeType, mutability = Var)
+listField("superTypes", irTypeType, mutability = Var) {
skipInIrFactory()
}
}
val returnTarget: ElementConfig by element(Declaration) {
parent(symbolOwner)
@@ -335,7 +388,9 @@ object IrTree : AbstractTreeBuilder() {
+field("extensionReceiverParameter", valueParameter, nullable = true, isChild = true)
+listField("valueParameters", valueParameter, mutability = Var, isChild = true)
// The first `contextReceiverParametersCount` value parameters are context receivers.
+field("contextReceiverParametersCount", int)
+field("contextReceiverParametersCount", int) {
skipInIrFactory()
}
+field("body", body, nullable = true, isChild = true)
}
val constructor: ElementConfig by element(Declaration) {
@@ -363,8 +418,17 @@ object IrTree : AbstractTreeBuilder() {
parent(declarationBase)
additionalIrFactoryMethodParameters.add(
descriptor("DeclarationDescriptor", nullable = true).apply {
useFieldInIrFactory(defaultValue = code("null"))
}
)
fieldsToSkipInIrFactoryMethod.add("origin")
+field("symbol", symbolType, mutable = false) {
baseGetter = code("error(\"Should never be called\")")
skipInIrFactory()
}
}
val functionWithLateBinding: ElementConfig by declarationWithLateBinding(simpleFunctionSymbolType) {
@@ -388,7 +452,9 @@ object IrTree : AbstractTreeBuilder() {
+field("isFinal", boolean)
+field("isStatic", boolean)
+field("initializer", expressionBody, nullable = true, isChild = true)
+field("correspondingPropertySymbol", propertySymbolType, nullable = true)
+field("correspondingPropertySymbol", propertySymbolType, nullable = true) {
skipInIrFactory()
}
}
val localDelegatedProperty: ElementConfig by element(Declaration) {
visitorParent = declarationBase
@@ -410,6 +476,7 @@ object IrTree : AbstractTreeBuilder() {
visitorParent = rootElement
transform = true
transformByChildren = true
generateIrFactoryMethod = false
+descriptor("ModuleDescriptor")
+field("name", type<Name>(), mutable = false)
@@ -440,17 +507,29 @@ object IrTree : AbstractTreeBuilder() {
+field("isConst", boolean)
+field("isLateinit", boolean)
+field("isDelegated", boolean)
+field("isExpect", boolean)
+field("isFakeOverride", boolean)
+field("isExpect", boolean) {
useFieldInIrFactory(defaultValue = false)
}
+isFakeOverrideField()
+field("backingField", field, nullable = true, isChild = true)
+field("getter", simpleFunction, nullable = true, isChild = true)
+field("setter", simpleFunction, nullable = true, isChild = true)
}
private fun isFakeOverrideField() = field("isFakeOverride", boolean) {
useFieldInIrFactory(
defaultValue = code(
"origin == %T.FAKE_OVERRIDE",
type(Packages.declarations, "IrDeclarationOrigin").toPoet(),
),
)
}
//TODO: make IrScript as IrPackageFragment, because script is used as a file, not as a class
//NOTE: declarations and statements stored separately
val script: ElementConfig by element(Declaration) {
visitorParent = declarationBase
generateIrFactoryMethod = false
parent(declarationBase)
parent(declarationWithName)
@@ -484,10 +563,12 @@ object IrTree : AbstractTreeBuilder() {
+symbol(simpleFunctionSymbolType)
+field("isTailrec", boolean)
+field("isSuspend", boolean)
+field("isFakeOverride", boolean)
+isFakeOverrideField()
+field("isOperator", boolean)
+field("isInfix", boolean)
+field("correspondingPropertySymbol", propertySymbolType, nullable = true)
+field("correspondingPropertySymbol", propertySymbolType, nullable = true) {
skipInIrFactory()
}
}
val typeAlias: ElementConfig by element(Declaration) {
visitorParent = declarationBase
@@ -505,6 +586,8 @@ object IrTree : AbstractTreeBuilder() {
val variable: ElementConfig by element(Declaration) {
visitorParent = declarationBase
generateIrFactoryMethod = false
parent(declarationBase)
parent(valueDeclaration)
@@ -541,6 +624,7 @@ object IrTree : AbstractTreeBuilder() {
val externalPackageFragment: ElementConfig by element(Declaration) {
visitorParent = packageFragment
transformByChildren = true
generateIrFactoryMethod = false
parent(packageFragment)
@@ -551,6 +635,7 @@ object IrTree : AbstractTreeBuilder() {
transform = true
transformByChildren = true
visitorParent = packageFragment
generateIrFactoryMethod = false
parent(packageFragment)
parent(mutableAnnotationContainerType)
@@ -572,9 +657,11 @@ object IrTree : AbstractTreeBuilder() {
+field("attributeOwnerId", attributeContainer) {
baseDefaultValue = code("this")
skipInIrFactory()
}
+field("originalBeforeInline", attributeContainer, nullable = true) {
baseDefaultValue = code("null")
skipInIrFactory()
}
+field("type", irTypeType)
}
@@ -594,15 +681,19 @@ object IrTree : AbstractTreeBuilder() {
transform = true
visitorParent = body
visitorParam = "body"
generateIrFactoryMethod = true
parent(body)
+factory
+field("expression", expression, isChild = true)
+field("expression", expression, isChild = true) {
useFieldInIrFactory()
}
}
val blockBody: ElementConfig by element(Expression) {
visitorParent = body
visitorParam = "body"
generateIrFactoryMethod = true
parent(body)
parent(statementContainer)
@@ -706,7 +797,9 @@ object IrTree : AbstractTreeBuilder() {
parent(functionAccessExpression)
+symbol(constructorSymbolType, mutable = true)
+field("source", type<SourceElement>())
+field("source", type<SourceElement>()) {
useFieldInIrFactory(defaultValue = code("%T.NO_SOURCE", SourceElement::class))
}
+field("constructorTypeArgumentsCount", int)
}
val getSingletonValue: ElementConfig by element(Expression) {
@@ -30,6 +30,7 @@ fun main(args: Array<String>) {
yield(printTransformer(generationPath, model))
yield(printTypeVisitor(generationPath, model))
// IrElementTransformerVoid is too random to autogenerate
yield(printFactory(generationPath, model))
}.map {
GeneratorsFileUtil.writeFileIfContentChanged(it.file, it.newText, logNotChanged = false)
it.file
@@ -37,6 +37,10 @@ class ElementConfig(
var ownsChildren = true // If false, acceptChildren/transformChildren will NOT be generated.
var generateIrFactoryMethod = category == Category.Declaration
val additionalIrFactoryMethodParameters = mutableListOf<FieldConfig>()
val fieldsToSkipInIrFactoryMethod = hashSetOf<String>()
/**
* Set this to `true` if the element should be a leaf semantically, but technically it's not.
*
@@ -91,6 +95,13 @@ class ElementConfigRef(
override fun toString() = element.name
}
sealed class UseFieldAsParameterInIrFactoryStrategy {
data object No : UseFieldAsParameterInIrFactoryStrategy()
data class Yes(val defaultValue: CodeBlock?) : UseFieldAsParameterInIrFactoryStrategy()
}
sealed class FieldConfig(
val name: String,
val isChild: Boolean,
@@ -100,6 +111,21 @@ sealed class FieldConfig(
var printProperty = true
var strictCastInTransformChildren = false
internal var useFieldInIrFactoryStrategy: UseFieldAsParameterInIrFactoryStrategy =
if (isChild) UseFieldAsParameterInIrFactoryStrategy.No else UseFieldAsParameterInIrFactoryStrategy.Yes(null)
fun useFieldInIrFactory(defaultValue: CodeBlock? = null) {
useFieldInIrFactoryStrategy = UseFieldAsParameterInIrFactoryStrategy.Yes(defaultValue)
}
fun useFieldInIrFactory(defaultValue: Boolean) {
useFieldInIrFactoryStrategy = UseFieldAsParameterInIrFactoryStrategy.Yes(code("%L", defaultValue))
}
fun skipInIrFactory() {
useFieldInIrFactoryStrategy = UseFieldAsParameterInIrFactoryStrategy.No
}
var kdoc: String? = null
var generationCallback: (PropertySpec.Builder.() -> Unit)? = null
@@ -9,6 +9,7 @@ import com.squareup.kotlinpoet.CodeBlock
import org.jetbrains.kotlin.ir.generator.config.ElementConfig
import org.jetbrains.kotlin.ir.generator.config.FieldConfig
import org.jetbrains.kotlin.ir.generator.util.*
import org.jetbrains.kotlin.utils.topologicalSort
class Element(
config: ElementConfig,
@@ -16,6 +17,7 @@ class Element(
val packageName: String,
val params: List<TypeVariable>,
val fields: MutableList<Field>,
val additionalFactoryMethodParameters: MutableList<Field>,
) {
var elementParents: List<ElementRef> = emptyList()
var otherParents: List<ClassRef<*>> = emptyList()
@@ -38,6 +40,8 @@ class Element(
val transform = config.transform
val transformByChildren = config.transformByChildren
val ownsChildren = config.ownsChildren
val generateIrFactoryMethod = config.generateIrFactoryMethod
val fieldsToSkipInIrFactoryMethod = config.fieldsToSkipInIrFactoryMethod
val generationCallback = config.generationCallback
val suppressPrint = config.suppressPrint
@@ -59,6 +63,29 @@ class Element(
companion object {
fun elementName2typeName(name: String) = "Ir" + name.replaceFirstChar(Char::uppercaseChar)
}
fun elementParentsRecursively(): List<ElementRef> {
val linkedSet = buildSet {
fun recurse(element: Element) {
addAll(element.elementParents)
element.elementParents.forEach { recurse(it.element) }
}
recurse(this@Element)
}
return topologicalSort(linkedSet) {
element.elementParents
}
}
fun allFieldsRecursively(): List<Field> {
val parentFields = elementParentsRecursively()
.reversed()
.flatMap { it.element.fields }
return (parentFields + fields)
.asReversed()
.distinctBy { it.name }
.asReversed()
}
}
data class ElementRef(
@@ -72,7 +99,7 @@ data class ElementRef(
}
sealed class Field(
config: FieldConfig?,
config: FieldConfig,
val name: String,
val nullable: Boolean,
val mutable: Boolean,
@@ -85,16 +112,17 @@ sealed class Field(
var needsDescriptorApiAnnotation = false
abstract val transformable: Boolean
val kdoc = config?.kdoc
val useInIrFactoryStrategy = config.useFieldInIrFactoryStrategy
val kdoc = config.kdoc
val printProperty = config?.printProperty ?: true
val generationCallback = config?.generationCallback
val printProperty = config.printProperty
val generationCallback = config.generationCallback
override fun toString() = "$name: $type"
}
class SingleField(
config: FieldConfig?,
config: FieldConfig,
name: String,
override var type: TypeRef,
nullable: Boolean,
@@ -108,7 +136,7 @@ class SingleField(
}
class ListField(
config: FieldConfig?,
config: FieldConfig,
name: String,
var elementType: TypeRef,
private val listType: ClassRef<PositionTypeParameterRef>,
@@ -20,56 +20,16 @@ fun config2model(config: Config): Model {
val ec2el = mutableMapOf<ElementConfig, Element>()
val elements = config.elements.map { ec ->
val fields = ec.fields.mapTo(mutableListOf()) { fc ->
val field = when (fc) {
is SimpleFieldConfig -> SingleField(
fc,
fc.name,
fc.type ?: InferredOverriddenType,
fc.nullable,
fc.mutable,
fc.isChild,
fc.baseDefaultValue,
fc.baseGetter
)
is ListFieldConfig -> {
val listType = when (fc.mutability) {
ListFieldConfig.Mutability.List -> type(
"kotlin.collections",
"MutableList"
)
ListFieldConfig.Mutability.Array -> type(
"kotlin.",
"Array"
)
else -> type("kotlin.collections", "List")
}
ListField(
fc,
fc.name,
fc.elementType ?: InferredOverriddenType,
listType,
fc.nullable,
fc.mutability == ListFieldConfig.Mutability.Var,
fc.isChild,
fc.mutability != ListFieldConfig.Mutability.Immutable,
fc.baseDefaultValue,
fc.baseGetter
)
}
}
field
Element(
config = ec,
name = ec.name,
packageName = ec.category.packageName,
params = ec.params,
fields = ec.fields.mapTo(mutableListOf(), ::transformFieldConfig),
additionalFactoryMethodParameters = ec.additionalIrFactoryMethodParameters.mapTo(mutableListOf(), ::transformFieldConfig)
).also {
ec2el[ec.element] = it
}
val element = Element(
ec,
ec.name,
ec.category.packageName,
ec.params,
fields
)
ec2el[ec.element] = element
element
}
val rootElement = replaceElementRefs(config, ec2el)
@@ -83,6 +43,44 @@ fun config2model(config: Config): Model {
return Model(elements, rootElement)
}
private fun transformFieldConfig(fc: FieldConfig): Field = when (fc) {
is SimpleFieldConfig -> SingleField(
fc,
fc.name,
fc.type ?: InferredOverriddenType,
fc.nullable,
fc.mutable,
fc.isChild,
fc.baseDefaultValue,
fc.baseGetter,
)
is ListFieldConfig -> {
val listType = when (fc.mutability) {
ListFieldConfig.Mutability.List -> type(
"kotlin.collections",
"MutableList",
)
ListFieldConfig.Mutability.Array -> type(
"kotlin.",
"Array",
)
else -> type("kotlin.collections", "List")
}
ListField(
fc,
fc.name,
fc.elementType ?: InferredOverriddenType,
listType,
fc.nullable,
fc.mutability == ListFieldConfig.Mutability.Var,
fc.isChild,
fc.mutability != ListFieldConfig.Mutability.Immutable,
fc.baseDefaultValue,
fc.baseGetter,
)
}
}
@OptIn(UnsafeCastFunction::class)
private fun replaceElementRefs(config: Config, mapping: Map<ElementConfig, Element>): Element {
val visited = mutableMapOf<TypeRef, TypeRef>()
@@ -0,0 +1,368 @@
/*
* 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.ir.generator.print
import com.squareup.kotlinpoet.*
import org.jetbrains.kotlin.ir.generator.IrTree
import org.jetbrains.kotlin.ir.generator.Packages
import org.jetbrains.kotlin.ir.generator.config.UseFieldAsParameterInIrFactoryStrategy
import org.jetbrains.kotlin.ir.generator.model.Model
import org.jetbrains.kotlin.ir.generator.util.GeneratedFile
import org.jetbrains.kotlin.ir.generator.util.parameterizedByIfAny
import org.jetbrains.kotlin.ir.generator.util.tryParameterizedBy
import org.jetbrains.kotlin.ir.generator.util.type
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
import java.io.File
internal val IR_FACTORY_TYPE = type(Packages.declarations, "IrFactory")
@Suppress("DuplicatedCode")
internal fun printFactory(generationPath: File, model: Model): GeneratedFile {
val visitorType = TypeSpec.interfaceBuilder(IR_FACTORY_TYPE.toPoet() as ClassName).apply {
addProperty("stageController", ClassName(Packages.declarations, "StageController"))
model.elements
.filter { it.isLeaf && it.generateIrFactoryMethod }
.sortedWith(compareBy({ it.packageName }, { it.name }))
.forEach { element ->
val typeParams = element.params.map { it.toPoet() }
addFunction(
FunSpec.builder("create${element.name.capitalizeAsciiOnly()}")
.addTypeVariables(typeParams)
.apply {
val fields = (element.allFieldsRecursively() + element.additionalFactoryMethodParameters)
.filterNot { it.name in element.fieldsToSkipInIrFactoryMethod }
.mapNotNull { field ->
(field.useInIrFactoryStrategy as? UseFieldAsParameterInIrFactoryStrategy.Yes)?.let {
field to it.defaultValue
}
}
.sortedBy { (_, defaultValue) -> defaultValue != null } // All parameters with default values must go last
fields.forEach { (field, defaultValue) ->
addParameter(
ParameterSpec.builder(field.name, field.type.toPoet().copy(nullable = field.nullable))
.defaultValue(defaultValue)
.build(),
)
}
}
.returns(element.toPoet().parameterizedByIfAny(typeParams))
.addModifiers(KModifier.ABSTRACT)
.build(),
)
}
fun replacement(name: String) = funSpecs.find { it.name == name } ?: error("Method '$name' not found")
addDeprecatedFunction(
replacement("createBlockBody")
.toBuilder()
.addParameter(
"initializer",
LambdaTypeName.get(receiver = IrTree.blockBody.toPoet(), returnType = UNIT)
)
.build()
) {
deprecationMessage = "This method was moved to an extension."
additionalImports.add("${Packages.declarations}.$oldName")
parameter("startOffset")
parameter("endOffset")
parameter("initializer")
}
addDeprecatedFunction(
replacement("createBlockBody")
.toBuilder()
.addParameter(
"statements",
LIST.tryParameterizedBy(IrTree.statement.toPoet())
)
.build()
) {
deprecationMessage = "This method was moved to an extension."
additionalImports.add("${Packages.declarations}.$oldName")
parameter("startOffset")
parameter("endOffset")
parameter("statements")
}
addDeprecatedFunction(replacement("createClass")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("kind")
parameter("visibility")
parameter("modality")
parameter("isCompanion")
parameter("isInner")
parameter("isData")
parameter("isExternal")
parameter("isValue")
parameter("isExpect")
parameter("isFun")
parameter("source")
}
addDeprecatedFunction(replacement("createConstructor")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("visibility")
parameter("returnType")
parameter("isInline")
parameter("isExternal", removeDefaultValue = true)
parameter("isPrimary")
parameter("isExpect")
parameter("containerSource")
}
addDeprecatedFunction(replacement("createEnumEntry")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
}
addDeprecatedFunction(replacement("createExpressionBody")) {
deprecationMessage = "This method was moved to an extension."
additionalImports.add("${Packages.declarations}.$oldName")
parameter("expression")
}
addDeprecatedFunction(replacement("createField")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("type")
parameter("visibility")
parameter("isFinal")
parameter("isExternal", removeDefaultValue = true)
parameter("isStatic")
}
addDeprecatedFunction(replacement("createFunctionWithLateBinding")) {
returnType = IrTree.simpleFunction.toPoet()
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("name")
parameter("visibility")
parameter("modality")
parameter("returnType")
parameter("isInline")
parameter("isExternal", removeDefaultValue = true)
parameter("isTailrec")
parameter("isSuspend")
parameter("isOperator")
parameter("isInfix")
parameter("isExpect")
}
addDeprecatedFunction(replacement("createLocalDelegatedProperty")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("type")
parameter("isVar")
}
addDeprecatedFunction(replacement("createProperty")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("visibility")
parameter("modality")
parameter("isVar")
parameter("isConst")
parameter("isLateinit")
parameter("isDelegated")
parameter("isExternal", removeDefaultValue = true)
parameter("isExpect")
parameter("isFakeOverride")
parameter("containerSource")
}
addDeprecatedFunction(replacement("createPropertyWithLateBinding")) {
returnType = IrTree.property.toPoet()
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("name")
parameter("visibility")
parameter("modality")
parameter("isVar")
parameter("isConst")
parameter("isLateinit")
parameter("isDelegated")
parameter("isExternal", removeDefaultValue = true)
parameter("isExpect", removeDefaultValue = true)
}
addDeprecatedFunction(replacement("createSimpleFunction"),) {
oldName = "createFunction"
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("visibility")
parameter("modality")
parameter("returnType")
parameter("isInline")
parameter("isExternal", removeDefaultValue = true)
parameter("isTailrec")
parameter("isSuspend")
parameter("isOperator")
parameter("isInfix")
parameter("isExpect")
parameter("isFakeOverride")
parameter("containerSource")
}
addDeprecatedFunction(replacement("createTypeAlias")) {
parameter("startOffset")
parameter("endOffset")
parameter("symbol")
parameter("name")
parameter("visibility")
parameter("expandedType")
parameter("isActual")
parameter("origin")
}
addDeprecatedFunction(replacement("createTypeParameter")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("index")
parameter("isReified")
parameter("variance")
}
addDeprecatedFunction(replacement("createValueParameter")) {
parameter("startOffset")
parameter("endOffset")
parameter("origin")
parameter("symbol")
parameter("name")
parameter("index")
parameter("type")
parameter("varargElementType")
parameter("isCrossinline")
parameter("isNoinline")
parameter("isHidden")
parameter("isAssignable")
}
}.build()
return printTypeCommon(generationPath, IR_FACTORY_TYPE.packageName, visitorType)
}
private class DeprecatedFunctionBuilder(private val replacement: FunSpec) {
val deprecatedFunctionParameterSpecs = mutableListOf<ParameterSpec>()
var oldName = replacement.name
var returnType = replacement.returnType
var deprecationMessage: String? = null
val additionalImports = mutableListOf<String>()
fun parameter(name: String, removeDefaultValue: Boolean = false) {
val replacementParameter =
replacement.parameters.find { it.name == name } ?: error("Parameter '$name' not found in $replacement")
deprecatedFunctionParameterSpecs.add(
replacementParameter
.toBuilder()
.applyIf(removeDefaultValue) {
defaultValue(null)
}
.build()
)
}
}
private fun TypeSpec.Builder.addDeprecatedFunction(
replacement: FunSpec,
build: DeprecatedFunctionBuilder.() -> Unit
): TypeSpec.Builder {
val builder = DeprecatedFunctionBuilder(replacement)
builder.build()
val message = builder.deprecationMessage ?: if (builder.oldName != replacement.name) {
"The method has been renamed, and its parameters were reordered."
} else {
"The method's parameters were reordered."
}
fun CodeBlock.Builder.addCallToNewFunction(explicitParameterName: Boolean) =
add("%N(\n", replacement)
.apply {
for (parameter in replacement.parameters) {
if (builder.deprecatedFunctionParameterSpecs.any { it.name == parameter.name }) {
indent()
add(if (explicitParameterName) "%1N = %1N,\n" else "%N,\n", parameter)
unindent()
}
}
}
.add(")")
return addFunction(
FunSpec.builder(builder.oldName)
.addTypeVariables(replacement.typeVariables)
.addCode(CodeBlock.builder().add("return ").addCallToNewFunction(explicitParameterName = false).build())
.addAnnotation(
AnnotationSpec.builder(Deprecated::class)
.addMember(
"message = %S + %S",
message,
" This variant of the method will be removed when the 2024.2 IntelliJ platform is shipped (see KTIJ-26314).",
)
.addMember(
CodeBlock.builder()
.add("replaceWith = ReplaceWith(\n")
.indent()
.add("\"\"\"")
.addCallToNewFunction(explicitParameterName = true)
.unindent()
.add("\"\"\",\n")
.apply {
for (additionalImport in builder.additionalImports) {
indent()
add("%S,\n", additionalImport)
unindent()
}
}
.add(")")
.build()
)
.addMember("level = %T.%N", DeprecationLevel::class, DeprecationLevel.HIDDEN.name)
.build(),
)
.addParameters(builder.deprecatedFunctionParameterSpecs)
.apply {
builder.returnType?.let { returns(it) }
}
.build(),
)
}