[FIR/IR generator] Introduce ImportCollector
This class enables printing the import list in generated files in a smarter way. Also, refactor `Importable` interface hierarchy, namely, don't inherit `TypeRef` from `Importable`, since we have types like `TypeRef.Star` which are not really importable. Replace the `Importable#typeWithArguments` property with the `TypeRef#render` method to utilize `ImportCollector` while rendering types.
This commit is contained in:
committed by
Space Team
parent
bec6d38490
commit
7b7bcb8ffa
+1
-1
@@ -447,7 +447,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
|
||||
field = "attributes",
|
||||
fieldPredicate = { it.typeRef == declarationAttributesType }
|
||||
) {
|
||||
default(it, "${declarationAttributesType.type}()")
|
||||
default(it, "${declarationAttributesType.typeName}()")
|
||||
}
|
||||
|
||||
configureFieldInAllLeafBuilders(
|
||||
|
||||
+5
-5
@@ -632,7 +632,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
|
||||
configureFieldInAllImplementations(
|
||||
"status",
|
||||
implementationPredicate = { it.type in implementationsWithoutStatusAndTypeParameters }
|
||||
implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters }
|
||||
) {
|
||||
default(it, "FirResolvedDeclarationStatusImpl.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS")
|
||||
useTypes(resolvedDeclarationStatusImplType)
|
||||
@@ -640,7 +640,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
|
||||
configureFieldInAllImplementations(
|
||||
"typeParameters",
|
||||
implementationPredicate = { it.type in implementationsWithoutStatusAndTypeParameters }
|
||||
implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters }
|
||||
) {
|
||||
defaultEmptyList(it)
|
||||
useTypes(resolvedDeclarationStatusImplType)
|
||||
@@ -650,7 +650,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
private fun configureAllImplementations() {
|
||||
configureFieldInAllImplementations(
|
||||
field = "controlFlowGraphReference",
|
||||
implementationPredicate = { it.type != "FirAnonymousFunctionImpl" }
|
||||
implementationPredicate = { it.typeName != "FirAnonymousFunctionImpl" }
|
||||
) {
|
||||
defaultNull(it)
|
||||
}
|
||||
@@ -682,7 +682,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
)
|
||||
configureFieldInAllImplementations(
|
||||
field = "typeRef",
|
||||
implementationPredicate = { it.type !in implementationWithConfigurableTypeRef },
|
||||
implementationPredicate = { it.typeName !in implementationWithConfigurableTypeRef },
|
||||
fieldPredicate = { it.defaultValueInImplementation == null }
|
||||
) {
|
||||
default(it, "FirImplicitTypeRefImplWithoutSource")
|
||||
@@ -691,7 +691,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
|
||||
configureFieldInAllImplementations(
|
||||
field = "lValueTypeRef",
|
||||
implementationPredicate = { it.type in "FirVariableAssignmentImpl" },
|
||||
implementationPredicate = { it.typeName in "FirVariableAssignmentImpl" },
|
||||
fieldPredicate = { it.defaultValueInImplementation == null }
|
||||
) {
|
||||
default(it, "FirImplicitTypeRefImplWithoutSource")
|
||||
|
||||
+3
-3
@@ -50,7 +50,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
}
|
||||
|
||||
typeParameterRef.configure {
|
||||
+symbol(typeParameterSymbolType.type)
|
||||
+symbol(typeParameterSymbolType.typeName)
|
||||
}
|
||||
|
||||
typeParametersOwner.configure {
|
||||
@@ -85,7 +85,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
isMutable = true; isVolatile = true; isFinal = true; isLateinit = true
|
||||
customInitializationCall = "resolvePhase.asResolveState()"
|
||||
arbitraryImportables += phaseAsResolveStateExtentionImport
|
||||
optInAnnotation = resolveStateAccessImport
|
||||
optInAnnotation = resolveStateAccessAnnotation
|
||||
}
|
||||
|
||||
+field("moduleData", firModuleDataType)
|
||||
@@ -137,7 +137,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
|
||||
expression.configure {
|
||||
+field("coneTypeOrNull", coneKotlinTypeType, nullable = true, withReplace = true).apply {
|
||||
optInAnnotation = unresolvedExpressionTypeAccessImport
|
||||
optInAnnotation = unresolvedExpressionTypeAccessAnnotation
|
||||
}
|
||||
+annotations
|
||||
}
|
||||
|
||||
@@ -115,3 +115,14 @@ val errorTypeRefImplType = type("fir.types.impl", "FirErrorTypeRefImpl")
|
||||
val annotationResolvePhaseType = generatedType("expressions", "FirAnnotationResolvePhase")
|
||||
|
||||
val typeRefMarkerType = type("mpp", "TypeRefMarker")
|
||||
|
||||
val firVisitorType = type("fir.visitors", "FirVisitor", kind = TypeKind.Class)
|
||||
val firVisitorVoidType = type("fir.visitors", "FirVisitorVoid", kind = TypeKind.Class)
|
||||
val firDefaultVisitorType = type("fir.visitors", "FirDefaultVisitor", kind = TypeKind.Class)
|
||||
val firDefaultVisitorVoidType = type("fir.visitors", "FirDefaultVisitorVoid", kind = TypeKind.Class)
|
||||
val firTransformerType = type("fir.visitors", "FirTransformer", kind = TypeKind.Class)
|
||||
|
||||
val resolveStateAccessAnnotation = type("fir.declarations", "ResolveStateAccess", kind = TypeKind.Class)
|
||||
val unresolvedExpressionTypeAccessAnnotation = type("fir.expressions", "UnresolvedExpressionTypeAccess", kind = TypeKind.Class)
|
||||
val firBuilderDslAnnotation = type("fir.builder", "FirBuilderDsl", kind = TypeKind.Class)
|
||||
val experimentalContractsAnnotation = type("kotlin.contracts", "ExperimentalContracts", exactPackage = true, kind = TypeKind.Class)
|
||||
|
||||
+3
-3
@@ -153,18 +153,18 @@ abstract class AbstractBuilderConfigurator<T : AbstractFirTreeBuilder>(val firTr
|
||||
val message = buildString {
|
||||
appendLine("${this@extractImplementation} has multiple implementations:")
|
||||
for (implementation in allImplementations) {
|
||||
appendLine(" - ${implementation.type}")
|
||||
appendLine(" - ${implementation.typeName}")
|
||||
}
|
||||
appendLine("Please specify implementation is needed")
|
||||
}
|
||||
throw IllegalArgumentException(message)
|
||||
}
|
||||
} else {
|
||||
allImplementations.firstOrNull { it.type == type } ?: this@AbstractBuilderConfigurator.run {
|
||||
allImplementations.firstOrNull { it.typeName == type } ?: this@AbstractBuilderConfigurator.run {
|
||||
val message = buildString {
|
||||
appendLine("${this@extractImplementation} has not implementation $type. Existing implementations:")
|
||||
for (implementation in allImplementations) {
|
||||
appendLine(" - ${implementation.type}")
|
||||
appendLine(" - ${implementation.typeName}")
|
||||
}
|
||||
appendLine("Please specify implementation is needed")
|
||||
}
|
||||
|
||||
+3
-2
@@ -5,11 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.printer.VISITOR_PACKAGE
|
||||
import org.jetbrains.kotlin.generators.tree.ArbitraryImportable
|
||||
|
||||
val phaseAsResolveStateExtentionImport = ArbitraryImportable("org.jetbrains.kotlin.fir.declarations", "asResolveState")
|
||||
val resolvePhaseExtensionImport = ArbitraryImportable("org.jetbrains.kotlin.fir.declarations", "resolvePhase")
|
||||
val resolveStateAccessImport = ArbitraryImportable("org.jetbrains.kotlin.fir.declarations", "ResolveStateAccess")
|
||||
val resolvedDeclarationStatusImport = ArbitraryImportable("org.jetbrains.kotlin.fir.declarations.impl", "FirResolvedDeclarationStatusImpl")
|
||||
|
||||
val buildResolvedTypeRefImport = ArbitraryImportable("org.jetbrains.kotlin.fir.types.builder", "buildResolvedTypeRef")
|
||||
@@ -21,4 +21,5 @@ val coneTypeOrNullImport = ArbitraryImportable("org.jetbrains.kotlin.fir.types",
|
||||
val fakeSourceElementKindImport = ArbitraryImportable("org.jetbrains.kotlin", "KtFakeSourceElementKind")
|
||||
val fakeElementImport = ArbitraryImportable("org.jetbrains.kotlin", "fakeElement")
|
||||
|
||||
val unresolvedExpressionTypeAccessImport = ArbitraryImportable("org.jetbrains.kotlin.fir.expressions","UnresolvedExpressionTypeAccess")
|
||||
val transformInPlaceImport = ArbitraryImportable(VISITOR_PACKAGE, "transformInplace")
|
||||
val toMutableOrEmptyImport = ArbitraryImportable("org.jetbrains.kotlin.fir.builder", "toMutableOrEmpty")
|
||||
|
||||
+18
-12
@@ -5,13 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator.model
|
||||
|
||||
import org.jetbrains.kotlin.generators.tree.FieldContainer
|
||||
import org.jetbrains.kotlin.generators.tree.Importable
|
||||
import org.jetbrains.kotlin.generators.tree.printer.generics
|
||||
import org.jetbrains.kotlin.generators.tree.*
|
||||
|
||||
private const val DEFAULT_BUILDER_PACKAGE = "org.jetbrains.kotlin.fir.tree.builder"
|
||||
|
||||
sealed class Builder : FieldContainer, Importable {
|
||||
sealed class Builder : FieldContainer, TypeRef, Importable {
|
||||
val parents: MutableList<IntermediateBuilder> = mutableListOf()
|
||||
val usedTypes: MutableList<Importable> = mutableListOf()
|
||||
abstract override val allFields: List<FieldWithDefault>
|
||||
@@ -21,7 +19,7 @@ sealed class Builder : FieldContainer, Importable {
|
||||
|
||||
override fun get(fieldName: String): FieldWithDefault {
|
||||
return allFields.firstOrNull { it.name == fieldName }
|
||||
?: throw IllegalArgumentException("Builder $type doesn't contains field $fieldName")
|
||||
?: throw IllegalArgumentException("Builder $typeName doesn't contains field $fieldName")
|
||||
}
|
||||
|
||||
private val fieldsFromParentIndex: Map<String, Boolean> by lazy {
|
||||
@@ -33,18 +31,23 @@ sealed class Builder : FieldContainer, Importable {
|
||||
}
|
||||
|
||||
fun isFromParent(field: Field): Boolean = fieldsFromParentIndex.getValue(field.name)
|
||||
|
||||
override fun substitute(map: TypeParameterSubstitutionMap) = this
|
||||
}
|
||||
|
||||
class LeafBuilder(val implementation: Implementation) : Builder() {
|
||||
override val type: String
|
||||
override val typeName: String
|
||||
get() = if (implementation.name != null) {
|
||||
"${implementation.name}Builder"
|
||||
} else {
|
||||
"${implementation.element.type}Builder"
|
||||
"${implementation.element.typeName}Builder"
|
||||
}
|
||||
|
||||
override val typeWithArguments: String
|
||||
get() = type + implementation.element.generics
|
||||
context(ImportCollector)
|
||||
override fun renderTo(appendable: Appendable) {
|
||||
addImport(this)
|
||||
appendable.append(typeName)
|
||||
}
|
||||
|
||||
override val allFields: List<FieldWithDefault> by lazy { implementation.fieldsWithoutDefault }
|
||||
|
||||
@@ -59,7 +62,7 @@ class LeafBuilder(val implementation: Implementation) : Builder() {
|
||||
var wantsCopy: Boolean = false
|
||||
}
|
||||
|
||||
class IntermediateBuilder(override val type: String) : Builder() {
|
||||
class IntermediateBuilder(override val typeName: String) : Builder() {
|
||||
val fields: MutableList<FieldWithDefault> = mutableListOf()
|
||||
var materializedElement: Element? = null
|
||||
|
||||
@@ -73,6 +76,9 @@ class IntermediateBuilder(override val type: String) : Builder() {
|
||||
override val uselessFields: List<FieldWithDefault> = emptyList()
|
||||
override var packageName: String = DEFAULT_BUILDER_PACKAGE
|
||||
|
||||
override val typeWithArguments: String
|
||||
get() = type
|
||||
context(ImportCollector)
|
||||
override fun renderTo(appendable: Appendable) {
|
||||
addImport(this)
|
||||
appendable.append(typeName)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -33,9 +33,9 @@ class Element(override val name: String, override val propertyName: String, kind
|
||||
override var kDoc: String? = null
|
||||
|
||||
override val fields = mutableSetOf<Field>()
|
||||
override val type: String = "Fir$name"
|
||||
override val typeName: String = "Fir$name"
|
||||
|
||||
override val packageName: String = BASE_PACKAGE + kind.packageName.let { if (it.isBlank()) it else "." + it }
|
||||
override val fullQualifiedName: String get() = super.fullQualifiedName!!
|
||||
|
||||
override val elementParents = mutableListOf<ElementRef>()
|
||||
|
||||
@@ -158,7 +158,7 @@ class Element(override val name: String, override val propertyName: String, kind
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return typeWithArguments
|
||||
return with(ImportCollector("")) { render() }
|
||||
}
|
||||
|
||||
enum class Kind(val packageName: String) {
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@ fun field(name: String, type: TypeRefWithNullability, nullable: Boolean = false,
|
||||
return SimpleField(name, type.copy(nullable), withReplace)
|
||||
}
|
||||
|
||||
fun field(type: TypeRefWithNullability, nullable: Boolean = false, withReplace: Boolean = false): Field {
|
||||
return SimpleField(type.type.replaceFirstChar(Char::lowercaseChar), type.copy(nullable), withReplace)
|
||||
fun field(type: ClassRef<*>, nullable: Boolean = false, withReplace: Boolean = false): Field {
|
||||
return SimpleField(type.simpleName.replaceFirstChar(Char::lowercaseChar), type.copy(nullable), withReplace)
|
||||
}
|
||||
|
||||
fun booleanField(name: String, withReplace: Boolean = false): Field {
|
||||
|
||||
+1
-2
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator.model
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.printer.generics
|
||||
import org.jetbrains.kotlin.generators.tree.*
|
||||
import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef
|
||||
|
||||
@@ -104,7 +103,7 @@ class FieldWithDefault(val origin: Field) : Field() {
|
||||
get() = origin.customInitializationCall
|
||||
set(_) {}
|
||||
|
||||
override var optInAnnotation: ArbitraryImportable?
|
||||
override var optInAnnotation: ClassRef<*>?
|
||||
get() = origin.optInAnnotation
|
||||
set(_) {}
|
||||
|
||||
|
||||
+12
-9
@@ -5,18 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator.model
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.printer.generics
|
||||
import org.jetbrains.kotlin.generators.tree.*
|
||||
import org.jetbrains.kotlin.generators.tree.printer.generics
|
||||
|
||||
class ImplementationWithArg(
|
||||
val implementation: Implementation,
|
||||
val argument: Importable?
|
||||
) : FieldContainer by implementation, ImplementationKindOwner by implementation {
|
||||
val element: Element get() = implementation.element
|
||||
|
||||
override val typeWithArguments: String
|
||||
get() = type + generics
|
||||
}
|
||||
|
||||
class Implementation(val element: Element, val name: String?) : FieldContainer, ImplementationKindOwner {
|
||||
@@ -25,7 +20,8 @@ class Implementation(val element: Element, val name: String?) : FieldContainer,
|
||||
|
||||
override val allParents: List<ImplementationKindOwner> get() = listOf(element) + parents
|
||||
val isDefault = name == null
|
||||
override val type = name ?: element.type + "Impl"
|
||||
override val typeName = name ?: (element.typeName + "Impl")
|
||||
|
||||
override val allFields = element.allFields.toMutableList().mapTo(mutableListOf()) {
|
||||
FieldWithDefault(it)
|
||||
}
|
||||
@@ -42,12 +38,19 @@ class Implementation(val element: Element, val name: String?) : FieldContainer,
|
||||
}
|
||||
}
|
||||
|
||||
override val typeWithArguments: String
|
||||
get() = type + element.generics
|
||||
context(ImportCollector)
|
||||
override fun renderTo(appendable: Appendable) {
|
||||
addImport(this)
|
||||
appendable.append(this.typeName)
|
||||
if (element.params.isNotEmpty()) {
|
||||
element.params.joinTo(appendable, prefix = "<", postfix = ">") { it.name }
|
||||
}
|
||||
}
|
||||
|
||||
override fun substitute(map: TypeParameterSubstitutionMap) = this
|
||||
|
||||
override val packageName = element.packageName + ".impl"
|
||||
val usedTypes = mutableListOf<Importable>()
|
||||
val arbitraryImportables = mutableListOf<ArbitraryImportable>()
|
||||
|
||||
var isPublic = false
|
||||
var requiresOptIn = false
|
||||
|
||||
+56
-38
@@ -5,32 +5,38 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator.printer
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.declarationAttributesType
|
||||
import org.jetbrains.kotlin.fir.tree.generator.*
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.*
|
||||
import org.jetbrains.kotlin.generators.tree.ImportCollector
|
||||
import org.jetbrains.kotlin.generators.tree.StandardTypes
|
||||
import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
|
||||
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
|
||||
import org.jetbrains.kotlin.generators.tree.render
|
||||
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||
import org.jetbrains.kotlin.utils.withIndent
|
||||
import java.io.File
|
||||
|
||||
fun Builder.generateCode(generationPath: File): GeneratedFile =
|
||||
printGeneratedType(generationPath, TREE_GENERATOR_README, packageName, type, fileSuppressions = listOf("DuplicatedCode", "unused")) {
|
||||
val imports = collectImports()
|
||||
imports.forEach { println("import $it") }
|
||||
if (imports.isNotEmpty()) {
|
||||
println()
|
||||
}
|
||||
printGeneratedType(
|
||||
generationPath,
|
||||
TREE_GENERATOR_README,
|
||||
packageName,
|
||||
typeName,
|
||||
fileSuppressions = listOf("DuplicatedCode", "unused"),
|
||||
) {
|
||||
println()
|
||||
addAllImports(usedTypes)
|
||||
printBuilder(this@generateCode)
|
||||
}
|
||||
|
||||
context(ImportCollector)
|
||||
private fun SmartPrinter.printBuilder(builder: Builder) {
|
||||
if (builder is LeafBuilder && builder.allFields.isEmpty()) {
|
||||
printDslBuildFunction(builder, false)
|
||||
return
|
||||
}
|
||||
|
||||
println("@FirBuilderDsl")
|
||||
println("@${firBuilderDslAnnotation.render()}")
|
||||
when (builder) {
|
||||
is IntermediateBuilder -> print("interface ")
|
||||
is LeafBuilder -> {
|
||||
@@ -40,9 +46,9 @@ private fun SmartPrinter.printBuilder(builder: Builder) {
|
||||
print("class ")
|
||||
}
|
||||
}
|
||||
print(builder.typeWithArguments)
|
||||
print(builder.render())
|
||||
if (builder.parents.isNotEmpty()) {
|
||||
print(builder.parents.joinToString(separator = ", ", prefix = " : ") { it.type })
|
||||
print(builder.parents.joinToString(separator = ", ", prefix = " : ") { it.render() })
|
||||
}
|
||||
var hasRequiredFields = false
|
||||
println(" {")
|
||||
@@ -58,11 +64,11 @@ private fun SmartPrinter.printBuilder(builder: Builder) {
|
||||
println()
|
||||
}
|
||||
val buildType = when (builder) {
|
||||
is LeafBuilder -> builder.implementation.element.typeWithArguments
|
||||
is IntermediateBuilder -> builder.materializedElement!!.typeWithArguments.replace(Regex("<.>"), "<*>")
|
||||
is LeafBuilder -> builder.implementation.element.render()
|
||||
is IntermediateBuilder -> builder.materializedElement!!.withStarArgs().render()
|
||||
}
|
||||
if (builder is LeafBuilder && builder.implementation.isPublic) {
|
||||
println("@OptIn(FirImplementationDetail::class)")
|
||||
println("@OptIn(${firImplementationDetailType.render()}::class)")
|
||||
}
|
||||
if (builder.parents.isNotEmpty()) {
|
||||
print("override ")
|
||||
@@ -71,13 +77,16 @@ private fun SmartPrinter.printBuilder(builder: Builder) {
|
||||
if (builder is LeafBuilder) {
|
||||
println(" {")
|
||||
withIndent {
|
||||
println("return ${builder.implementation.type}(")
|
||||
println("return ${builder.implementation.render()}(")
|
||||
withIndent {
|
||||
for (field in builder.allFields) {
|
||||
if (field.invisibleField) continue
|
||||
val name = field.name
|
||||
print(name)
|
||||
if (field.isMutableOrEmpty) print(".toMutableOrEmpty()")
|
||||
if (field.isMutableOrEmpty) {
|
||||
addImport(toMutableOrEmptyImport)
|
||||
print(".toMutableOrEmpty()")
|
||||
}
|
||||
println(",")
|
||||
}
|
||||
}
|
||||
@@ -132,15 +141,17 @@ private fun FieldWithDefault.needBackingField(fieldIsUseless: Boolean) =
|
||||
private fun FieldWithDefault.needNotNullDelegate(fieldIsUseless: Boolean) =
|
||||
needBackingField(fieldIsUseless) && (typeRef == StandardTypes.boolean || typeRef == StandardTypes.int)
|
||||
|
||||
|
||||
private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: Builder, fieldIsUseless: Boolean): Pair<Boolean, Boolean> {
|
||||
context(ImportCollector)
|
||||
private fun SmartPrinter.printFieldInBuilder(
|
||||
field: FieldWithDefault,
|
||||
builder: Builder,
|
||||
fieldIsUseless: Boolean,
|
||||
): Pair<Boolean, Boolean> {
|
||||
if (field.withGetter && !fieldIsUseless || field.invisibleField) return false to false
|
||||
if (field.origin is FieldList) {
|
||||
printFieldListInBuilder(field.origin, builder, fieldIsUseless)
|
||||
return true to false
|
||||
}
|
||||
val name = field.name
|
||||
val type = field.typeRef.typeWithArguments
|
||||
val defaultValue = if (fieldIsUseless)
|
||||
field.defaultValueInImplementation.also { requireNotNull(it) }
|
||||
else
|
||||
@@ -148,7 +159,7 @@ private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: B
|
||||
|
||||
printDeprecationOnUselessFieldIfNeeded(field, builder, fieldIsUseless)
|
||||
printModifiers(builder, field, fieldIsUseless)
|
||||
print("var $name: $type")
|
||||
print("var ${field.name}: ${field.typeRef.render()}")
|
||||
var hasRequiredFields = false
|
||||
val needNewLine = when {
|
||||
fieldIsUseless -> {
|
||||
@@ -169,7 +180,7 @@ private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: B
|
||||
false
|
||||
}
|
||||
field.needNotNullDelegate(fieldIsUseless) -> {
|
||||
println(" by kotlin.properties.Delegates.notNull<${field.typeRef.type}>()")
|
||||
println(" by kotlin.properties.Delegates.notNull<${field.typeRef.render()}>()")
|
||||
hasRequiredFields = true
|
||||
true
|
||||
}
|
||||
@@ -200,14 +211,19 @@ private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: B
|
||||
|
||||
private fun SmartPrinter.printDeprecationOnUselessFieldIfNeeded(field: Field, builder: Builder, fieldIsUseless: Boolean) {
|
||||
if (fieldIsUseless) {
|
||||
println("@Deprecated(\"Modification of '${field.name}' has no impact for ${builder.type}\", level = DeprecationLevel.HIDDEN)")
|
||||
println("@Deprecated(\"Modification of '${field.name}' has no impact for ${builder.typeName}\", level = DeprecationLevel.HIDDEN)")
|
||||
}
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printFieldListInBuilder(field: FieldList, builder: Builder, fieldIsUseless: Boolean) {
|
||||
context(ImportCollector)
|
||||
private fun SmartPrinter.printFieldListInBuilder(
|
||||
field: FieldList,
|
||||
builder: Builder,
|
||||
fieldIsUseless: Boolean,
|
||||
) {
|
||||
printDeprecationOnUselessFieldIfNeeded(field, builder, fieldIsUseless)
|
||||
printModifiers(builder, field, fieldIsUseless)
|
||||
print("val ${field.name}: ${field.getMutableType(forBuilder = true).typeWithArguments}")
|
||||
print("val ${field.name}: ${field.getMutableType(forBuilder = true).render()}")
|
||||
if (builder is LeafBuilder) {
|
||||
print(" = mutableListOf()")
|
||||
}
|
||||
@@ -228,69 +244,71 @@ private fun SmartPrinter.printModifiers(builder: Builder, field: Field, fieldIsU
|
||||
}
|
||||
}
|
||||
|
||||
context(ImportCollector)
|
||||
private fun SmartPrinter.printDslBuildFunction(
|
||||
builder: LeafBuilder,
|
||||
hasRequiredFields: Boolean
|
||||
) {
|
||||
val isEmpty = builder.allFields.isEmpty()
|
||||
if (!isEmpty) {
|
||||
println("@OptIn(ExperimentalContracts::class)")
|
||||
println("@OptIn(${experimentalContractsAnnotation.render()}::class)")
|
||||
print("inline ")
|
||||
} else if(builder.implementation.isPublic) {
|
||||
println("@OptIn(FirImplementationDetail::class)")
|
||||
} else if (builder.implementation.isPublic) {
|
||||
println("@OptIn(${firImplementationDetailType.render()}::class)")
|
||||
}
|
||||
print("fun ")
|
||||
builder.implementation.element.params.takeIf { it.isNotEmpty() }?.let {
|
||||
print(it.joinToString(separator = ", ", prefix = "<", postfix = "> "))
|
||||
}
|
||||
val builderType = builder.typeWithArguments
|
||||
val name = builder.implementation.name?.replaceFirst("Fir", "") ?: builder.implementation.element.name
|
||||
print("build${name}(")
|
||||
if (!isEmpty) {
|
||||
print("init: $builderType.() -> Unit")
|
||||
print("init: ${builder.render()}.() -> Unit")
|
||||
if (!hasRequiredFields) {
|
||||
print(" = {}")
|
||||
}
|
||||
}
|
||||
println("): ${builder.implementation.element.typeWithArguments} {")
|
||||
println("): ${builder.implementation.element.render()} {")
|
||||
withIndent {
|
||||
if (!isEmpty) {
|
||||
addStarImport("kotlin.contracts")
|
||||
println("contract {")
|
||||
withIndent {
|
||||
println("callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)")
|
||||
println("callsInPlace(init, InvocationKind.EXACTLY_ONCE)")
|
||||
}
|
||||
println("}")
|
||||
}
|
||||
print("return ")
|
||||
if (isEmpty) {
|
||||
println("${builder.implementation.type}()")
|
||||
println("${builder.implementation.render()}()")
|
||||
} else {
|
||||
println("$builderType().apply(init).build()")
|
||||
println("${builder.render()}().apply(init).build()")
|
||||
}
|
||||
}
|
||||
println("}")
|
||||
}
|
||||
|
||||
context(ImportCollector)
|
||||
private fun SmartPrinter.printDslBuildCopyFunction(
|
||||
builder: LeafBuilder,
|
||||
hasRequiredFields: Boolean,
|
||||
) {
|
||||
val optIns =
|
||||
builder.allFields.filter { !it.invisibleField }.mapNotNullTo(mutableSetOf("ExperimentalContracts")) { it.optInAnnotation?.type }
|
||||
println("@OptIn(${optIns.joinToString { "$it::class" }})")
|
||||
builder.allFields.filter { !it.invisibleField }.mapNotNullTo(mutableSetOf(experimentalContractsAnnotation)) { it.optInAnnotation }
|
||||
println("@OptIn(${optIns.joinToString { "${it.render()}::class" }})")
|
||||
print("inline ")
|
||||
print("fun ")
|
||||
builder.implementation.element.params.takeIf { it.isNotEmpty() }?.let {
|
||||
print(it.joinToString(separator = ", ", prefix = "<", postfix = "> "))
|
||||
}
|
||||
val builderType = builder.typeWithArguments
|
||||
val builderType = builder.render()
|
||||
val name = builder.implementation.name?.replaceFirst("Fir", "") ?: builder.implementation.element.name
|
||||
print("build${name}Copy(")
|
||||
print("original: ${builder.implementation.element.typeWithArguments}, init: $builderType.() -> Unit")
|
||||
print("original: ${builder.implementation.element.render()}, init: $builderType.() -> Unit")
|
||||
if (!hasRequiredFields) {
|
||||
print(" = {}")
|
||||
}
|
||||
println("): ${builder.implementation.element.typeWithArguments} {")
|
||||
println("): ${builder.implementation.element.render()} {")
|
||||
withIndent {
|
||||
println("contract {")
|
||||
withIndent {
|
||||
|
||||
+24
-18
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator.printer
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.*
|
||||
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.Element
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.Field
|
||||
import org.jetbrains.kotlin.fir.tree.generator.util.get
|
||||
@@ -15,15 +17,12 @@ import org.jetbrains.kotlin.utils.withIndent
|
||||
import java.io.File
|
||||
|
||||
fun Element.generateCode(generationPath: File): GeneratedFile =
|
||||
printGeneratedType(generationPath, TREE_GENERATOR_README, packageName, type) {
|
||||
val imports = collectImports()
|
||||
imports.forEach { println("import $it") }
|
||||
if (imports.isNotEmpty()) {
|
||||
println()
|
||||
}
|
||||
printGeneratedType(generationPath, TREE_GENERATOR_README, packageName, this.typeName) {
|
||||
println()
|
||||
printElement(this@generateCode)
|
||||
}
|
||||
|
||||
context(ImportCollector)
|
||||
fun SmartPrinter.printElement(element: Element) {
|
||||
with(element) {
|
||||
val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface
|
||||
@@ -40,13 +39,13 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
}
|
||||
|
||||
printKDoc(element.extendedKDoc())
|
||||
print("${kind!!.title} $type")
|
||||
print("${kind!!.title} $typeName")
|
||||
print(typeParameters())
|
||||
val parentRefs = element.parentRefs
|
||||
if (parentRefs.isNotEmpty()) {
|
||||
print(
|
||||
parentRefs.sortedBy { it.typeKind }.joinToString(prefix = " : ") { parent ->
|
||||
parent.typeWithArguments + parent.inheritanceClauseParenthesis()
|
||||
parent.render() + parent.inheritanceClauseParenthesis()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -66,8 +65,9 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
if (allFields.isNotEmpty()) {
|
||||
println()
|
||||
}
|
||||
|
||||
override()
|
||||
println("fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =")
|
||||
println("fun <R, D> accept(visitor: ${firVisitorType.render()}<R, D>, data: D): R =")
|
||||
withIndent {
|
||||
println("visitor.visit${element.name}(this, data)")
|
||||
}
|
||||
@@ -77,7 +77,13 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
println()
|
||||
println("@Suppress(\"UNCHECKED_CAST\")")
|
||||
override()
|
||||
println("fun <E : FirElement, D> transform(transformer: FirTransformer<D>, data: D): E =")
|
||||
println(
|
||||
"fun <E : ",
|
||||
AbstractFirTreeBuilder.baseFirElement.render(),
|
||||
", D> transform(transformer: ",
|
||||
firTransformerType.render(),
|
||||
"<D>, data: D): E ="
|
||||
)
|
||||
withIndent {
|
||||
println("transformer.transform$name(this, data) as E")
|
||||
}
|
||||
@@ -86,7 +92,7 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
fun Field.replaceDeclaration(override: Boolean, overridenType: TypeRefWithNullability? = null, forceNullable: Boolean = false) {
|
||||
println()
|
||||
if (name == "source") {
|
||||
println("@FirImplementationDetail")
|
||||
println("@${firImplementationDetailType.render()}")
|
||||
}
|
||||
abstract()
|
||||
if (override) print("override ")
|
||||
@@ -95,7 +101,7 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
|
||||
allFields.filter { it.withReplace }.forEach {
|
||||
val override = overridenFields[it, it] &&
|
||||
!(it.name == "source" && fullQualifiedName.endsWith("FirQualifiedAccessExpression"))
|
||||
!(it.name == "source" && element == FirTreeBuilder.qualifiedAccessExpression)
|
||||
it.replaceDeclaration(override, forceNullable = it.useNullableForReplace)
|
||||
for (overridenType in it.overridenTypes) {
|
||||
it.replaceDeclaration(true, overridenType)
|
||||
@@ -109,7 +115,7 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
if (field.fromParent && field.parentHasSeparateTransform) {
|
||||
print("override ")
|
||||
}
|
||||
println(field.transformFunctionDeclaration(typeWithArguments))
|
||||
println(field.transformFunctionDeclaration(element))
|
||||
}
|
||||
if (needTransformOtherChildren) {
|
||||
println()
|
||||
@@ -117,7 +123,7 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
if (element.elementParents.any { it.element.needTransformOtherChildren }) {
|
||||
print("override ")
|
||||
}
|
||||
println(transformFunctionDeclaration("OtherChildren", typeWithArguments))
|
||||
println(transformFunctionDeclaration("OtherChildren", element))
|
||||
}
|
||||
|
||||
if (element.isRootElement) {
|
||||
@@ -125,16 +131,16 @@ fun SmartPrinter.printElement(element: Element) {
|
||||
"$element must be an interface"
|
||||
}
|
||||
println()
|
||||
println("fun accept(visitor: FirVisitorVoid) = accept(visitor, null)")
|
||||
println("fun accept(visitor: ${firVisitorVoidType.render()}) = accept(visitor, null)")
|
||||
if (element.hasAcceptChildrenMethod) {
|
||||
println()
|
||||
println("fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D)")
|
||||
println("fun <R, D> acceptChildren(visitor: ${firVisitorType.render()}<R, D>, data: D)")
|
||||
}
|
||||
println()
|
||||
println("fun acceptChildren(visitor: FirVisitorVoid) = acceptChildren(visitor, null)")
|
||||
println("fun acceptChildren(visitor: ${firVisitorVoidType.render()}) = acceptChildren(visitor, null)")
|
||||
if (element.hasTransformChildrenMethod) {
|
||||
println()
|
||||
println("fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement")
|
||||
println("fun <D> transformChildren(transformer: ${firTransformerType.render()}<D>, data: D): FirElement")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -6,11 +6,13 @@
|
||||
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,
|
||||
@@ -27,7 +29,8 @@ fun SmartPrinter.printField(
|
||||
}
|
||||
|
||||
field.optInAnnotation?.let {
|
||||
println(if (inConstructor) "@property:${it.type}" else "@${it.type}")
|
||||
val rendered = it.render()
|
||||
println(if (inConstructor) "@property:$rendered" else "@$rendered")
|
||||
}
|
||||
|
||||
modifiers()
|
||||
@@ -44,17 +47,18 @@ fun SmartPrinter.printField(
|
||||
print("val")
|
||||
}
|
||||
val type = if (isImplementation) field.getMutableType() else field.typeRef
|
||||
print(" ${field.name}: ${type.typeWithArguments}")
|
||||
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.type}::class)")
|
||||
println("@OptIn(${it.render()}::class)")
|
||||
}
|
||||
val defaultValue = field.defaultValueInImplementation
|
||||
print("override ")
|
||||
@@ -63,7 +67,7 @@ fun SmartPrinter.printFieldWithDefaultInImplementation(field: Field) {
|
||||
} else {
|
||||
print("var")
|
||||
}
|
||||
print(" ${field.name}: ${field.getMutableType().typeWithArguments}")
|
||||
print(" ${field.name}: ${field.getMutableType().render()}")
|
||||
if (field.withGetter) {
|
||||
println()
|
||||
pushIndent()
|
||||
|
||||
+50
-28
@@ -5,8 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator.printer
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.*
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.*
|
||||
import org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType
|
||||
import org.jetbrains.kotlin.generators.tree.*
|
||||
import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
|
||||
import org.jetbrains.kotlin.generators.tree.printer.braces
|
||||
@@ -18,15 +18,19 @@ import org.jetbrains.kotlin.utils.withIndent
|
||||
import java.io.File
|
||||
|
||||
fun Implementation.generateCode(generationPath: File): GeneratedFile =
|
||||
printGeneratedType(generationPath, TREE_GENERATOR_README, packageName, type, fileSuppressions = listOf("DuplicatedCode", "unused")) {
|
||||
val imports = collectImports()
|
||||
imports.forEach { println("import $it") }
|
||||
if (imports.isNotEmpty()) {
|
||||
println()
|
||||
}
|
||||
printGeneratedType(
|
||||
generationPath,
|
||||
TREE_GENERATOR_README,
|
||||
packageName,
|
||||
this.typeName,
|
||||
fileSuppressions = listOf("DuplicatedCode", "unused"),
|
||||
) {
|
||||
println()
|
||||
addAllImports(usedTypes)
|
||||
printImplementation(this@generateCode)
|
||||
}
|
||||
|
||||
context(ImportCollector)
|
||||
fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
fun Field.transform() {
|
||||
when (this) {
|
||||
@@ -36,6 +40,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
println("$name = ${name}${call()}transform(transformer, data)")
|
||||
|
||||
is FieldList -> {
|
||||
addImport(transformInPlaceImport)
|
||||
println("${name}.transformInplace(transformer, data)")
|
||||
}
|
||||
|
||||
@@ -46,20 +51,22 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
with(implementation) {
|
||||
buildSet {
|
||||
if (requiresOptIn) {
|
||||
add("FirImplementationDetail")
|
||||
add(firImplementationDetailType)
|
||||
}
|
||||
|
||||
for (field in fieldsWithoutDefault) {
|
||||
field.optInAnnotation?.let { add(it.type) }
|
||||
field.optInAnnotation?.let {
|
||||
add(it)
|
||||
}
|
||||
}
|
||||
}.ifNotEmpty {
|
||||
println("@OptIn(${joinToString { "$it::class" }})")
|
||||
println("@OptIn(${joinToString { "${it.render()}::class" }})")
|
||||
}
|
||||
|
||||
if (!isPublic) {
|
||||
print("internal ")
|
||||
}
|
||||
print("${kind!!.title} $type")
|
||||
print("${kind!!.title} ${this.typeName}")
|
||||
print(element.typeParameters(end = " "))
|
||||
|
||||
val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface
|
||||
@@ -73,13 +80,13 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
|
||||
if (!isInterface && !isAbstract && fieldsWithoutDefault.isNotEmpty()) {
|
||||
if (isPublic) {
|
||||
print(" @FirImplementationDetail constructor")
|
||||
print(" @${firImplementationDetailType.render()} constructor")
|
||||
}
|
||||
println("(")
|
||||
withIndent {
|
||||
fieldsWithoutDefault.forEachIndexed { _, field ->
|
||||
if (field.isParameter) {
|
||||
print("${field.name}: ${field.typeRef.typeWithArguments}")
|
||||
print("${field.name}: ${field.typeRef.render()}")
|
||||
if (field.nullable) print("?")
|
||||
println(",")
|
||||
} else if (!field.isFinal) {
|
||||
@@ -92,9 +99,9 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
|
||||
print(" : ")
|
||||
if (needPureAbstractElement) {
|
||||
print("${pureAbstractElementType.type}(), ")
|
||||
print("${pureAbstractElementType.render()}(), ")
|
||||
}
|
||||
print(allParents.joinToString { "${it.typeWithArguments}${it.kind.braces()}" })
|
||||
print(allParents.joinToString { "${it.render()}${it.kind.braces()}" })
|
||||
println(" {")
|
||||
withIndent {
|
||||
if (isInterface || isAbstract) {
|
||||
@@ -114,13 +121,13 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
|
||||
|
||||
val bindingCalls = element.allFields.filter {
|
||||
it.withBindThis && it.typeRef.type.contains("Symbol") && it !is FieldList && it.name != "companionObjectSymbol"
|
||||
it.withBindThis && it.hasSymbolType && it !is FieldList && it.name != "companionObjectSymbol"
|
||||
}.takeIf {
|
||||
it.isNotEmpty() && !isInterface && !isAbstract &&
|
||||
!element.type.contains("Reference")
|
||||
&& !element.type.contains("ResolvedQualifier")
|
||||
&& !element.type.endsWith("Ref")
|
||||
&& !element.type.endsWith("AnnotationsContainer")
|
||||
!element.typeName.contains("Reference")
|
||||
&& !element.typeName.contains("ResolvedQualifier")
|
||||
&& !element.typeName.endsWith("Ref")
|
||||
&& !element.typeName.endsWith("AnnotationsContainer")
|
||||
}.orEmpty()
|
||||
|
||||
val customCalls = fieldsWithoutDefault.filter { it.customInitializationCall != null }
|
||||
@@ -132,6 +139,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
}
|
||||
|
||||
for (customCall in customCalls) {
|
||||
addAllImports(customCall.arbitraryImportables)
|
||||
println("${customCall.name} = ${customCall.customInitializationCall}")
|
||||
}
|
||||
}
|
||||
@@ -141,7 +149,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
|
||||
fun Field.acceptString(): String = "${name}${call()}accept(visitor, data)"
|
||||
if (hasAcceptChildrenMethod) {
|
||||
print("override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {")
|
||||
print("override fun <R, D> acceptChildren(visitor: ${firVisitorType.render()}<R, D>, data: D) {")
|
||||
|
||||
val walkableFields = walkableChildren
|
||||
if (walkableFields.isNotEmpty()) {
|
||||
@@ -170,7 +178,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (type == "FirWhenExpressionImpl" && field.name == "subject") {
|
||||
if (this.typeName == "FirWhenExpressionImpl" && field.name == "subject") {
|
||||
println(
|
||||
"""
|
||||
|val subjectVariable_ = subjectVariable
|
||||
@@ -206,7 +214,12 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
|
||||
if (hasTransformChildrenMethod) {
|
||||
abstract()
|
||||
print("override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): $typeWithArguments")
|
||||
print(
|
||||
"override fun <D> transformChildren(transformer: ",
|
||||
firTransformerType.render(),
|
||||
"<D>, data: D): ",
|
||||
render(),
|
||||
)
|
||||
if (!isInterface && !isAbstract) {
|
||||
println(" {")
|
||||
withIndent {
|
||||
@@ -269,7 +282,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
if (!field.needsSeparateTransform) continue
|
||||
println()
|
||||
abstract()
|
||||
print("override ${field.transformFunctionDeclaration(typeWithArguments)}")
|
||||
print("override ${field.transformFunctionDeclaration(this)}")
|
||||
if (isInterface || isAbstract) {
|
||||
println()
|
||||
continue
|
||||
@@ -278,7 +291,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
withIndent {
|
||||
if (field.isMutable && field.isFirType) {
|
||||
// TODO: replace with smth normal
|
||||
if (type == "FirWhenExpressionImpl" && field.name == "subject") {
|
||||
if (this.typeName == "FirWhenExpressionImpl" && field.name == "subject") {
|
||||
println(
|
||||
"""
|
||||
|if (subjectVariable != null) {
|
||||
@@ -301,7 +314,12 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
if (element.needTransformOtherChildren) {
|
||||
println()
|
||||
abstract()
|
||||
print("override fun <D> transformOtherChildren(transformer: FirTransformer<D>, data: D): $typeWithArguments")
|
||||
print(
|
||||
"override fun <D> transformOtherChildren(transformer: ",
|
||||
firTransformerType.render(),
|
||||
"<D>, data: D): ",
|
||||
render(),
|
||||
)
|
||||
if (isInterface || isAbstract) {
|
||||
println()
|
||||
} else {
|
||||
@@ -330,7 +348,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
) {
|
||||
println()
|
||||
if (field.name == "source") {
|
||||
println("@FirImplementationDetail")
|
||||
println("@${firImplementationDetailType.render()}")
|
||||
}
|
||||
abstract()
|
||||
print("override ${field.replaceFunctionDeclaration(overridenType, forceNullable)}")
|
||||
@@ -368,6 +386,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
}
|
||||
print("${field.name} = $newValue")
|
||||
if (field.origin is FieldList && field.isMutableOrEmpty) {
|
||||
addImport(toMutableOrEmptyImport)
|
||||
print(".toMutableOrEmpty()")
|
||||
}
|
||||
println()
|
||||
@@ -377,7 +396,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
|
||||
for (overridenType in field.overridenTypes) {
|
||||
generateReplace(field, overridenType) {
|
||||
println("require($newValue is ${field.typeRef.typeWithArguments})")
|
||||
println("require($newValue is ${field.typeRef.render()})")
|
||||
println("replace$capitalizedFieldName($newValue)")
|
||||
}
|
||||
}
|
||||
@@ -386,3 +405,6 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
||||
println("}")
|
||||
}
|
||||
}
|
||||
|
||||
private val Field.hasSymbolType: Boolean
|
||||
get() = (typeRef as? ClassRef<*>)?.simpleName?.contains("Symbol") ?: false
|
||||
|
||||
+21
-5
@@ -11,12 +11,12 @@ import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
|
||||
import org.jetbrains.kotlin.generators.tree.printer.multipleUpperBoundsList
|
||||
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
|
||||
import org.jetbrains.kotlin.generators.tree.printer.typeParameters
|
||||
import org.jetbrains.kotlin.generators.tree.render
|
||||
import org.jetbrains.kotlin.utils.withIndent
|
||||
import java.io.File
|
||||
|
||||
fun printTransformer(elements: List<Element>, generationPath: File): GeneratedFile =
|
||||
printGeneratedType(generationPath, TREE_GENERATOR_README, VISITOR_PACKAGE, "FirTransformer") {
|
||||
elements.forEach { println("import ${it.fullQualifiedName}") }
|
||||
println()
|
||||
println("abstract class FirTransformer<in D> : FirVisitor<FirElement, D>() {")
|
||||
println()
|
||||
@@ -29,8 +29,16 @@ fun printTransformer(elements: List<Element>, generationPath: File): GeneratedFi
|
||||
print("open fun ")
|
||||
element.typeParameters(end = " ").takeIf { it.isNotBlank() }?.let { print(it) }
|
||||
println(
|
||||
"transform${element.name}($varName: ${element.typeWithArguments}, data: D): ${element.transformerType
|
||||
.typeWithArguments}${element.multipleUpperBoundsList()} {",
|
||||
"transform",
|
||||
element.name,
|
||||
"(",
|
||||
varName,
|
||||
": ",
|
||||
element.render(),
|
||||
", data: D): ",
|
||||
element.transformerType.render(),
|
||||
element.multipleUpperBoundsList(),
|
||||
" {",
|
||||
)
|
||||
withIndent {
|
||||
println("return transformElement($varName, data)")
|
||||
@@ -45,8 +53,16 @@ fun printTransformer(elements: List<Element>, generationPath: File): GeneratedFi
|
||||
element.typeParameters(end = " ").takeIf { it.isNotBlank() }?.let { print(it) }
|
||||
|
||||
println(
|
||||
"visit${element.name}($varName: ${element.typeWithArguments}, data: D): ${element.transformerType
|
||||
.typeWithArguments}${element.multipleUpperBoundsList()} {",
|
||||
"visit",
|
||||
element.name,
|
||||
"(",
|
||||
varName,
|
||||
": ",
|
||||
element.render(),
|
||||
", data: D): ",
|
||||
element.transformerType.render(),
|
||||
element.multipleUpperBoundsList(),
|
||||
" {"
|
||||
)
|
||||
withIndent {
|
||||
println("return transform${element.name}($varName, data)")
|
||||
|
||||
+13
-112
@@ -5,129 +5,33 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.tree.generator.printer
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder
|
||||
import org.jetbrains.kotlin.fir.tree.generator.firImplementationDetailType
|
||||
import org.jetbrains.kotlin.fir.tree.generator.firTransformerType
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.*
|
||||
import org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType
|
||||
import org.jetbrains.kotlin.generators.tree.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
enum class ImportKind(val postfix: String) {
|
||||
Element(""), Implementation(".impl"), Builder(".builder")
|
||||
}
|
||||
|
||||
fun Builder.collectImports(): List<String> {
|
||||
val parents = parents.mapNotNull { it.fullQualifiedName }
|
||||
val builderDsl = "org.jetbrains.kotlin.fir.builder.FirBuilderDsl"
|
||||
return when (this) {
|
||||
is LeafBuilder -> implementation.collectImports(
|
||||
parents,
|
||||
ImportKind.Builder,
|
||||
) + implementation.fullQualifiedName!! + usedTypes.mapNotNull { it.fullQualifiedName } + builderDsl + "kotlin.contracts.*"
|
||||
is IntermediateBuilder -> {
|
||||
val fqns = buildList {
|
||||
addAll(parents)
|
||||
usedTypes.mapNotNullTo(this) { it.fullQualifiedName }
|
||||
for (field in allFields) {
|
||||
if (field.invisibleField) continue
|
||||
// TODO: Use recursive import collection for TypeRefs
|
||||
field.typeRef.fullQualifiedName?.let(this::add)
|
||||
(field.typeRef as? ParametrizedTypeRef<*, *>)?.args?.values?.mapNotNullTo(this) { it.fullQualifiedName }
|
||||
}
|
||||
|
||||
add(materializedElement?.fullQualifiedName ?: throw IllegalStateException(type))
|
||||
add(builderDsl)
|
||||
}
|
||||
|
||||
fqns.filterRedundantImports(packageName, ImportKind.Builder)
|
||||
}
|
||||
}.sorted()
|
||||
}
|
||||
|
||||
fun Implementation.collectImports(base: List<String> = emptyList(), kind: ImportKind = ImportKind.Implementation): List<String> {
|
||||
return element.collectImportsInternal(
|
||||
base + listOf(element.fullQualifiedName)
|
||||
+ usedTypes.mapNotNull { it.fullQualifiedName }
|
||||
+ arbitraryImportables.mapNotNull { it.fullQualifiedName }
|
||||
+ parents.mapNotNull { it.fullQualifiedName }
|
||||
+ listOfNotNull(
|
||||
pureAbstractElementType.fullQualifiedName.takeIf { needPureAbstractElement },
|
||||
firImplementationDetailType.fullQualifiedName.takeIf { isPublic || requiresOptIn },
|
||||
),
|
||||
kind,
|
||||
)
|
||||
}
|
||||
|
||||
fun Element.collectImports(): List<String> {
|
||||
val baseTypes = elementParents.mapTo(mutableListOf()) { it.fullQualifiedName!! }
|
||||
baseTypes += AbstractFirTreeBuilder.baseFirElement.fullQualifiedName
|
||||
baseTypes += elementParents.flatMap { it.args.values }.mapNotNull { it.fullQualifiedName } // TODO: Use recursive import collection for TypeRefs
|
||||
if (needPureAbstractElement) {
|
||||
baseTypes += pureAbstractElementType.fullQualifiedName
|
||||
}
|
||||
baseTypes.addAll(otherParents.map { it.fullQualifiedName })
|
||||
return collectImportsInternal(
|
||||
baseTypes,
|
||||
ImportKind.Element,
|
||||
)
|
||||
}
|
||||
|
||||
private fun Element.collectImportsInternal(base: List<String>, kind: ImportKind): List<String> {
|
||||
val fqns = base + allFields.mapNotNull { it.typeRef.fullQualifiedName } +
|
||||
allFields.flatMap { it.overridenTypes.mapNotNull { it.fullQualifiedName } + it.arbitraryImportables.mapNotNull { it.fullQualifiedName } } +
|
||||
allFields.flatMap { (it.typeRef as? ParametrizedTypeRef<*, *>)?.args?.values?.mapNotNull { it.fullQualifiedName } ?: emptyList() } + // TODO: Use recursive import collection for TypeRefs
|
||||
params.flatMap { it.bounds.mapNotNull { it.fullQualifiedName } }
|
||||
val result = fqns.filterRedundantImports(packageName, kind).toMutableList()
|
||||
|
||||
if (allFields.any { it is FieldList && it.isMutableOrEmpty }) {
|
||||
result += when (kind) {
|
||||
ImportKind.Implementation -> listOf(
|
||||
"org.jetbrains.kotlin.fir.MutableOrEmptyList",
|
||||
"org.jetbrains.kotlin.fir.builder.toMutableOrEmpty"
|
||||
)
|
||||
ImportKind.Builder -> listOf("org.jetbrains.kotlin.fir.builder.toMutableOrEmpty")
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
allFields.mapNotNull { it.optInAnnotation?.fullQualifiedName }.distinct().ifNotEmpty {
|
||||
result += this
|
||||
}
|
||||
|
||||
if (allFields.any { it.name == "source" && it.withReplace }) {
|
||||
return (result + "org.jetbrains.kotlin.fir.FirImplementationDetail").distinct()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun List<String>.filterRedundantImports(
|
||||
packageName: String,
|
||||
kind: ImportKind,
|
||||
): List<String> {
|
||||
val realPackageName = "$packageName.${kind.postfix}"
|
||||
return filter { fqn ->
|
||||
!fqn.startsWith("kotlin.") && fqn.dropLastWhile { it != '.' } != realPackageName
|
||||
}.distinct().sorted() + "$VISITOR_PACKAGE.*"
|
||||
}
|
||||
|
||||
|
||||
val Field.isVal: Boolean
|
||||
get() = (this is FieldList && !isMutableOrEmpty) || (this is FieldWithDefault && origin is FieldList && !origin.isMutableOrEmpty) || !isMutable
|
||||
|
||||
|
||||
fun Field.transformFunctionDeclaration(returnType: String): String {
|
||||
context(ImportCollector)
|
||||
fun Field.transformFunctionDeclaration(returnType: TypeRef): String {
|
||||
return transformFunctionDeclaration(name.replaceFirstChar(Char::uppercaseChar), returnType)
|
||||
}
|
||||
|
||||
fun transformFunctionDeclaration(transformName: String, returnType: String): String {
|
||||
return "fun <D> transform$transformName(transformer: FirTransformer<D>, data: D): $returnType"
|
||||
context(ImportCollector)
|
||||
fun transformFunctionDeclaration(transformName: String, returnType: TypeRef): String {
|
||||
return "fun <D> transform$transformName(transformer: ${firTransformerType.render()}<D>, data: D): " +
|
||||
returnType.render()
|
||||
}
|
||||
|
||||
fun Field.replaceFunctionDeclaration(overridenType: TypeRefWithNullability? = null, forceNullable: Boolean = false): String {
|
||||
context(ImportCollector)
|
||||
fun Field.replaceFunctionDeclaration(
|
||||
overridenType: TypeRefWithNullability? = null,
|
||||
forceNullable: Boolean = false,
|
||||
): String {
|
||||
val capName = name.replaceFirstChar(Char::uppercaseChar)
|
||||
val type = overridenType ?: typeRef
|
||||
val typeWithNullable = if (forceNullable) type.copy(nullable = true) else type
|
||||
return "fun replace$capName(new$capName: ${typeWithNullable.typeWithArguments})"
|
||||
return "fun replace$capName(new$capName: ${typeWithNullable.render()})"
|
||||
}
|
||||
|
||||
fun Field.getMutableType(forBuilder: Boolean = false): TypeRef = when (this) {
|
||||
@@ -143,6 +47,3 @@ fun Field.getMutableType(forBuilder: Boolean = false): TypeRef = when (this) {
|
||||
fun Field.call(): String = if (nullable) "?." else "."
|
||||
|
||||
val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" else name.replaceFirstChar(Char::lowercaseChar)
|
||||
|
||||
val ImplementationWithArg.generics: String
|
||||
get() = argument?.let { "<${it.type}>" } ?: ""
|
||||
|
||||
+57
-7
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
|
||||
import org.jetbrains.kotlin.generators.tree.printer.multipleUpperBoundsList
|
||||
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
|
||||
import org.jetbrains.kotlin.generators.tree.printer.typeParameters
|
||||
import org.jetbrains.kotlin.generators.tree.render
|
||||
import org.jetbrains.kotlin.utils.withIndent
|
||||
import java.io.File
|
||||
|
||||
@@ -34,7 +35,6 @@ private fun Element.getNameOfSupertypeForDefaultVisiting(): String {
|
||||
fun printVisitor(elements: List<Element>, generationPath: File, visitSuperTypeByDefault: Boolean): GeneratedFile {
|
||||
val className = if (visitSuperTypeByDefault) "FirDefaultVisitor" else "FirVisitor"
|
||||
return printGeneratedType(generationPath, TREE_GENERATOR_README, VISITOR_PACKAGE, className) {
|
||||
elements.forEach { println("import ${it.fullQualifiedName}") }
|
||||
println()
|
||||
|
||||
print("abstract class $className<out R, in D> ")
|
||||
@@ -57,7 +57,19 @@ fun printVisitor(elements: List<Element>, generationPath: File, visitSuperTypeBy
|
||||
} else {
|
||||
print("open")
|
||||
}
|
||||
print(" fun ${typeParameters(end = " ")}visit$name($varName: $typeWithArguments, data: D): R${multipleUpperBoundsList()} = visit")
|
||||
print(
|
||||
" fun ",
|
||||
typeParameters(end = " "),
|
||||
"visit",
|
||||
name,
|
||||
"(",
|
||||
varName,
|
||||
": ",
|
||||
render(),
|
||||
", data: D): R",
|
||||
multipleUpperBoundsList(),
|
||||
" = visit"
|
||||
)
|
||||
if (visitSuperTypeByDefault) {
|
||||
print(element.getNameOfSupertypeForDefaultVisiting())
|
||||
} else {
|
||||
@@ -75,7 +87,6 @@ fun printVisitor(elements: List<Element>, generationPath: File, visitSuperTypeBy
|
||||
|
||||
fun printVisitorVoid(elements: List<Element>, generationPath: File): GeneratedFile =
|
||||
printGeneratedType(generationPath, TREE_GENERATOR_README, VISITOR_PACKAGE, "FirVisitorVoid") {
|
||||
elements.forEach { println("import ${it.fullQualifiedName}") }
|
||||
println()
|
||||
println("abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {")
|
||||
|
||||
@@ -86,7 +97,19 @@ fun printVisitorVoid(elements: List<Element>, generationPath: File): GeneratedFi
|
||||
if (element == AbstractFirTreeBuilder.baseFirElement) continue
|
||||
with(element) {
|
||||
val varName = safeDecapitalizedName
|
||||
println("open fun ${typeParameters(end = " ")}visit$name($varName: $typeWithArguments)${multipleUpperBoundsList()} {")
|
||||
println(
|
||||
"open fun ",
|
||||
typeParameters(end = " "),
|
||||
"visit",
|
||||
name,
|
||||
"(",
|
||||
varName,
|
||||
": ",
|
||||
render(),
|
||||
")",
|
||||
multipleUpperBoundsList(),
|
||||
" {"
|
||||
)
|
||||
withIndent {
|
||||
println("visitElement($varName)")
|
||||
}
|
||||
@@ -98,7 +121,19 @@ fun printVisitorVoid(elements: List<Element>, generationPath: File): GeneratedFi
|
||||
for (element in elements) {
|
||||
with(element) {
|
||||
val varName = safeDecapitalizedName
|
||||
println("final override fun ${typeParameters(end = " ")}visit$name($varName: $typeWithArguments, data: Nothing?)${multipleUpperBoundsList()} {")
|
||||
println(
|
||||
"final override fun ",
|
||||
typeParameters(end = " "),
|
||||
"visit",
|
||||
name,
|
||||
"(",
|
||||
varName,
|
||||
": ",
|
||||
render(),
|
||||
", data: Nothing?)",
|
||||
multipleUpperBoundsList(),
|
||||
" {"
|
||||
)
|
||||
withIndent {
|
||||
println("visit$name($varName)")
|
||||
}
|
||||
@@ -112,7 +147,6 @@ fun printVisitorVoid(elements: List<Element>, generationPath: File): GeneratedFi
|
||||
|
||||
fun printDefaultVisitorVoid(elements: List<Element>, generationPath: File): GeneratedFile =
|
||||
printGeneratedType(generationPath, TREE_GENERATOR_README, VISITOR_PACKAGE, "FirDefaultVisitorVoid") {
|
||||
elements.forEach { println("import ${it.fullQualifiedName}") }
|
||||
println()
|
||||
println("abstract class FirDefaultVisitorVoid : FirVisitorVoid() {")
|
||||
|
||||
@@ -121,7 +155,23 @@ fun printDefaultVisitorVoid(elements: List<Element>, generationPath: File): Gene
|
||||
if (!element.isAcceptableForDefaultVisiting()) continue
|
||||
with(element) {
|
||||
val varName = safeDecapitalizedName
|
||||
println("override fun ${typeParameters(end = " ")}visit$name($varName: $typeWithArguments)${multipleUpperBoundsList()} = visit${element.getNameOfSupertypeForDefaultVisiting()}($varName)")
|
||||
println(
|
||||
"override fun ",
|
||||
typeParameters(end = " "),
|
||||
"visit",
|
||||
name,
|
||||
"(",
|
||||
varName,
|
||||
": ",
|
||||
render(),
|
||||
")",
|
||||
multipleUpperBoundsList(),
|
||||
" = visit",
|
||||
getNameOfSupertypeForDefaultVisiting(),
|
||||
"(",
|
||||
varName,
|
||||
")"
|
||||
)
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -33,13 +33,13 @@ fun printHierarchyGraph(builder: AbstractFirTreeBuilder) {
|
||||
with(printer) {
|
||||
println("digraph FirTree {")
|
||||
elements.forEach {
|
||||
println(" ${it.type} [color=${it.kind!!.toColor()}]")
|
||||
println(" ${it.typeName} [color=${it.kind!!.toColor()}]")
|
||||
}
|
||||
println()
|
||||
val edges = mutableSetOf<Edge>()
|
||||
elements.forEach { element ->
|
||||
element.allParents.forEach { parent ->
|
||||
edges += Edge(parent.type, element.type)
|
||||
edges += Edge(parent.typeName, element.typeName)
|
||||
}
|
||||
}
|
||||
edges.forEach {
|
||||
|
||||
Reference in New Issue
Block a user