From 84bd12c6670039149e4bfef09e140268e73ab533 Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Wed, 6 Sep 2023 17:13:20 +0200 Subject: [PATCH] [FIR generator] Factor out field printer into the common code This is a step towards commonizing the code generator between FIR and IR: KT-61970 --- .../kotlin/fir/tree/generator/model/Field.kt | 15 +-- .../fir/tree/generator/printer/builder.kt | 2 +- .../fir/tree/generator/printer/element.kt | 5 +- .../fir/tree/generator/printer/field.kt | 90 ------------------ .../tree/generator/printer/implementation.kt | 28 ++++-- .../fir/tree/generator/printer/utils.kt | 7 +- .../kotlin/generators/tree/AbstractField.kt | 2 + .../generators/tree/AbstractFieldPrinter.kt | 95 +++++++++++++++++++ 8 files changed, 133 insertions(+), 111 deletions(-) delete mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt create mode 100644 generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt index ecb34cfdf62..eb822205faa 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt @@ -23,8 +23,9 @@ sealed class Field : AbstractField() { open var customInitializationCall: String? = null - open val defaultValueInImplementation: String? get() = null - abstract var isMutableOrEmpty: Boolean + open val isMutableOrEmptyList: Boolean + get() = false + open var isMutableInInterface: Boolean = false open val fromDelegate: Boolean get() = false @@ -110,7 +111,9 @@ class FieldWithDefault(val origin: Field) : Field() { override var defaultValueInImplementation: String? = origin.defaultValueInImplementation var defaultValueInBuilder: String? = null override var isMutable: Boolean = origin.isMutable - override var isMutableOrEmpty: Boolean = origin.isMutableOrEmpty + override val isMutableOrEmptyList: Boolean + get() = origin.isMutableOrEmptyList + override var isMutableInInterface: Boolean = origin.isMutableInInterface override var withGetter: Boolean = false override var customSetter: String? = null @@ -148,7 +151,6 @@ class SimpleField( ) : Field() { override val isFirType: Boolean = false override var isMutable: Boolean = withReplace - override var isMutableOrEmpty: Boolean = false override fun internalCopy(): Field { return SimpleField( @@ -191,7 +193,6 @@ class FirField( override val isFirType: Boolean = true override var isMutable: Boolean = true - override var isMutableOrEmpty: Boolean = false override var isLateinit: Boolean = false override var isParameter: Boolean = false @@ -221,7 +222,7 @@ class FieldList( override var isVolatile: Boolean = false override var isFinal: Boolean = false override var isMutable: Boolean = true - override var isMutableOrEmpty: Boolean = useMutableOrEmpty + override val isMutableOrEmptyList: Boolean = useMutableOrEmpty override var isLateinit: Boolean = false override var isParameter: Boolean = false @@ -230,7 +231,7 @@ class FieldList( name, baseType, withReplace, - isMutableOrEmpty + isMutableOrEmptyList ) } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt index 7c46bdb0ba8..9e1ca7d27cf 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/builder.kt @@ -83,7 +83,7 @@ private fun SmartPrinter.printBuilder(builder: Builder) { if (field.invisibleField) continue val name = field.name print(name) - if (field.isMutableOrEmpty) { + if (field.isMutableOrEmptyList) { addImport(toMutableOrEmptyImport) print(".toMutableOrEmpty()") } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt index e62ed105933..c0326df88b6 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/element.kt @@ -22,6 +22,8 @@ fun Element.generateCode(generationPath: File): GeneratedFile = printElement(this@generateCode) } +private class ElementFieldPrinter(printer: SmartPrinter) : AbstractFieldPrinter(printer) + context(ImportCollector) fun SmartPrinter.printElement(element: Element) { with(element) { @@ -52,9 +54,10 @@ fun SmartPrinter.printElement(element: Element) { print(params.multipleUpperBoundsList()) println(" {") withIndent { + val fieldPrinter = ElementFieldPrinter(this@printElement) allFields.forEach { field -> if (field.isFinal && field.fromParent || field.isParameter) return@forEach - printField(field, isImplementation = false, override = field.fromParent) { + fieldPrinter.printField(field, override = field.fromParent) { if (!field.isFinal) { abstract() } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt deleted file mode 100644 index b202f9797bf..00000000000 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/field.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.fir.tree.generator.printer - -import org.jetbrains.kotlin.fir.tree.generator.model.Field -import org.jetbrains.kotlin.generators.tree.ImportCollector -import org.jetbrains.kotlin.generators.tree.printer.printKDoc -import org.jetbrains.kotlin.generators.tree.render -import org.jetbrains.kotlin.utils.SmartPrinter -import org.jetbrains.kotlin.utils.withIndent - -context(ImportCollector) -fun SmartPrinter.printField( - field: Field, - isImplementation: Boolean, - override: Boolean, - inConstructor: Boolean = false, - modifiers: SmartPrinter.() -> Unit = {}, -) { - if (!override && field.kDoc != null) { - println() - printKDoc(field.kDoc) - } - if (!field.isVal && field.isVolatile) { - println("@Volatile") - } - - field.optInAnnotation?.let { - val rendered = it.render() - println(if (inConstructor) "@property:$rendered" else "@$rendered") - } - - modifiers() - - if (override) { - print("override ") - } - if (field.isLateinit) { - print("lateinit ") - } - if (isImplementation && !field.isVal || field.isFinal && field.isMutable) { - print("var") - } else { - print("val") - } - val type = if (isImplementation) field.getMutableType() else field.typeRef - print(" ${field.name}: ${type.render()}") - if (inConstructor) print(",") - println() -} - -context(ImportCollector) -fun SmartPrinter.printFieldWithDefaultInImplementation(field: Field) { - if (!field.isVal && field.isVolatile) { - println("@Volatile") - } - field.optInAnnotation?.let { - println("@OptIn(${it.render()}::class)") - } - val defaultValue = field.defaultValueInImplementation - print("override ") - if (field.isVal) { - print("val") - } else { - print("var") - } - print(" ${field.name}: ${field.getMutableType().render()}") - if (field.withGetter) { - println() - pushIndent() - print("get()") - } - requireNotNull(defaultValue) { - "No default value for $field" - } - println(" = $defaultValue") - field.customSetter?.let { - println("set(value) {") - withIndent { - println(it) - } - println("}") - } - if (field.withGetter) { - popIndent() - } -} diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt index 1bf8ac86c49..3d38ae1bd4c 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.tree.generator.printer +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.tree.generator.* import org.jetbrains.kotlin.fir.tree.generator.model.* import org.jetbrains.kotlin.generators.tree.* @@ -30,6 +31,19 @@ fun Implementation.generateCode(generationPath: File): GeneratedFile = printImplementation(this@generateCode) } +private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldPrinter(printer) { + + private fun Field.isMutableOrEmptyIfList(): Boolean = when (this) { + is FieldList -> isMutableOrEmptyList + is FieldWithDefault -> origin.isMutableOrEmptyIfList() + else -> true + } + + override fun forceMutable(field: Field): Boolean = field.isMutable && field.isMutableOrEmptyIfList() + + override fun actualTypeOfField(field: Field) = field.getMutableType() +} + context(ImportCollector) fun SmartPrinter.printImplementation(implementation: Implementation) { fun Field.transform() { @@ -78,6 +92,8 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { } } + val fieldPrinter = ImplementationFieldPrinter(this@printImplementation) + if (!isInterface && !isAbstract && fieldsWithoutDefault.isNotEmpty()) { if (isPublic) { print(" @${firImplementationDetailType.render()} constructor") @@ -90,7 +106,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { if (field.nullable) print("?") println(",") } else if (!field.isFinal) { - printField(field, isImplementation = true, override = true, inConstructor = true) + fieldPrinter.printField(field, override = true, inConstructor = true) } } } @@ -106,13 +122,11 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { withIndent { if (isInterface || isAbstract) { allFields.forEach { - - abstract() - printField(it, isImplementation = true, override = true) + fieldPrinter.printField(it, override = true, modality = Modality.ABSTRACT.takeIf { isAbstract }) } } else { fieldsWithDefault.forEach { - printFieldWithDefaultInImplementation(it) + fieldPrinter.printField(it, override = true) } if (fieldsWithDefault.isNotEmpty()) { println() @@ -375,7 +389,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { when { field.withGetter -> {} - field.origin is FieldList && !field.isMutableOrEmpty -> { + field.origin is FieldList && !field.isMutableOrEmptyList -> { println("${field.name}.clear()") println("${field.name}.addAll($newValue)") } @@ -385,7 +399,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { println("require($newValue != null)") } print("${field.name} = $newValue") - if (field.origin is FieldList && field.isMutableOrEmpty) { + if (field.origin is FieldList && field.isMutableOrEmptyList) { addImport(toMutableOrEmptyImport) print(".toMutableOrEmpty()") } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt index 143fcaae65f..ecd1b050f19 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt @@ -9,9 +9,6 @@ import org.jetbrains.kotlin.fir.tree.generator.firTransformerType import org.jetbrains.kotlin.fir.tree.generator.model.* import org.jetbrains.kotlin.generators.tree.* -val Field.isVal: Boolean - get() = (this is FieldList && !isMutableOrEmpty) || (this is FieldWithDefault && origin is FieldList && !origin.isMutableOrEmpty) || !isMutable - context(ImportCollector) fun Field.transformFunctionDeclaration(returnType: TypeRef): String { return transformFunctionDeclaration(name.replaceFirstChar(Char::uppercaseChar), returnType) @@ -34,9 +31,9 @@ fun Field.replaceFunctionDeclaration( return "fun replace$capName(new$capName: ${typeWithNullable.render()})" } -fun Field.getMutableType(forBuilder: Boolean = false): TypeRef = when (this) { +fun Field.getMutableType(forBuilder: Boolean = false): TypeRefWithNullability = when (this) { is FieldList -> when { - isMutableOrEmpty && !forBuilder -> type(BASE_PACKAGE, "MutableOrEmptyList", kind = TypeKind.Class) + isMutableOrEmptyList && !forBuilder -> type(BASE_PACKAGE, "MutableOrEmptyList", kind = TypeKind.Class) isMutable -> StandardTypes.mutableList else -> StandardTypes.list }.withArgs(baseType).copy(nullable) diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt index b2c928b2ce4..41e06e9b8dd 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt @@ -34,6 +34,8 @@ abstract class AbstractField { var fromParent: Boolean = false + open val defaultValueInImplementation: String? get() = null + override fun toString(): String { return name } diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt new file mode 100644 index 00000000000..5f714694be5 --- /dev/null +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt @@ -0,0 +1,95 @@ +/* + * 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 + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.generators.tree.printer.printKDoc +import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly +import org.jetbrains.kotlin.utils.SmartPrinter +import org.jetbrains.kotlin.utils.withIndent + +abstract class AbstractFieldPrinter( + private val printer: SmartPrinter, +) { + + /** + * Allows to forcibly make the field a `var` instead of `val`. + */ + protected open fun forceMutable(field: Field): Boolean = false + + /** + * Allows to override the printed type of [field]. For example, for list fields we may want to use [MutableList] instead of [List] + * in implementation classes. + */ + protected open fun actualTypeOfField(field: Field): TypeRefWithNullability = field.typeRef + + context(ImportCollector) + fun printField( + field: Field, + override: Boolean, + inConstructor: Boolean = false, + modality: Modality? = null, + ) { + printer.run { + printKDoc(field.kDoc) + if (field.isVolatile) { + println("@", type().render()) + } + + val defaultValue = field.defaultValueInImplementation + + field.optInAnnotation?.let { + val rendered = it.render() + when { + defaultValue != null -> println("@OptIn(", rendered, "::class)") + inConstructor -> println("@property:", rendered) + else -> println("@", rendered) + } + } + + modality?.let { + print(it.name.toLowerCaseAsciiOnly(), " ") + } + + if (override) { + print("override ") + } + if (field.isLateinit) { + print("lateinit ") + } + if (forceMutable(field) || field.isFinal && field.isMutable) { + print("var ") + } else { + print("val ") + } + print(field.name, ": ", actualTypeOfField(field).render()) + if (inConstructor) { + print(",") + } + if (defaultValue == null) { + println() + return + } + + if (field.withGetter) { + println() + pushIndent() + print("get()") + } + println(" = $defaultValue") + field.customSetter?.let { + println("set(value) {") + withIndent { + println(it) + } + println("}") + } + if (field.withGetter) { + popIndent() + } + } + } +} \ No newline at end of file