[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
This commit is contained in:
committed by
Space Team
parent
bca35c0015
commit
84bd12c667
+8
-7
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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()")
|
||||
}
|
||||
|
||||
+4
-1
@@ -22,6 +22,8 @@ fun Element.generateCode(generationPath: File): GeneratedFile =
|
||||
printElement(this@generateCode)
|
||||
}
|
||||
|
||||
private class ElementFieldPrinter(printer: SmartPrinter) : AbstractFieldPrinter<Field>(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()
|
||||
}
|
||||
|
||||
-90
@@ -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()
|
||||
}
|
||||
}
|
||||
+21
-7
@@ -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<Field>(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()")
|
||||
}
|
||||
|
||||
+2
-5
@@ -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)
|
||||
|
||||
+2
@@ -34,6 +34,8 @@ abstract class AbstractField {
|
||||
|
||||
var fromParent: Boolean = false
|
||||
|
||||
open val defaultValueInImplementation: String? get() = null
|
||||
|
||||
override fun toString(): String {
|
||||
return name
|
||||
}
|
||||
|
||||
+95
@@ -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<Field : AbstractField>(
|
||||
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<Volatile>().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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user