From 8aa0b6a5624084adfb435036ce0d90294b1ba429 Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Tue, 18 Jul 2023 17:54:59 +0200 Subject: [PATCH] [IR] Automatically generate IrFactory interface ^KT-59308 Fixed --- .../kotlin/ir/declarations/IrFactory.kt | 89 +++-- .../ir.tree/tree-generator/build.gradle.kts | 1 + .../jetbrains/kotlin/ir/generator/IrTree.kt | 153 ++++++-- .../org/jetbrains/kotlin/ir/generator/Main.kt | 1 + .../kotlin/ir/generator/config/ConfigModel.kt | 26 ++ .../kotlin/ir/generator/model/Model.kt | 40 +- .../ir/generator/model/Transformations.kt | 96 +++-- .../kotlin/ir/generator/print/Factory.kt | 368 ++++++++++++++++++ 8 files changed, 650 insertions(+), 124 deletions(-) rename compiler/ir/ir.tree/{src => gen}/org/jetbrains/kotlin/ir/declarations/IrFactory.kt (94%) create mode 100644 compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Factory.kt diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFactory.kt b/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/declarations/IrFactory.kt similarity index 94% rename from compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFactory.kt rename to compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/declarations/IrFactory.kt index 235992f4d15..ce929718d25 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrFactory.kt +++ b/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/declarations/IrFactory.kt @@ -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." + diff --git a/compiler/ir/ir.tree/tree-generator/build.gradle.kts b/compiler/ir/ir.tree/tree-generator/build.gradle.kts index 0ccd44eca24..b6199b11e3f 100644 --- a/compiler/ir/ir.tree/tree-generator/build.gradle.kts +++ b/compiler/ir/ir.tree/tree-generator/build.gradle.kts @@ -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()) diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt index e7db4b471ed..4c6b0d2e609 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt @@ -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(TypeKind.Interface, "org.jetbrains.kotlin.descriptors", typeName), mutable = false) + + private fun descriptor(typeName: String, nullable: Boolean = false): SimpleFieldConfig = + field( + name = "descriptor", + type = ClassRef(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(), nullable = true, mutable = false) + +field("containerSource", type(), 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()) +field("modality", type()) - +field("isCompanion", boolean) - +field("isInner", boolean) - +field("isData", boolean) - +field("isValue", boolean) - +field("isExpect", boolean) - +field("isFun", boolean) - +field("source", type(), 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(), 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>().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()) +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(), 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()) + +field("source", type()) { + useFieldInIrFactory(defaultValue = code("%T.NO_SOURCE", SourceElement::class)) + } +field("constructorTypeArgumentsCount", int) } val getSingletonValue: ElementConfig by element(Expression) { diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/Main.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/Main.kt index 1bfc35897d5..d9fd3314065 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/Main.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/Main.kt @@ -30,6 +30,7 @@ fun main(args: Array) { 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 diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/config/ConfigModel.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/config/ConfigModel.kt index 60ca85665f8..f58244b7b2d 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/config/ConfigModel.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/config/ConfigModel.kt @@ -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() + val fieldsToSkipInIrFactoryMethod = hashSetOf() + /** * 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 diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt index f14a235234c..6dd784b344e 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt @@ -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, val fields: MutableList, + val additionalFactoryMethodParameters: MutableList, ) { var elementParents: List = emptyList() var otherParents: List> = 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 { + 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 { + 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, diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt index 8ef738750d4..dbed7720a88 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Transformations.kt @@ -20,56 +20,16 @@ fun config2model(config: Config): Model { val ec2el = mutableMapOf() 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): Element { val visited = mutableMapOf() diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Factory.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Factory.kt new file mode 100644 index 00000000000..59ed882ac84 --- /dev/null +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Factory.kt @@ -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() + + var oldName = replacement.name + + var returnType = replacement.returnType + + var deprecationMessage: String? = null + + val additionalImports = mutableListOf() + + 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(), + ) +} \ No newline at end of file