[FIR] Implement builders for leaf nodes of FIR tree

This commit is contained in:
Dmitriy Novozhilov
2020-01-31 14:00:12 +03:00
parent b0c1387279
commit d57fa859c8
319 changed files with 11298 additions and 4284 deletions
@@ -3,6 +3,7 @@ import tasks.WriteCopyrightToFile
plugins {
kotlin("jvm")
id("jps-compatible")
application
}
val runtimeOnly by configurations
@@ -32,6 +33,10 @@ val writeCopyright by task<WriteCopyrightToFile> {
commented = true
}
application {
mainClassName = "org.jetbrains.kotlin.fir.tree.generator.MainKt"
}
val processResources by tasks
processResources.dependsOn(writeCopyright)
@@ -0,0 +1,335 @@
/*
* Copyright 2010-2020 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
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractBuilderConfigurator
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeImplementationConfigurator
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.model.Implementation
import org.jetbrains.kotlin.fir.tree.generator.model.LeafBuilder
import org.jetbrains.kotlin.fir.tree.generator.util.traverseParents
object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTreeBuilder) {
fun configureBuilders() = with(firTreeBuilder) {
val annotationContainerBuilder by builder {
fields from annotationContainer
}
val expressionBuilder by builder {
fields from expression
}
val typeParametersOwnerBuilder by builder {
fields from typeParametersOwner
}
val classBuilder by builder {
parents += annotationContainerBuilder
fields from klass without listOf("symbol", "resolvePhase")
}
val regularClassBuilder by builder("AbstractFirRegularClassBuilder") {
parents += classBuilder
parents += typeParametersOwnerBuilder
fields from regularClass
}
val qualifiedAccessBuilder by builder {
fields from qualifiedAccess without "calleeReference"
}
val callBuilder by builder {
fields from call
}
val loopBuilder by builder {
fields from loop
}
val functionBuilder by builder {
parents += annotationContainerBuilder
fields from function without listOf("symbol", "resolvePhase", "controlFlowGraphReference", "receiverTypeRef")
}
val loopJumpBuilder by builder {
fields from loopJump without "typeRef"
}
val abstractConstructorBuilder by builder {
parents += functionBuilder
fields from constructor without "isPrimary"
}
for (constructorType in listOf("FirPrimaryConstructor", "FirConstructorImpl")) {
builder(constructor, constructorType) {
parents += abstractConstructorBuilder
defaultNull("delegatedConstructor")
defaultNull("body")
}
}
builder(constructor, "FirConstructorImpl") {
openBuilder()
}
builder(field) {
default("resolvePhase", "FirResolvePhase.DECLARATIONS")
openBuilder()
}
builder(regularClass) {
parents += regularClassBuilder
defaultNull("companionObject")
openBuilder()
}
builder(sealedClass) {
parents += regularClassBuilder
defaultNull("companionObject")
}
builder(anonymousObject) {
parents += classBuilder
}
builder(typeAlias) {
parents += typeParametersOwnerBuilder
}
builder(annotationCall) {
parents += callBuilder
}
builder(arrayOfCall) {
parents += callBuilder
}
builder(arraySetCall) {
parents += qualifiedAccessBuilder
defaultFalse("safe")
defaultNoReceivers()
}
builder(callableReferenceAccess) {
parents += qualifiedAccessBuilder
defaultNull("explicitReceiver")
defaultNoReceivers()
defaultFalse("safe")
}
builder(componentCall) {
parents += callBuilder
}
builder(whileLoop) {
parents += loopBuilder
defaultNull("label")
}
builder(doWhileLoop) {
parents += loopBuilder
defaultNull("label")
}
builder(errorLoop) {
defaultNull("label")
}
builder(delegatedConstructorCall) {
parents += callBuilder
}
builder(functionCall) {
parents += qualifiedAccessBuilder
parents += callBuilder
defaultFalse("safe")
defaultNoReceivers()
openBuilder()
}
builder(qualifiedAccessExpression) {
parents += qualifiedAccessBuilder
defaultFalse("safe")
defaultNoReceivers()
}
builder(getClassCall) {
parents += callBuilder
}
builder(property) {
parents += typeParametersOwnerBuilder
defaultNull("getter", "setter", "containerSource", "delegateFieldSymbol")
default("resolvePhase", "FirResolvePhase.RAW_FIR")
}
builder(operatorCall) {
parents += callBuilder
}
builder(typeOperatorCall) {
parents += callBuilder
}
builder(stringConcatenationCall) {
parents += callBuilder
}
builder(thisReceiverExpression) {
parents += qualifiedAccessBuilder
}
builder(variableAssignment) {
parents += qualifiedAccessBuilder
defaultNoReceivers()
}
builder(anonymousFunction) {
parents += functionBuilder
defaultNull("invocationKind", "label", "body")
default("controlFlowGraphReference", "FirEmptyControlFlowGraphReference")
useTypes(emptyCfgReferenceType)
}
builder(propertyAccessor) {
parents += functionBuilder
defaultNull("body")
}
builder(whenExpression) {
defaultFalse("isExhaustive")
default("calleeReference", "FirStubReference")
useTypes(stubReferenceType)
}
builder(resolvedTypeRef) {
defaultNull("delegatedTypeRef")
}
builder(breakExpression) {
parents += loopJumpBuilder
}
builder(continueExpression) {
parents += loopJumpBuilder
}
builder(valueParameter, type = "FirValueParameterImpl") {
openBuilder()
}
builder(valueParameter, type = "FirDefaultSetterValueParameter") {
defaultNull("defaultValue", "initializer", "delegate", "receiverTypeRef", "delegateFieldSymbol", "getter", "setter")
defaultFalse("isCrossinline", "isNoinline", "isVararg", "isVar")
defaultTrue("isVal")
}
builder(simpleFunction) {
parents += functionBuilder
parents += typeParametersOwnerBuilder
defaultNull("body")
openBuilder()
}
builder(tryExpression) {
default("calleeReference", "FirStubReference")
useTypes(stubReferenceType)
}
builder(checkNotNullCall) {
default("calleeReference", "FirStubReference")
useTypes(stubReferenceType)
}
val elementsWithDefaultTypeRef = listOf(
thisReceiverExpression,
callableReferenceAccess,
anonymousObject,
qualifiedAccessExpression,
functionCall,
anonymousFunction,
whenExpression,
tryExpression,
checkNotNullCall,
resolvedQualifier,
resolvedReifiedParameterReference,
expression to "FirExpressionStub",
varargArgumentsExpression
)
elementsWithDefaultTypeRef.forEach {
val (element, name) = when (it) {
is Pair<*, *> -> it.first as Element to it.second as String
is Element -> it to null
else -> throw IllegalArgumentException()
}
builder(element, name) {
default("typeRef", "FirImplicitTypeRefImpl(null)")
useTypes(implicitTypeRefType)
}
}
noBuilder(constExpression)
// -----------------------------------------------------------------------
findImplementationsWithElementInParents(annotationContainer) {
it.type !in setOf("FirDelegatedTypeRefImpl", "FirImplicitTypeRefImpl")
}.forEach {
it.builder?.parents?.add(annotationContainerBuilder)
}
findImplementationsWithElementInParents(expression).forEach {
it.builder?.parents?.add(expressionBuilder)
}
configureFieldInAllLeafBuilders(
field = "resolvePhase",
fieldPredicate = { it.defaultValueInImplementation == null }
) {
default(it, "FirResolvePhase.RAW_FIR")
}
configureFieldInAllLeafBuilders(
field = "containerSource"
) {
defaultNull(it)
}
}
private inline fun findImplementationsWithElementInParents(
element: Element,
implementationPredicate: (Implementation) -> Boolean = { true }
): Collection<Implementation> {
return FirTreeBuilder.elements.flatMap { it.allImplementations }.mapNotNullTo(mutableSetOf()) {
if (!implementationPredicate(it)) return@mapNotNullTo null
var hasAnnotations = false
if (it.element == element) return@mapNotNullTo null
it.element.traverseParents {
if (it == element) {
hasAnnotations = true
}
}
it.takeIf { hasAnnotations }
}
}
private fun configureFieldInAllLeafBuilders(
field: String,
builderPredicate: ((LeafBuilder) -> Boolean)? = null,
fieldPredicate: ((Field) -> Boolean)? = null,
init: LeafBuilderConfigurationContext.(field: String) -> Unit
) {
val builders = FirTreeBuilder.elements.flatMap { it.allImplementations }.mapNotNull { it.builder }
for (builder in builders) {
if (builderPredicate != null && !builderPredicate(builder)) continue
if (!builder.allFields.any { it.name == field }) continue
if (fieldPredicate != null && !fieldPredicate(builder[field])) continue
LeafBuilderConfigurationContext(builder).init(field)
}
}
}
@@ -32,21 +32,23 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
impl(constructor) {
kind = OpenClass
parents += modifiableConstructor
defaultNull("delegatedConstructor")
defaultNull("body")
default("isPrimary") {
value = "false"
withGetter = true
}
defaultFalse("isPrimary", withGetter = true)
default("typeParameters") {
needAcceptAndTransform = false
}
}
impl(constructor, "FirPrimaryConstructor") {
parents += modifiableConstructor
defaultTrue("isPrimary", withGetter = true)
default("typeParameters") {
needAcceptAndTransform = false
}
}
noImpl(declarationStatus)
noImpl(resolvedDeclarationStatus)
@@ -59,8 +61,9 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
val regularClassConfig: ImplementationContext.() -> Unit = {
parents += modifiableRegularClass
defaultNull("companionObject")
defaultFalse("hasLazyNestedClassifiers", withGetter = true)
}
impl(regularClass, "FirClassImpl", regularClassConfig)
impl(sealedClass, config = regularClassConfig)
@@ -69,7 +72,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
parents += modifiableClass.withArg(anonymousObject)
}
impl(typeAlias) {
parents += modifiableTypeParametersOwner
}
@@ -100,14 +102,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
}
impl(breakExpression) {
lateinit("target")
}
impl(continueExpression) {
lateinit("target")
}
impl(annotationCall) {
parents += callWithArgumentList
default("typeRef") {
@@ -126,7 +120,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(arraySetCall) {
parents += modifiableQualifiedAccess
lateinit("calleeReference")
default("arguments") {
value = "indexes + rValue"
withGetter = true
@@ -135,16 +128,10 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
value = "calleeReference"
customSetter = "calleeReference = value"
}
default("safe", "false")
defaultNoReceivers()
}
impl(callableReferenceAccess) {
parents += modifiableQualifiedAccess
defaultNull("explicitReceiver")
default("safe", "false")
defaultNoReceivers()
lateinit("calleeReference")
}
impl(componentCall) {
@@ -161,20 +148,17 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
default("calleeReference", "FirSimpleNamedReference(source, Name.identifier(\"component\$componentIndex\"), null)")
useTypes(simpleNamedReferenceType, nameType, noReceiverExpressionType)
optInToInternals()
}
val abstractLoop = impl(loop, "FirAbstractLoop")
impl(whileLoop) {
parents += abstractLoop
defaultNull("label")
lateinit("block")
}
impl(doWhileLoop) {
parents += abstractLoop
defaultNull("label")
lateinit("block")
}
impl(delegatedConstructorCall) {
@@ -190,46 +174,41 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
useTypes(explicitThisReferenceType, explicitSuperReferenceType)
}
impl(expression, "FirElseIfTrueCondition") {
val elseIfTrueCondition = impl(expression, "FirElseIfTrueCondition") {
default("typeRef", "FirImplicitBooleanTypeRef(source)")
useTypes(implicitBooleanTypeRefType)
publicImplementation()
}
impl(block)
val emptyExpressionBlock = impl(block, "FirEmptyExpressionBlock") {
noSource()
defaultEmptyList("statements")
defaultEmptyList("annotations")
publicImplementation()
}
impl(errorLoop) {
default("block", "FirEmptyExpressionBlock()")
default("condition", "FirErrorExpressionImpl(source, diagnostic)")
defaultNull("label")
useTypes(emptyExpressionBlock)
}
impl(expression, "FirExpressionStub")
impl(expression, "FirExpressionStub") {
publicImplementation()
}
impl(functionCall) {
parents += modifiableQualifiedAccess
parents += callWithArgumentList
defaultFalse("safe")
lateinit("calleeReference")
defaultNoReceivers()
kind = OpenClass
}
impl(qualifiedAccessExpression) {
parents += modifiableQualifiedAccess
defaultFalse("safe")
lateinit("calleeReference")
defaultNoReceivers()
}
impl(checkNotNullCall) {
default("calleeReference", "FirStubReference()")
useTypes(stubReferenceType)
}
noImpl(expressionWithSmartcast)
@@ -252,11 +231,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
default("backingFieldSymbol", "FirBackingFieldSymbol(symbol.callableId)")
default("delegateFieldSymbol", "delegate?.let { FirDelegateFieldSymbol(symbol.callableId) }")
defaultNull("getter", "setter")
default("resolvePhase") {
value = "if (isLocal) FirResolvePhase.DECLARATIONS else FirResolvePhase.RAW_FIR"
}
useTypes(backingFieldSymbolType, delegateFieldSymbolType)
}
@@ -266,10 +240,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
withGetter = true
}
default("resolvePhase") {
value = "FirResolvePhase.DECLARATIONS"
}
defaultNull("delegateFieldSymbol", "receiverTypeRef", "initializer", "delegate", "getter", "setter", withGetter = true)
}
@@ -337,7 +307,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(resolvedReifiedParameterReference)
impl(returnExpression) {
lateinit("target")
default("typeRef", "FirImplicitNothingTypeRef(source)")
useTypes(implicitNothingTypeRefType)
}
@@ -362,20 +331,14 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
defaultNoReceivers()
}
impl(tryExpression) {
default("calleeReference", "FirStubReference()")
useTypes(stubReferenceType)
}
impl(expression, "FirUnitExpression") {
default("typeRef", "FirImplicitUnitTypeRef(source)")
useTypes(implicitUnitTypeRefType)
publicImplementation()
}
impl(variableAssignment) {
parents += modifiableQualifiedAccess
lateinit("calleeReference")
defaultNoReceivers()
default("lValue") {
value = "calleeReference"
@@ -387,7 +350,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(anonymousFunction) {
parents += modifiableFunction.withArg(anonymousFunction)
defaultNull("invocationKind", "label", "body")
default("resolvePhase", "FirResolvePhase.DECLARATIONS")
}
@@ -401,18 +363,11 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
value = "!isGetter"
withGetter = true
}
defaultNull("body")
default("contractDescription", "FirEmptyContractDescription")
useTypes(modalityType, emptyContractDescriptionType)
kind = OpenClass
}
impl(whenExpression) {
default("calleeReference", "FirStubReference()")
defaultFalse("isExhaustive")
useTypes(stubReferenceType)
}
impl(whenSubjectExpression) {
default("typeRef") {
value = "whenSubject.whenExpression.subject!!.typeRef"
@@ -421,7 +376,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
impl(wrappedDelegateExpression) {
lateinit("delegateProvider")
default("typeRef") {
delegate = "expression"
}
@@ -433,6 +387,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(resolvedNamedReference, "FirPropertyFromParameterResolvedNamedReference") {
defaultNull("candidateSymbol", withGetter = true)
publicImplementation()
}
impl(resolvedCallableReference) {
@@ -479,13 +434,10 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(controlFlowGraphReference, "FirEmptyControlFlowGraphReference") {
noSource()
kind = Object
}
impl(resolvedTypeRef) {
default("delegatedTypeRef") {
value = "null"
}
}
impl(resolvedTypeRef)
val errorTypeRefImpl = impl(errorTypeRef) {
default("type", "ConeClassErrorType(diagnostic.reason)")
@@ -493,9 +445,16 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
value = "null"
withGetter = true
}
default("annotations", "mutableListOf()")
useTypes(coneClassErrorTypeType)
}
impl(errorExpression) {
defaultEmptyList("annotations")
default("typeRef", "FirErrorTypeRefImpl(source, diagnostic)")
useTypes(errorTypeRefImpl)
}
impl(resolvedFunctionTypeRef) {
default("delegatedTypeRef") {
value = "null"
@@ -521,6 +480,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
value = "null"
withGetter = true
}
kind = Object
}
impl(errorNamedReference) {
@@ -533,9 +493,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
noSource()
}
val abstractLoopJump = impl(loopJump, "FirAbstractLoopJump") {
lateinit("target")
}
val abstractLoopJump = impl(loopJump, "FirAbstractLoopJump") {}
impl(breakExpression) {
parents += abstractLoopJump
@@ -552,23 +510,19 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(valueParameter) {
kind = OpenClass
parents += modifiableVariable.withArg(valueParameter)
defaultTrue("isVal", true)
defaultTrue("isVal", withGetter = true)
defaultFalse("isVar", withGetter = true)
defaultNull("getter", "setter", "initializer", "delegate", "receiverTypeRef", "delegateFieldSymbol", withGetter = true)
}
impl(valueParameter, "FirDefaultSetterValueParameter") {
default("name", "Name.identifier(\"value\")")
defaultNull("defaultValue", "initializer", "delegate", "receiverTypeRef", "delegateFieldSymbol", "getter", "setter")
defaultFalse("isCrossinline", "isNoinline", "isVararg", "isVar")
defaultTrue("isVal")
}
impl(simpleFunction) {
kind = OpenClass
parents += modifiableFunction.withArg(simpleFunction)
parents += modifiableTypeParametersOwner
defaultNull("body")
default("contractDescription", "FirEmptyContractDescription")
useTypes(emptyContractDescriptionType)
}
@@ -582,67 +536,41 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
noImpl(userTypeRef)
// impl(delegatedConstructorCall) {
// defaultTrue("safe", withGetter = true)
// listOf("dispatchReceiver", "extensionReceiver", "explicitReceiver").forEach {
// default(it) {
// value = "FirNoReceiverExpression"
// withGetter = true
// }
// }
// }
}
private fun findImplementationsWithAnnotations(implementationPredicate: (Implementation) -> Boolean): Collection<Implementation> {
return FirTreeBuilder.elements.flatMap { it.allImplementations }.mapNotNullTo(mutableSetOf()) {
if (!implementationPredicate(it)) return@mapNotNullTo null
var hasAnnotations = false
if (it.element == FirTreeBuilder.annotationContainer) return@mapNotNullTo null
it.element.traverseParents {
if (it == FirTreeBuilder.annotationContainer) {
hasAnnotations = true
}
}
it.takeIf { hasAnnotations }
}
}
private fun configureAllImplementations() {
configureFieldInAllImplementations("controlFlowGraphReference") {
default(it, "FirEmptyControlFlowGraphReference()")
configureFieldInAllImplementations(
field = "controlFlowGraphReference",
implementationPredicate = { it.type != "FirAnonymousFunctionImpl"}
) {
default(it, "FirEmptyControlFlowGraphReference")
useTypes(emptyCfgReferenceType)
}
val implementationWithConfigurableTypeRef = listOf(
"FirDelegatedTypeRefImpl",
"FirTypeProjectionWithVarianceImpl",
"FirCallableReferenceAccessImpl",
"FirThisReceiverExpressionImpl",
"FirAnonymousObjectImpl",
"FirQualifiedAccessExpressionImpl",
"FirFunctionCallImpl",
"FirAnonymousFunctionImpl",
"FirWhenExpressionImpl",
"FirTryExpressionImpl",
"FirCheckNotNullCallImpl",
"FirResolvedQualifierImpl",
"FirResolvedReifiedParameterReferenceImpl",
"FirExpressionStub",
"FirVarargArgumentsExpressionImpl",
)
configureFieldInAllImplementations(
field = "typeRef",
implementationPredicate = { it.type !in listOf("FirDelegatedTypeRefImpl", "FirTypeProjectionWithVarianceImpl") },
fieldPredicate = { it.defaultValue == null }
implementationPredicate = { it.type !in implementationWithConfigurableTypeRef },
fieldPredicate = { it.defaultValueInImplementation == null }
) {
default(it, "FirImplicitTypeRefImpl(null)")
useTypes(implicitTypeRefType)
}
configureFieldInAllImplementations(
field = "resolvePhase",
fieldPredicate = { it.defaultValue == null }
) {
default(it, "FirResolvePhase.RAW_FIR")
}
configureFieldInAllImplementations(
field = "containerSource"
) {
default(it) {
value = "null"
isMutable = true
}
}
findImplementationsWithAnnotations {
it.type !in setOf("FirDelegatedTypeRefImpl", "FirImplicitTypeRefImpl")
}.forEach {
it.addParent(abstractAnnotatedElement)
}
}
}
@@ -11,15 +11,19 @@ import java.io.File
fun main(args: Array<String>) {
val generationPath = args.firstOrNull()?.let { File(it) }
?: File("compiler/fir/tree/gen").absoluteFile
// val generationPath = args.firstOrNull()?.let { File(it) }
// ?: File("/home/demiurg/Programming/kotlin/kotlin/compiler/fir/tree/gen").absoluteFile
val generationPath = File("/home/demiurg/Programming/kotlin/kotlin/compiler/fir/tree/gen").absoluteFile
NodeConfigurator.configureFields()
detectBaseTransformerTypes(FirTreeBuilder)
ImplementationConfigurator.configureImplementations()
configureInterfacesAndAbstractClasses(FirTreeBuilder)
BuilderConfigurator.configureBuilders()
removePreviousGeneratedFiles(generationPath)
printElements(FirTreeBuilder, generationPath)
// printFieldUsageTable(FirTreeBuilder)
// printHierarchyGraph(FirTreeBuilder)
}
// FirTreeBuilder.constExpression.fields.first()
@@ -218,6 +218,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+name
+symbol("FirRegularClassSymbol")
+field("companionObject", regularClass, nullable = true)
+booleanField("hasLazyNestedClassifiers")
+superTypeRefs(withReplace = true)
}
@@ -267,7 +268,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
}
contractDescriptionOwner.configure {
+field(contractDescription).withTransform()
+field(contractDescription, withReplace = true).withTransform()
}
property.configure {
@@ -431,7 +432,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+field("packageFqName", fqNameType)
+field("relativeClassFqName", fqNameType, nullable = true)
+field("classId", classIdType, nullable = true)
+booleanField("safe")
+booleanField("safe", withReplace = true)
+typeArguments.withTransform()
}
@@ -67,3 +67,5 @@ val effectDeclarationType = type("fir.contracts.description", "ConeEffectDeclara
val emptyContractDescriptionType = generatedType("contracts.impl", "FirEmptyContractDescription")
val firDiagnosticType = generatedType("diagnostics", "FirDiagnostic")
val dslBuilderAnnotationType = generatedType("builder", "FirBuilderDsl")
val firImplementationDetailType = generatedType("FirImplementationDetail")
@@ -0,0 +1,196 @@
/*
* Copyright 2010-2020 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.context
import org.jetbrains.kotlin.fir.tree.generator.model.*
import org.jetbrains.kotlin.fir.tree.generator.noReceiverExpressionType
import org.jetbrains.kotlin.fir.tree.generator.printer.call
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
abstract class AbstractBuilderConfigurator<T : AbstractFirTreeBuilder>(val firTreeBuilder: T) {
abstract class BuilderConfigurationContext {
abstract val builder: Builder
private fun getField(name: String): FieldWithDefault {
return builder[name]
}
fun useTypes(vararg types: Importable) {
types.forEach { builder.usedTypes += it }
}
fun defaultNoReceivers() {
defaultNull("explicitReceiver")
default("dispatchReceiver", "FirNoReceiverExpression")
default("extensionReceiver", "FirNoReceiverExpression")
useTypes(noReceiverExpressionType)
}
fun default(field: String, value: String) {
default(field) {
this.value = value
}
}
fun defaultTrue(field: String) {
default(field) {
value = "true"
}
}
fun defaultFalse(vararg fields: String) {
for (field in fields) {
default(field) {
value = "false"
}
}
}
fun defaultNull(vararg fields: String) {
for (field in fields) {
default(field) {
value = "null"
}
require(getField(field).nullable) {
"$field is not nullable field"
}
}
}
fun default(field: String, init: DefaultValueContext.() -> Unit) {
DefaultValueContext(getField(field)).apply(init).applyConfiguration()
}
inner class DefaultValueContext(private val field: FieldWithDefault) {
var value: String? = null
fun applyConfiguration() {
if (value != null) field.defaultValueInBuilder = value
}
}
}
class IntermediateBuilderConfigurationContext(override val builder: IntermediateBuilder) : BuilderConfigurationContext() {
inner class Fields {
// fields from <element>
infix fun from(element: Element): ExceptConfigurator {
builder.fields += element.allFields.map {
FieldWithDefault(it.copy())
}
builder.packageName = "${element.packageName}.builder"
builder.materializedElement = element
return ExceptConfigurator()
}
inner class Helper(val fieldName: String) {
infix fun from(element: Element) {
val field = element[fieldName] ?: throw IllegalArgumentException("Element $element doesn't have field $fieldName")
builder.fields += FieldWithDefault(field)
}
}
// fields has <field> from <element>
infix fun has(name: String): Helper = Helper(name)
}
inner class ExceptConfigurator {
infix fun without(name: String) {
without(listOf(name))
}
infix fun without(names: List<String>) {
builder.fields.removeAll { it.name in names }
}
}
val fields = Fields()
val parents: MutableList<IntermediateBuilder> get() = builder.parents
var materializedElement: Element
get() = throw IllegalArgumentException()
set(value) {
builder.materializedElement = value
}
}
inner class IntermediateBuilderDelegateProvider(
private val name: String?,
private val block: IntermediateBuilderConfigurationContext.() -> Unit
) {
lateinit var builder: IntermediateBuilder
operator fun provideDelegate(
thisRef: Nothing?,
prop: KProperty<*>
): ReadOnlyProperty<Nothing?, IntermediateBuilder> {
val name = name ?: "Fir${prop.name.capitalize()}"
builder = IntermediateBuilder(name).apply {
firTreeBuilder.intermediateBuilders += this
IntermediateBuilderConfigurationContext(this).block()
}
return DummyDelegate(builder)
}
private inner class DummyDelegate(val builder: IntermediateBuilder) : ReadOnlyProperty<Nothing?, IntermediateBuilder> {
override fun getValue(thisRef: Nothing?, property: KProperty<*>): IntermediateBuilder {
return builder
}
}
}
inner class LeafBuilderConfigurationContext(override val builder: LeafBuilder) : BuilderConfigurationContext() {
val parents: MutableList<IntermediateBuilder> get() = builder.parents
fun openBuilder() {
builder.isOpen = true
}
}
fun builder(name: String? = null, block: IntermediateBuilderConfigurationContext.() -> Unit): IntermediateBuilderDelegateProvider {
return IntermediateBuilderDelegateProvider(name, block)
}
fun builder(element: Element, type: String? = null, init: LeafBuilderConfigurationContext.() -> Unit) {
val implementation = element.extractImplementation(type)
val builder = implementation.builder
requireNotNull(builder)
LeafBuilderConfigurationContext(builder).apply(init)
}
private fun Element.extractImplementation(type: String?): Implementation {
return if (type == null) {
allImplementations.filter { it.kind?.hasLeafBuilder == true }.singleOrNull() ?: this@AbstractBuilderConfigurator.run {
val message = buildString {
appendln("${this@extractImplementation} has multiple implementations:")
for (implementation in allImplementations) {
appendln(" - ${implementation.type}")
}
appendln("Please specify implementation is needed")
}
throw IllegalArgumentException(message)
}
} else {
allImplementations.firstOrNull { it.type == type } ?: this@AbstractBuilderConfigurator.run {
val message = buildString {
appendln("${this@extractImplementation} has not implementation $type. Existing implementations:")
for (implementation in allImplementations) {
appendln(" - ${implementation.type}")
}
appendln("Please specify implementation is needed")
}
throw IllegalArgumentException(message)
}
}
}
fun noBuilder(element: Element, type: String? = null) {
val implementation = element.extractImplementation(type)
implementation.builder = null
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.tree.generator.context
import org.jetbrains.kotlin.fir.tree.generator.model.Element
import org.jetbrains.kotlin.fir.tree.generator.model.IntermediateBuilder
import org.jetbrains.kotlin.fir.tree.generator.model.Type
import org.jetbrains.kotlin.fir.tree.generator.printer.BASE_PACKAGE
import kotlin.reflect.KClass
@@ -23,6 +24,7 @@ abstract class AbstractFirTreeBuilder {
}
val elements = mutableListOf(baseFirElement)
val intermediateBuilders = mutableListOf<IntermediateBuilder>()
protected fun element(name: String, kind: Element.Kind, vararg dependencies: Element, init: Element.() -> Unit = {}): Element =
Element(name, kind).apply(init).also {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.tree.generator.context
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.tree.generator.model.*
import org.jetbrains.kotlin.fir.tree.generator.noReceiverExpressionType
import org.jetbrains.kotlin.fir.tree.generator.printer.call
@@ -89,17 +90,16 @@ abstract class AbstractFirTreeImplementationConfigurator {
fun Implementation.withArg(argument: Importable): ImplementationWithArg = ImplementationWithArg(this, argument)
fun useTypes(vararg types: Importable) {
types.forEach { implementation.usedTypes += it }
fun optInToInternals() {
implementation.requiresOptIn = true
}
fun lateinit(vararg fields: String) {
for (fieldName in fields) {
val field = getField(fieldName)
require(field.origin !is FieldList)
field.isLateinit = true
field.isMutable = true
}
fun publicImplementation() {
implementation.isPublic = true
}
fun useTypes(vararg types: Importable) {
types.forEach { implementation.usedTypes += it }
}
fun isMutable(vararg fields: String) {
@@ -151,7 +151,7 @@ abstract class AbstractFirTreeImplementationConfigurator {
}
fun noSource() {
defaultNull("source")
defaultNull("source", withGetter = true)
}
fun defaultEmptyList(field: String) {
@@ -218,11 +218,11 @@ abstract class AbstractFirTreeImplementationConfigurator {
isMutable?.let { field.isMutable = it }
field.needAcceptAndTransform = needAcceptAndTransform
when {
value != null -> field.defaultValue = value
value != null -> field.defaultValueInImplementation = value
delegate != null -> {
val actualDelegateField = getField(delegate!!)
val name = delegateCall ?: field.name
field.defaultValue = "${actualDelegateField.name}${actualDelegateField.call()}$name"
field.defaultValueInImplementation = "${actualDelegateField.name}${actualDelegateField.call()}$name"
}
}
}
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2020 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.model
private const val DEFAULT_BUILDER_PACKAGE = "org.jetbrains.kotlin.fir.tree.builder"
sealed class Builder : FieldContainer, Importable {
val parents: MutableList<IntermediateBuilder> = mutableListOf()
val usedTypes: MutableList<Importable> = mutableListOf()
abstract override val allFields: List<FieldWithDefault>
abstract val uselessFields: List<FieldWithDefault>
abstract override val packageName: String
override fun get(fieldName: String): FieldWithDefault {
return allFields.firstOrNull { it.name == fieldName }
?: throw IllegalArgumentException("Builder $type doesn't contains field $fieldName")
}
private val fieldsFromParentIndex: Map<String, Boolean> by lazy {
mutableMapOf<String, Boolean>().apply {
for (field in allFields + uselessFields) {
this[field.name] = parents.any { field.name in it.allFields.map { it.name } }
}
}
}
fun isFromParent(field: Field): Boolean = fieldsFromParentIndex.getValue(field.name)
}
class LeafBuilder(val implementation: Implementation) : Builder() {
override val type: String
get() = if (implementation.name != null) {
"${implementation.name}Builder"
} else {
"${implementation.element.type}Builder"
}
override val allFields: List<FieldWithDefault> by lazy { implementation.fieldsWithoutDefault }
override val uselessFields: List<FieldWithDefault> by lazy {
val fieldsFromParents = parents.flatMap { it.allFields }.distinct()
val fieldsFromImplementation = implementation.allFields
(fieldsFromImplementation - allFields).filter { it in fieldsFromParents }
}
override val packageName: String = implementation.packageName.replace(".impl", ".builder")
var isOpen: Boolean = false
}
class IntermediateBuilder(override val type: String) : Builder() {
val fields: MutableList<FieldWithDefault> = mutableListOf()
var materializedElement: Element? = null
override val allFields: List<FieldWithDefault> by lazy {
mutableSetOf<FieldWithDefault>().apply {
parents.forEach { this += it.allFields }
this += fields
}.toList()
}
override val uselessFields: List<FieldWithDefault> = emptyList()
override var packageName: String = DEFAULT_BUILDER_PACKAGE
}
@@ -17,7 +17,7 @@ sealed class Field : Importable {
var fromParent: Boolean = false
open var needsSeparateTransform: Boolean = false
open val defaultValue: String? get() = null
open val defaultValueInImplementation: String? get() = null
abstract var isMutable: Boolean
open var isMutableInInterface: Boolean = false
open val withGetter: Boolean get() = false
@@ -30,11 +30,13 @@ sealed class Field : Importable {
}
protected fun updateFieldsInCopy(copy: Field) {
copy.arguments.clear()
copy.arguments.addAll(arguments)
copy.needsSeparateTransform = needsSeparateTransform
if (copy !is FieldWithDefault) {
copy.arguments.clear()
copy.arguments.addAll(arguments)
copy.needsSeparateTransform = needsSeparateTransform
copy.isMutable = isMutable
}
copy.fromParent = fromParent
copy.isMutable = isMutable
}
protected abstract fun internalCopy(): Field
@@ -72,21 +74,23 @@ class FieldWithDefault(val origin: Field) : Field() {
override val arguments: MutableList<Importable>
get() = origin.arguments
override var defaultValue: String? = origin.defaultValue
override val fullQualifiedName: String?
get() = origin.fullQualifiedName
override var defaultValueInImplementation: String? = origin.defaultValueInImplementation
var defaultValueInBuilder: String? = null
override var isMutable: Boolean = origin.isMutable
override var isMutableInInterface: Boolean = origin.isMutableInInterface
override var withGetter: Boolean = false
override var isLateinit: Boolean = false
override var customSetter: String? = null
override var fromDelegate: Boolean = false
var needAcceptAndTransform: Boolean = true
override fun internalCopy(): Field {
return FieldWithDefault(origin).also {
it.defaultValue = defaultValue
it.defaultValueInImplementation = defaultValueInImplementation
it.isMutable = isMutable
it.withGetter = withGetter
it.isLateinit = isLateinit
it.fromDelegate = fromDelegate
it.needAcceptAndTransform = needAcceptAndTransform
}
@@ -136,6 +140,12 @@ class FirField(
override val nullable: Boolean,
override val withReplace: Boolean
) : Field() {
init {
if (element is ElementWithArguments) {
arguments += element.typeArguments.map { Type(null, it.name) }
}
}
override val type: String get() = element.type
override val packageName: String? get() = element.packageName
override val isFirType: Boolean = true
@@ -159,7 +169,7 @@ class FieldList(
val baseType: Importable,
override val withReplace: Boolean
) : Field() {
override val defaultValue: String? get() = if (isMutable) "mutableListOf()" else "emptyListOf()"
override var defaultValueInImplementation: String? = null
override val packageName: String? get() = baseType.packageName
override val fullQualifiedName: String? get() = baseType.fullQualifiedName
override val type: String = "List<${baseType.typeWithArguments}>"
@@ -5,6 +5,10 @@
package org.jetbrains.kotlin.fir.tree.generator.model
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
class ImplementationWithArg(
val implementation: Implementation,
val argument: Importable?
@@ -23,10 +27,25 @@ class Implementation(val element: Element, val name: String?) : FieldContainer,
FieldWithDefault(it)
}
override var kind: Kind? = null
set(value) {
field = value
if (kind != Kind.FinalClass) {
isPublic = true
}
if (value?.hasLeafBuilder == true) {
builder = builder ?: LeafBuilder(this)
} else {
builder = null
}
}
override val packageName = element.packageName + ".impl"
val usedTypes = mutableListOf<Importable>()
var isPublic = false
var requiresOptIn = false
var builder: LeafBuilder? = null
init {
if (isDefault) {
element.defaultImplementation = this
@@ -55,11 +74,14 @@ class Implementation(val element: Element, val name: String?) : FieldContainer,
}
}
enum class Kind(val title: String) {
Interface("interface"),
FinalClass("class"),
OpenClass("open class"),
AbstractClass("abstract class"),
Object("object")
val fieldsWithoutDefault by lazy { allFields.filter { it.defaultValueInImplementation == null } }
val fieldsWithDefault by lazy { allFields.filter { it.defaultValueInImplementation != null } }
enum class Kind(val title: String, val hasLeafBuilder: Boolean) {
Interface("interface", false),
FinalClass("class", true),
OpenClass("open class", true),
AbstractClass("abstract class", false),
Object("object", false)
}
}
@@ -0,0 +1,264 @@
/*
* Copyright 2010-2020 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.*
import java.io.File
fun Builder.generateCode(generationPath: File) {
val dir = generationPath.resolve(packageName.replace(".", "/"))
dir.mkdirs()
val file = File(dir, "$type.kt")
file.useSmartPrinter {
printCopyright()
println("package $packageName")
println()
val imports = collectImports()
imports.forEach { println("import $it") }
if (imports.isNotEmpty()) {
println()
}
printGeneratedMessage()
printBuilder(this@generateCode)
}
}
private fun SmartPrinter.printBuilder(builder: Builder) {
if (builder is LeafBuilder && builder.allFields.isEmpty()) {
printDslBuildFunction(builder, false)
return
}
println("@FirBuilderDsl")
when (builder) {
is IntermediateBuilder -> print("interface ")
is LeafBuilder -> {
if (builder.isOpen) {
print("open ")
}
print("class ")
}
}
print(builder.typeWithArguments)
if (builder.parents.isNotEmpty()) {
print(builder.parents.joinToString(separator = ", ", prefix = " : ") { it.type })
}
var hasRequiredFields = false
println(" {")
withIndent {
var needNewLine = false
for (field in builder.allFields) {
val (newLine, requiredFields) = printFieldInBuilder(field, builder, fieldIsUseless = false)
needNewLine = newLine
hasRequiredFields = hasRequiredFields || requiredFields
}
val hasBackingFields = builder.allFields.any { it.nullable }
if (needNewLine) {
println()
}
val buildType = when (builder) {
is LeafBuilder -> builder.implementation.element.typeWithArguments
is IntermediateBuilder -> builder.materializedElement!!.typeWithArguments.replace(Regex("<.>"), "<*>")
}
if (builder is LeafBuilder && builder.implementation.isPublic) {
println("@UseExperimental(FirImplementationDetail::class)")
}
if (builder.parents.isNotEmpty()) {
print("override ")
}
print("fun build(): $buildType")
if (builder is LeafBuilder) {
println(" {")
withIndent {
println("return ${builder.implementation.type}(")
withIndent {
for (field in builder.allFields) {
val name = field.name
println(name, ",")
}
}
println(")")
}
println("}")
if (hasBackingFields) {
println()
}
} else {
println()
}
if (builder is LeafBuilder) {
// for (field in builder.allFields) {
// printBackingFieldIfNeeded(field)
// }
val hasUselessFields = builder.uselessFields.isNotEmpty()
if (hasUselessFields) {
println()
builder.uselessFields.forEachIndexed { index, field ->
if (index > 0) {
println()
}
printFieldInBuilder(field, builder, fieldIsUseless = true)
}
}
}
}
println("}")
if (builder is LeafBuilder) {
println()
printDslBuildFunction(builder, hasRequiredFields)
}
}
private val String.nullable: String get() = if (endsWith("?")) this else "$this?"
private fun FieldWithDefault.needBackingField(fieldIsUseless: Boolean) = !nullable && origin !is FieldList && if (fieldIsUseless) {
defaultValueInImplementation == null
} else {
defaultValueInBuilder == null
}
private fun FieldWithDefault.needNotNullDelegate(fieldIsUseless: Boolean) = needBackingField(fieldIsUseless) && (type == "Boolean" || type == "Int")
private fun SmartPrinter.printFieldInBuilder(field: FieldWithDefault, builder: Builder, fieldIsUseless: Boolean): Pair<Boolean, Boolean> {
if (field.withGetter && !fieldIsUseless) 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.typeWithArguments
val defaultValue = if (fieldIsUseless)
field.defaultValueInImplementation.also { requireNotNull(it) }
else
field.defaultValueInBuilder
printDeprecationOnUselessFieldIfNeeded(field, builder, fieldIsUseless)
printModifiers(builder, field, fieldIsUseless)
print("var $name: $type")
var hasRequiredFields = false
val needNewLine = when {
fieldIsUseless -> {
println()
withIndent {
println("get() = throw IllegalStateException()")
println("set(value) {")
withIndent {
println("throw IllegalStateException()")
}
println("}")
}
true
}
builder is IntermediateBuilder -> {
println()
false
}
field.needNotNullDelegate(fieldIsUseless) -> {
println(" by kotlin.properties.Delegates.notNull<${field.type}>()")
hasRequiredFields = true
true
}
field.needBackingField(fieldIsUseless) -> {
// println()
// withIndent {
// println("get() = _$name ?: throw IllegalArgumentException(\"$name should be initialized\")")
// println("set(value) {")
// withIndent {
// println("_$name = value")
// }
// println("}")
// println()
// }
// false
println()
hasRequiredFields = true
true
}
else -> {
println(" = $defaultValue")
true
}
}
return needNewLine to hasRequiredFields
}
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)")
}
}
private fun SmartPrinter.printFieldListInBuilder(field: FieldList, builder: Builder, fieldIsUseless: Boolean) {
printDeprecationOnUselessFieldIfNeeded(field, builder, fieldIsUseless)
printModifiers(builder, field, fieldIsUseless)
print("val ${field.name}: ${field.mutableType}")
if (builder is LeafBuilder) {
print(" = mutableListOf()")
}
println()
}
private fun SmartPrinter.printModifiers(builder: Builder, field: Field, fieldIsUseless: Boolean) {
if (builder is IntermediateBuilder) {
print("abstract ")
}
if (builder.isFromParent(field)) {
print("override ")
} else if (builder is LeafBuilder && builder.isOpen) {
print("open ")
}
if (builder is LeafBuilder && field is FieldWithDefault && field.needBackingField(fieldIsUseless) && !fieldIsUseless && !field.needNotNullDelegate(fieldIsUseless)) {
print("lateinit ")
}
}
private fun SmartPrinter.printDslBuildFunction(
builder: LeafBuilder,
hasRequiredFields: Boolean
) {
val isEmpty = builder.allFields.isEmpty()
if (!isEmpty) {
println("@UseExperimental(ExperimentalContracts::class)")
print("inline ")
} else if(builder.implementation.isPublic) {
println("@UseExperimental(FirImplementationDetail::class)")
}
print("fun ")
builder.implementation.element.typeArguments.takeIf { it.isNotEmpty() }?.let {
print(it.joinToString(separator = ", ", prefix = "<", postfix = "> ") { it.name })
}
val builderType = builder.typeWithArguments
val name = builder.implementation.name?.replaceFirst("Fir", "") ?: builder.implementation.element.name
print("build${name}(")
if (!isEmpty) {
print("init: $builderType.() -> Unit")
if (!hasRequiredFields) {
print(" = {}")
}
}
println("): ${builder.implementation.element.typeWithArguments} {")
withIndent {
if (!isEmpty) {
println("contract {")
withIndent {
println("callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)")
}
println("}")
}
print("return ")
if (isEmpty) {
println("${builder.implementation.type}()")
} else {
println("$builderType().apply(init).build()")
}
}
println("}")
}
@@ -22,23 +22,14 @@ fun SmartPrinter.printField(field: Field, isImplementation: Boolean, override: B
}
fun SmartPrinter.printFieldWithDefaultInImplementation(field: Field) {
val defaultValue = field.defaultValue
val defaultValue = field.defaultValueInImplementation
print("override ")
if (field.isLateinit) {
print("lateinit ")
}
if (field.isVal) {
print("val")
} else {
print("var")
}
print(" ${field.name}: ${field.mutableType}")
if (field.isLateinit) {
println()
return
} else {
print(" ")
}
print(" ${field.name}: ${field.mutableType} ")
if (field.withGetter) {
if (field.customSetter != null) {
println()
@@ -45,10 +45,14 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
}
with(implementation) {
if (requiresOptIn) {
println("@UseExperimental(FirImplementationDetail::class)")
}
if (!isPublic) {
print("internal ")
}
print("${kind!!.title} $type")
print(element.typeParameters)
val fieldsWithoutDefault = allFields.filter { it.defaultValue == null && !it.isLateinit }
val fieldsWithDefault = allFields.filter { it.defaultValue != null || it.isLateinit }
val isInterface = kind == Implementation.Kind.Interface
val isAbstract = kind == Implementation.Kind.AbstractClass
@@ -60,11 +64,13 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
}
if (!isInterface && !isAbstract && fieldsWithoutDefault.isNotEmpty()) {
if (isPublic) {
print(" @FirImplementationDetail constructor")
}
println("(")
withIndent {
fieldsWithoutDefault.forEachIndexed { i, field ->
val end = if (i == fieldsWithoutDefault.size - 1) "" else ","
printField(field, isImplementation = true, override = true, end = end)
printField(field, isImplementation = true, override = true, end = ",")
}
}
print(")")
@@ -29,6 +29,8 @@ val GENERATED_MESSAGE = """
fun printElements(builder: AbstractFirTreeBuilder, generationPath: File) {
builder.elements.forEach { it.generateCode(generationPath) }
builder.elements.flatMap { it.allImplementations }.forEach { it.generateCode(generationPath) }
builder.elements.flatMap { it.allImplementations }.mapNotNull { it.builder }.forEach { it.generateCode(generationPath) }
builder.intermediateBuilders.forEach { it.generateCode(generationPath) }
printVisitor(builder.elements, generationPath)
printVisitorVoid(builder.elements, generationPath)
@@ -7,20 +7,40 @@ package org.jetbrains.kotlin.fir.tree.generator.printer
import org.jetbrains.kotlin.fir.tree.generator.compositeTransformResultType
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder
import org.jetbrains.kotlin.fir.tree.generator.firImplementationDetailType
import org.jetbrains.kotlin.fir.tree.generator.model.*
import org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType
enum class ImportKind(val postfix: String) {
Element(""), Implementation(".impl"), Builder(".builder")
}
fun Implementation.collectImports(): List<String> {
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 = parents + allFields.mapNotNull { it.fullQualifiedName } + allFields.flatMap {
it.arguments.mapNotNull { it.fullQualifiedName }
} + (materializedElement?.fullQualifiedName ?: throw IllegalStateException(type)) + builderDsl
fqns.filterRedundantImports(packageName, ImportKind.Builder)
}
}.sorted()
}
fun Implementation.collectImports(base: List<String> = emptyList(), kind: ImportKind = ImportKind.Implementation): List<String> {
return element.collectImportsInternal(
listOf(
element.fullQualifiedName,
)
base + listOf(element.fullQualifiedName)
+ usedTypes.mapNotNull { it.fullQualifiedName } + parents.mapNotNull { it.fullQualifiedName }
+ listOfNotNull(
pureAbstractElementType.fullQualifiedName?.takeIf { needPureAbstractElement },
firImplementationDetailType.fullQualifiedName?.takeIf { isPublic || requiresOptIn },
),
isImpl = true,
kind,
)
}
@@ -36,20 +56,28 @@ fun Element.collectImports(): List<String> {
}
return collectImportsInternal(
baseTypes,
isImpl = false,
ImportKind.Element,
)
}
private fun Element.collectImportsInternal(base: List<String>, isImpl: Boolean): List<String> {
private fun Element.collectImportsInternal(base: List<String>, kind: ImportKind): List<String> {
val fqns = base + allFields.mapNotNull { it.fullQualifiedName } +
allFields.flatMap { it.arguments.mapNotNull { it.fullQualifiedName } } +
typeArguments.flatMap { it.upperBounds.mapNotNull { it.fullQualifiedName } }
val realPackageName = if (isImpl) "$packageName.impl." else "$packageName."
return fqns.filter { fqn ->
return fqns.filterRedundantImports(packageName, kind)
}
private fun List<String>.filterRedundantImports(
packageName: String,
kind: ImportKind,
): List<String> {
val realPackageName = "$packageName.${kind.postfix}"
return filter { fqn ->
fqn.dropLastWhile { it != '.' } != realPackageName
}.distinct().sorted() + "$VISITOR_PACKAGE.*"
}
val KindOwner.needPureAbstractElement: Boolean
get() = (kind != Implementation.Kind.Interface) && !allParents.any { it.kind == Implementation.Kind.AbstractClass }
@@ -104,6 +132,8 @@ val Importable.typeWithArguments: String
is Field -> type + generics + if (nullable) "?" else ""
is Type -> type + generics
is ImplementationWithArg -> type + generics
is LeafBuilder -> type + implementation.element.generics
is IntermediateBuilder -> type
else -> throw IllegalArgumentException()
}