From 91b5a71f1ae1e7085f1036fd8e2039292d68709c Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Fri, 17 Nov 2023 20:37:00 +0100 Subject: [PATCH] [FIR generator] Extract the `Implementation` class to a common module We want to use it to generate implementation classes for other trees, just like we already do with elements (see `AbstractElement`). --- .../generator/ImplementationConfigurator.kt | 71 ++- .../kotlin/fir/tree/generator/Main.kt | 10 +- ...stractFirTreeImplementationConfigurator.kt | 228 +--------- .../fir/tree/generator/model/Element.kt | 20 +- .../kotlin/fir/tree/generator/model/Field.kt | 4 +- .../tree/generator/model/Implementation.kt | 47 +- .../tree/generator/printer/implementation.kt | 107 ++--- .../fir/tree/generator/printer/utils.kt | 2 - ...irInterfaceAndAbstractClassConfigurator.kt | 19 - .../kotlin/ir/generator/model/Model.kt | 9 +- .../kotlin/ir/generator/print/Elements.kt | 28 +- .../kotlin/generators/tree/AbstractElement.kt | 29 +- .../generators/tree/AbstractElementPrinter.kt | 2 +- .../kotlin/generators/tree/AbstractField.kt | 5 +- .../generators/tree/AbstractFieldPrinter.kt | 2 +- .../tree/AbstractFieldWithDefaultValue.kt | 14 + .../generators/tree/AbstractImplementation.kt | 74 ++++ .../tree/AbstractImplementationPrinter.kt | 101 +++++ .../generators/tree/AbstractVisitorPrinter.kt | 2 +- .../tree/AbstractVisitorVoidPrinter.kt | 2 +- .../InterfaceAndAbstractClassConfigurator.kt | 10 +- .../jetbrains/kotlin/generators/tree/Model.kt | 2 +- .../kotlin/generators/tree/TypeRef.kt | 15 +- .../generators/tree/addPureAbstractElement.kt | 2 +- .../AbstractImplementationConfigurator.kt | 403 ++++++++++++++++++ .../generators/tree/printer/printUtils.kt | 8 +- .../jetbrains/kotlin/generators/tree/utils.kt | 12 +- 27 files changed, 749 insertions(+), 479 deletions(-) delete mode 100644 compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/FirInterfaceAndAbstractClassConfigurator.kt create mode 100644 generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldWithDefaultValue.kt create mode 100644 generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementation.kt create mode 100644 generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementationPrinter.kt create mode 100644 generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/config/AbstractImplementationConfigurator.kt diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt index 62bcd263288..ab6d94dcea5 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt @@ -10,13 +10,8 @@ import org.jetbrains.kotlin.generators.tree.ImplementationKind.Object import org.jetbrains.kotlin.generators.tree.ImplementationKind.OpenClass object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() { - fun configureImplementations() { - configure() - generateDefaultImplementations(FirTreeBuilder) - configureAllImplementations() - } - private fun configure() = with(FirTreeBuilder) { + override fun configure() = with(FirTreeBuilder) { impl(constructor) { defaultFalse("isPrimary", withGetter = true) } @@ -87,7 +82,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() value = "annotationTypeRef.coneTypeOrNull" withGetter = true } - useTypes(coneTypeOrNullImport) + additionalImports(coneTypeOrNullImport) } impl(annotation) { @@ -117,7 +112,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(componentCall) { default("calleeReference", "FirSimpleNamedReference(source, Name.identifier(\"component\$componentIndex\"))") - useTypes(simpleNamedReferenceType, nameType) + additionalImports(simpleNamedReferenceType, nameType) optInToInternals() } @@ -130,7 +125,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() value = "!isThis" withGetter = true } - useTypes(explicitThisReferenceType, explicitSuperReferenceType) + additionalImports(explicitThisReferenceType, explicitSuperReferenceType) } impl(multiDelegatedConstructorCall) { @@ -204,7 +199,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(expression, "FirElseIfTrueCondition") { defaultBuiltInType("Boolean") - useTypes(implicitBooleanTypeRefType) + additionalImports(implicitBooleanTypeRefType) publicImplementation() } @@ -241,7 +236,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(errorLoop) { default("block", "FirEmptyExpressionBlock()") default("condition", "FirErrorExpressionImpl(source, MutableOrEmptyList.empty(), ConeStubDiagnostic(diagnostic), null, null)") - useTypes(emptyExpressionBlock, coneStubDiagnosticType) + additionalImports(emptyExpressionBlock, coneStubDiagnosticType) } impl(expression, "FirExpressionStub") { @@ -291,7 +286,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() withGetter = true } - useTypes(backingFieldSymbolType, delegateFieldSymbolType) + additionalImports(backingFieldSymbolType, delegateFieldSymbolType) } impl(errorProperty) { @@ -306,7 +301,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() withGetter = true ) default("returnTypeRef", "FirErrorTypeRefImpl(null, MutableOrEmptyList.empty(), null, null, diagnostic)") - useTypes(errorTypeRefImplType) + additionalImports(errorTypeRefImplType) } impl(field) { @@ -357,7 +352,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(comparisonExpression) { default("coneTypeOrNull", "StandardClassIds.Boolean.constructClassLikeType()") - useTypes(standardClassIdsType, constructClassLikeTypeImport) + additionalImports(standardClassIdsType, constructClassLikeTypeImport) } impl(typeOperatorCall) { @@ -370,7 +365,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(equalityOperatorCall) { default("coneTypeOrNull", "StandardClassIds.Boolean.constructClassLikeType()") - useTypes(standardClassIdsType, constructClassLikeTypeImport) + additionalImports(standardClassIdsType, constructClassLikeTypeImport) } impl(resolvedQualifier) { @@ -382,17 +377,17 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(returnExpression) { defaultBuiltInType("Nothing") - useTypes(implicitNothingTypeRefType) + additionalImports(implicitNothingTypeRefType) } impl(stringConcatenationCall) { defaultBuiltInType("String") - useTypes(implicitStringTypeRefType) + additionalImports(implicitStringTypeRefType) } impl(throwExpression) { defaultBuiltInType("Nothing") - useTypes(implicitNothingTypeRefType) + additionalImports(implicitNothingTypeRefType) } impl(thisReceiverExpression) { @@ -401,7 +396,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(expression, "FirUnitExpression") { defaultBuiltInType("Unit") - useTypes(implicitUnitTypeRefType) + additionalImports(implicitUnitTypeRefType) publicImplementation() } @@ -419,7 +414,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() value = "!isGetter" withGetter = true } - useTypes(modalityType) + additionalImports(modalityType) kind = OpenClass } @@ -432,12 +427,12 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() value = "whenRef.value.subject?.coneTypeOrNull ?: StandardClassIds.Unit.constructClassLikeType()" withGetter = true } - useTypes(whenExpression, standardClassIdsType, constructClassLikeTypeImport) - useTypes(standardClassIdsType, constructClassLikeTypeImport) + additionalImports(whenExpression, standardClassIdsType, constructClassLikeTypeImport) + additionalImports(standardClassIdsType, constructClassLikeTypeImport) } impl(desugaredAssignmentValueReferenceExpression) { - useTypes(expression) + additionalImports(expression) } impl(wrappedDelegateExpression) { @@ -450,7 +445,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() noSource() default("coneTypeOrNull") { value = "enumClassId.toLookupTag().constructClassType(emptyArray(), false)" - useTypes(toLookupTagImport, constructClassTypeImport) + additionalImports(toLookupTagImport, constructClassTypeImport) } } @@ -462,7 +457,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() default("source") { value = "originalExpression.source?.fakeElement(KtFakeSourceElementKind.SmartCastExpression)" } - useTypes(fakeElementImport, fakeSourceElementKindImport) + additionalImports(fakeElementImport, fakeSourceElementKindImport) } impl(resolvedNamedReference) @@ -528,18 +523,18 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(errorExpression) { default("coneTypeOrNull", "ConeErrorType(ConeStubDiagnostic(diagnostic))") - useTypes(coneErrorTypeType, coneStubDiagnosticType) + additionalImports(coneErrorTypeType, coneStubDiagnosticType) } impl(qualifiedErrorAccessExpression) { default("coneTypeOrNull", "ConeErrorType(ConeStubDiagnostic(diagnostic))") - useTypes(coneErrorTypeType, coneStubDiagnosticType) + additionalImports(coneErrorTypeType, coneStubDiagnosticType) } impl(errorFunction) { defaultNull("receiverParameter", "body", withGetter = true) default("returnTypeRef", "FirErrorTypeRefImpl(null, MutableOrEmptyList.empty(), null, null, diagnostic)") - useTypes(errorTypeRefImplType) + additionalImports(errorTypeRefImplType) } impl(functionTypeRef) @@ -561,12 +556,12 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(breakExpression) { defaultBuiltInType("Nothing") - useTypes(implicitNothingTypeRefType) + additionalImports(implicitNothingTypeRefType) } impl(continueExpression) { defaultBuiltInType("Nothing") - useTypes(implicitNothingTypeRefType) + additionalImports(implicitNothingTypeRefType) } impl(valueParameter) { @@ -582,11 +577,11 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() impl(simpleFunction) impl(safeCallExpression) { - useTypes(checkedSafeCallSubject) + additionalImports(checkedSafeCallSubject) } impl(checkedSafeCallSubject) { - useTypes(expression) + additionalImports(expression) } impl(resolvedQualifier) { @@ -603,7 +598,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() // If this `FirResolvedQualifier` is a receiver expression of some other qualified access, the value is updated in // `FirCallResolver` according to the resolution result. default("resolvedToCompanionObject", "(symbol?.fir as? FirRegularClass)?.companionObjectSymbol != null") - useTypes(regularClass) + additionalImports(regularClass) } impl(errorResolvedQualifier) { @@ -637,7 +632,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters } ) { default(it, "FirResolvedDeclarationStatusImpl.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS") - useTypes(resolvedDeclarationStatusImplType) + additionalImports(resolvedDeclarationStatusImplType) } configureFieldInAllImplementations( @@ -645,11 +640,11 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters } ) { defaultEmptyList(it) - useTypes(resolvedDeclarationStatusImplType) + additionalImports(resolvedDeclarationStatusImplType) } } - private fun configureAllImplementations() { + override fun configureAllImplementations() { configureFieldInAllImplementations( field = "controlFlowGraphReference", implementationPredicate = { it.typeName != "FirAnonymousFunctionImpl" } @@ -688,7 +683,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() fieldPredicate = { it.defaultValueInImplementation == null } ) { default(it, "FirImplicitTypeRefImplWithoutSource") - useTypes(firImplicitTypeWithoutSourceType) + additionalImports(firImplicitTypeWithoutSourceType) } configureFieldInAllImplementations( @@ -697,7 +692,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() fieldPredicate = { it.defaultValueInImplementation == null } ) { default(it, "FirImplicitTypeRefImplWithoutSource") - useTypes(firImplicitTypeWithoutSourceType) + additionalImports(firImplicitTypeWithoutSourceType) } } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt index ca35a2a9a62..ff0d6507a35 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt @@ -7,10 +7,10 @@ package org.jetbrains.kotlin.fir.tree.generator import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder import org.jetbrains.kotlin.fir.tree.generator.printer.generateElements -import org.jetbrains.kotlin.fir.tree.generator.util.FirInterfaceAndAbstractClassConfigurator +import org.jetbrains.kotlin.generators.tree.InterfaceAndAbstractClassConfigurator import org.jetbrains.kotlin.generators.tree.Model -import org.jetbrains.kotlin.generators.tree.detectBaseTransformerTypes import org.jetbrains.kotlin.generators.tree.addPureAbstractElement +import org.jetbrains.kotlin.generators.tree.detectBaseTransformerTypes import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.collectPreviouslyGeneratedFiles import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.removeExtraFilesFromPreviousGeneration @@ -24,8 +24,9 @@ fun main(args: Array) { NodeConfigurator.configureFields() val model = Model(FirTreeBuilder.elements, AbstractFirTreeBuilder.baseFirElement) detectBaseTransformerTypes(model) - ImplementationConfigurator.configureImplementations() - FirInterfaceAndAbstractClassConfigurator(FirTreeBuilder).configureInterfacesAndAbstractClasses() + ImplementationConfigurator.configureImplementations(model) + InterfaceAndAbstractClassConfigurator((model.elements + model.elements.flatMap { it.allImplementations })) + .configureInterfacesAndAbstractClasses() addPureAbstractElement(FirTreeBuilder.elements, pureAbstractElementType) BuilderConfigurator.configureBuilders() val previouslyGeneratedFiles = collectPreviouslyGeneratedFiles(generationPath) @@ -33,4 +34,3 @@ fun main(args: Array) { generatedFiles.forEach { GeneratorsFileUtil.writeFileIfContentChanged(it.file, it.newText, logNotChanged = false) } removeExtraFilesFromPreviousGeneration(previouslyGeneratedFiles, generatedFiles.map { it.file }) } - diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt index fe944af6c62..79fe2074475 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt @@ -6,223 +6,29 @@ package org.jetbrains.kotlin.fir.tree.generator.context import org.jetbrains.kotlin.fir.tree.generator.constructClassLikeTypeImport -import org.jetbrains.kotlin.fir.tree.generator.model.* -import org.jetbrains.kotlin.fir.tree.generator.printer.call +import org.jetbrains.kotlin.fir.tree.generator.model.Element +import org.jetbrains.kotlin.fir.tree.generator.model.FieldWithDefault +import org.jetbrains.kotlin.fir.tree.generator.model.Implementation import org.jetbrains.kotlin.fir.tree.generator.standardClassIdsType -import org.jetbrains.kotlin.generators.tree.ImplementationKind -import org.jetbrains.kotlin.generators.tree.Importable +import org.jetbrains.kotlin.generators.tree.config.AbstractImplementationConfigurator -abstract class AbstractFirTreeImplementationConfigurator { - private val elementsWithImpl = mutableSetOf() +abstract class AbstractFirTreeImplementationConfigurator : AbstractImplementationConfigurator() { - fun noImpl(element: Element) { - element.doesNotNeedImplementation = true + final override fun createImplementation(element: Element, name: String?) = Implementation(element, name) + + protected fun ImplementationContext.defaultNoReceivers() { + defaultNull("explicitReceiver", "dispatchReceiver", "extensionReceiver") } - fun impl(element: Element, name: String? = null, config: ImplementationContext.() -> Unit = {}): Implementation { - val implementation = if (name == null) { - element.defaultImplementation - } else { - element.customImplementations.firstOrNull { it.name == name } - } ?: Implementation(element, name) - val context = ImplementationContext(implementation) - context.apply(config) - elementsWithImpl += element - return implementation + protected fun ImplementationContext.defaultBuiltInType(type: String) { + default("coneTypeOrNull") { + value = "StandardClassIds.$type.constructClassLikeType()" + isMutable = false + } + additionalImports(standardClassIdsType, constructClassLikeTypeImport) } - protected fun generateDefaultImplementations(builder: AbstractFirTreeBuilder) { - collectLeafsWithoutImplementation(builder).forEach { - impl(it) - } - } - - protected fun configureFieldInAllImplementations( - field: String, - implementationPredicate: ((Implementation) -> Boolean)? = null, - fieldPredicate: ((Field) -> Boolean)? = null, - init: ImplementationContext.(field: String) -> Unit - ) { - for (element in elementsWithImpl) { - for (implementation in element.allImplementations) { - if (implementationPredicate != null && !implementationPredicate(implementation)) continue - if (!implementation.allFields.any { it.name == field }) continue - if (fieldPredicate != null && !fieldPredicate(implementation.getField(field))) continue - ImplementationContext(implementation).init(field) - } - } - } - - private fun collectLeafsWithoutImplementation(builder: AbstractFirTreeBuilder): Set { - val elements = builder.elements.toMutableSet() - builder.elements.forEach { - elements.removeAll(it.elementParents.map { it.element }.toSet()) - } - elements.removeAll(elementsWithImpl) - return elements - } - - private fun Implementation.getField(name: String): FieldWithDefault { - val result = allFields.firstOrNull { it.name == name } - requireNotNull(result) { - "Field \"$name\" not found in fields of ${element}\nExisting fields:\n" + - allFields.joinToString(separator = "\n ", prefix = " ") { it.name } - } - return result - } - - inner class ImplementationContext(private val implementation: Implementation) { - private fun getField(name: String): FieldWithDefault { - return implementation.getField(name) - } - - fun optInToInternals() { - implementation.requiresOptIn = true - } - - fun publicImplementation() { - implementation.isPublic = true - } - - fun useTypes(vararg types: Importable) { - types.forEach { implementation.usedTypes += it } - } - - fun isMutable(vararg fields: String) { - fields.forEach { - val field = getField(it) - field.isMutable = true - } - } - - fun defaultNoReceivers() { - defaultNull("explicitReceiver", "dispatchReceiver", "extensionReceiver") - } - - fun default(field: String, value: String) { - default(field) { - this.value = value - } - } - - fun defaultBuiltInType(type: String) { - default("coneTypeOrNull") { - value = "StandardClassIds.$type.constructClassLikeType()" - isMutable = false - } - useTypes(standardClassIdsType, constructClassLikeTypeImport) - } - - fun defaultTrue(field: String, withGetter: Boolean = false) { - default(field) { - value = "true" - this.withGetter = withGetter - } - } - - fun defaultFalse(vararg fields: String, withGetter: Boolean = false) { - for (field in fields) { - default(field) { - value = "false" - this.withGetter = withGetter - } - } - } - - fun defaultNull(vararg fields: String, withGetter: Boolean = false) { - for (field in fields) { - default(field) { - value = "null" - this.withGetter = withGetter - } - require(getField(field).nullable) { - "$field is not nullable field" - } - } - } - - fun noSource() { - defaultNull("source", withGetter = true) - } - - fun defaultEmptyList(field: String) { - require(getField(field).origin is FieldList) { - "$field is list field" - } - default(field) { - value = "emptyList()" - withGetter = true - } - } - - fun default(field: String, init: DefaultValueContext.() -> Unit) { - DefaultValueContext(getField(field)).apply(init).applyConfiguration() - } - - fun delegateFields(fields: List, delegate: String) { - for (field in fields) { - default(field) { - this.delegate = delegate - } - } - } - - var kind: ImplementationKind? - get() = implementation.kind - set(value) { - implementation.kind = value - } - - inner class DefaultValueContext(private val field: FieldWithDefault) { - var value: String? = null - - var delegate: String? = null - set(value) { - field = value - if (value != null) { - withGetter = true - } - } - var delegateCall: String? = null - - var isMutable: Boolean? = null - var withGetter: Boolean = false - set(value) { - field = value - if (value) { - isMutable = customSetter != null - } - } - - var customSetter: String? = null - set(value) { - field = value - isMutable = true - withGetter = true - } - - var needAcceptAndTransform: Boolean = true - - var notNull: Boolean = false - - fun applyConfiguration() { - field.withGetter = withGetter - field.customSetter = customSetter - isMutable?.let { field.isMutable = it } - field.needAcceptAndTransform = needAcceptAndTransform - - if (notNull) { - field.notNull = true - } - when { - value != null -> field.defaultValueInImplementation = value - delegate != null -> { - val actualDelegateField = getField(delegate!!) - val name = delegateCall ?: field.name - field.defaultValueInImplementation = "${actualDelegateField.name}${actualDelegateField.call()}$name" - } - } - } - } + protected fun ImplementationContext.noSource() { + defaultNull("source", withGetter = true) } } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt index b507a79a3d7..1638b17b510 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.generators.tree.* import org.jetbrains.kotlin.generators.tree.ElementOrRef as GenericElementOrRef import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef -class Element(name: String, override val propertyName: String, kind: Kind) : AbstractElement(name) { +class Element(name: String, override val propertyName: String, kind: Kind) : AbstractElement(name) { companion object { private val allowedKinds = setOf( ImplementationKind.Interface, @@ -41,9 +41,6 @@ class Element(name: String, override val propertyName: String, kind: Kind) : Abs override val otherParents = mutableListOf>() - var defaultImplementation: Implementation? = null - val customImplementations = mutableListOf() - override val params = mutableListOf() override var kind: ImplementationKind? = null @@ -76,18 +73,7 @@ class Element(name: String, override val propertyName: String, kind: Kind) : Abs override val visitorParameterName: String get() = safeDecapitalizedName - var doesNotNeedImplementation: Boolean = false - val needTransformOtherChildren: Boolean get() = _needTransformOtherChildren || elementParents.any { it.element.needTransformOtherChildren } - val allImplementations: List by lazy { - if (doesNotNeedImplementation) { - emptyList() - } else { - val implementations = customImplementations.toMutableList() - defaultImplementation?.let { implementations += it } - implementations - } - } override fun toString(): String { return with(ImportCollector("")) { render() } @@ -104,6 +90,6 @@ class Element(name: String, override val propertyName: String, kind: Kind) : Abs } } -typealias ElementRef = GenericElementRef +typealias ElementRef = GenericElementRef -typealias ElementOrRef = GenericElementOrRef +typealias ElementOrRef = GenericElementOrRef diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt index a5388822b68..9df1d9255bc 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt @@ -31,8 +31,6 @@ sealed class Field : AbstractField() { abstract override var isFinal: Boolean - abstract override var isLateinit: Boolean - abstract override var isParameter: Boolean abstract override var isMutable: Boolean @@ -69,7 +67,7 @@ sealed class Field : AbstractField() { // ----------- Field with default ----------- -class FieldWithDefault(val origin: Field) : Field() { +class FieldWithDefault(override val origin: Field) : Field(), AbstractFieldWithDefaultValue { override val name: String get() = origin.name override val typeRef: TypeRefWithNullability get() = origin.typeRef override var isVolatile: Boolean = origin.isVolatile diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Implementation.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Implementation.kt index 3c695b3944c..1908695130c 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Implementation.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Implementation.kt @@ -7,10 +7,7 @@ package org.jetbrains.kotlin.fir.tree.generator.model import org.jetbrains.kotlin.generators.tree.* -class Implementation(val element: Element, val name: String?) : FieldContainer, ImplementationKindOwner { - override val allParents: List get() = listOf(element) - val isDefault = name == null - override val typeName = name ?: (element.typeName + "Impl") +class Implementation(element: Element, name: String?) : AbstractImplementation(element, name) { override val allFields = element.allFields.toMutableList().mapTo(mutableListOf()) { FieldWithDefault(it) @@ -28,49 +25,7 @@ class Implementation(val element: Element, val name: String?) : FieldContainer() - - var isPublic = false - var requiresOptIn = false var builder: LeafBuilder? = null - - init { - if (isDefault) { - element.defaultImplementation = this - } else { - element.customImplementations += this - } - } - - override val hasAcceptChildrenMethod: Boolean - get() { - val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface - val isAbstract = kind == ImplementationKind.AbstractClass || kind == ImplementationKind.SealedClass - return !isInterface && !isAbstract - } - - override val hasTransformChildrenMethod: Boolean - get() = true - - override fun get(fieldName: String): FieldWithDefault? { - return allFields.firstOrNull { it.name == fieldName } - } - - val fieldsWithoutDefault by lazy { allFields.filter { it.defaultValueInImplementation == null } } - val fieldsWithDefault by lazy { allFields.filter { it.defaultValueInImplementation != null } } - } val ImplementationKind.hasLeafBuilder: Boolean diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt index 764c6d8ea96..500fe88c398 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/implementation.kt @@ -25,10 +25,10 @@ fun Implementation.generateCode(generationPath: File): GeneratedFile = fileSuppressions = listOf("DuplicatedCode", "unused"), ) { addAllImports(usedTypes) - printImplementation(this@generateCode) + ImplementationPrinter(this).printImplementation(this@generateCode) } -private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldPrinter(printer) { +private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldPrinter(printer) { private fun Field.isMutableOrEmptyIfList(): Boolean = when (this) { is FieldList -> isMutableOrEmptyList @@ -36,91 +36,44 @@ private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldP else -> true } - override fun forceMutable(field: Field): Boolean = field.isMutable && field.isMutableOrEmptyIfList() + override fun forceMutable(field: FieldWithDefault): Boolean = field.isMutable && field.isMutableOrEmptyIfList() - override fun actualTypeOfField(field: Field) = field.getMutableType() + override fun actualTypeOfField(field: FieldWithDefault) = field.getMutableType() } -context(ImportCollector) -fun SmartPrinter.printImplementation(implementation: Implementation) { - fun Field.transform() { - when (this) { - is FieldWithDefault -> origin.transform() +private class ImplementationPrinter( + printer: SmartPrinter +) : AbstractImplementationPrinter(printer) { - is FirField -> - println("$name = ${name}${call()}transform(transformer, data)") + override val implementationOptInAnnotation: ClassRef<*> + get() = firImplementationDetailType - is FieldList -> { - addImport(transformInPlaceImport) - println("${name}.transformInplace(transformer, data)") - } - else -> throw IllegalStateException() - } - } + override val pureAbstractElementType: ClassRef<*> + get() = org.jetbrains.kotlin.fir.tree.generator.pureAbstractElementType - with(implementation) { - buildSet { - if (requiresOptIn) { - add(firImplementationDetailType) - } + override fun makeFieldPrinter(printer: SmartPrinter) = ImplementationFieldPrinter(printer) - for (field in fieldsWithoutDefault) { - field.optInAnnotation?.let { - add(it) + context(ImportCollector) + override fun SmartPrinter.printAdditionalMethods(implementation: Implementation) { + fun Field.transform() { + when (this) { + is FieldWithDefault -> origin.transform() + + is FirField -> + println("$name = ${name}${call()}transform(transformer, data)") + + is FieldList -> { + addImport(transformInPlaceImport) + println("${name}.transformInplace(transformer, data)") } + + else -> throw IllegalStateException() } - }.ifNotEmpty { - println("@OptIn(${joinToString { "${it.render()}::class" }})") } - - if (!isPublic) { - print("internal ") - } - print("${kind!!.title} ${this.typeName}") - print(element.params.typeParameters(end = " ")) - - val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface - val isAbstract = kind == ImplementationKind.AbstractClass || kind == ImplementationKind.SealedClass - - val fieldPrinter = ImplementationFieldPrinter(this@printImplementation) - - if (!isInterface && !isAbstract && fieldsWithoutDefault.isNotEmpty()) { - if (isPublic) { - print(" @${firImplementationDetailType.render()} constructor") - } - println("(") - withIndent { - fieldsWithoutDefault.forEachIndexed { _, field -> - if (field.isParameter) { - print("${field.name}: ${field.typeRef.render()}") - if (field.nullable) print("?") - println(",") - } else if (!field.isFinal) { - fieldPrinter.printField(field, override = true, inConstructor = true) - } - } - } - print(")") - } - - print(" : ") - if (needPureAbstractElement) { - print("${pureAbstractElementType.render()}(), ") - } - print(allParents.joinToString { "${it.render()}${it.kind.braces()}" }) - printBlock { - if (isInterface || isAbstract) { - allFields.forEach { - fieldPrinter.printField(it, override = true, modality = Modality.ABSTRACT.takeIf { isAbstract }) - } - } else { - fieldsWithDefault.forEach { - fieldPrinter.printField(it, override = true) - } - } - - + with(implementation) { + val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface + val isAbstract = kind == ImplementationKind.AbstractClass || kind == ImplementationKind.SealedClass val bindingCalls = element.allFields.filter { it.withBindThis && it.hasSymbolType && it !is FieldList && it.name != "companionObjectSymbol" }.takeIf { @@ -199,7 +152,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) { } is FieldList -> { - println("${field.name}.forEach { it.accept(visitor, data) }") + println(field.name, field.call(), "forEach { it.accept(visitor, data) }") } else -> throw IllegalStateException() diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt index adf6fa7c76a..1abb2f1f19b 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/printer/utils.kt @@ -88,6 +88,4 @@ fun Field.getMutableType(forBuilder: Boolean = false): TypeRefWithNullability = else -> typeRef } -fun Field.call(): String = if (nullable) "?." else "." - val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" else name.replaceFirstChar(Char::lowercaseChar) diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/FirInterfaceAndAbstractClassConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/FirInterfaceAndAbstractClassConfigurator.kt deleted file mode 100644 index 62b4b30ff57..00000000000 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/util/FirInterfaceAndAbstractClassConfigurator.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2010-2019 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.util - -import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder -import org.jetbrains.kotlin.fir.tree.generator.model.Implementation -import org.jetbrains.kotlin.generators.tree.ImplementationKindOwner -import org.jetbrains.kotlin.generators.tree.InterfaceAndAbstractClassConfigurator - -internal class FirInterfaceAndAbstractClassConfigurator(builder: AbstractFirTreeBuilder) : InterfaceAndAbstractClassConfigurator( - elements = (builder.elements + builder.elements.flatMap { it.allImplementations }) -) { - override fun shouldBeFinalClass(element: ImplementationKindOwner, allParents: Set): Boolean = - element is Implementation && element !in allParents -} - diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt index 20604de970b..b0c4215ecb4 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/model/Model.kt @@ -18,7 +18,7 @@ class Element( name: String, override val propertyName: String, category: Category, -) : AbstractElement(name) { +) : AbstractElement(name) { enum class Category(private val packageDir: String, val defaultVisitorParam: String) { Expression("expressions", "expression"), @@ -136,8 +136,8 @@ class Element( } } -typealias ElementRef = GenericElementRef -typealias ElementOrRef = GenericElementOrRef +typealias ElementRef = GenericElementRef +typealias ElementOrRef = GenericElementOrRef sealed class Field( override val name: String, @@ -179,9 +179,6 @@ sealed class Field( override val isFinal: Boolean get() = defaultValueInImplementation != null - override val isLateinit: Boolean - get() = false - override val isParameter: Boolean get() = false diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Elements.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Elements.kt index 9652b320b16..05fa0a5efde 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Elements.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/print/Elements.kt @@ -75,14 +75,11 @@ private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter println(".accept(visitor, data)") + is SingleField -> println("accept(visitor, data)") is ListField -> { - print(".forEach { it") + print("forEach { it") if (child.baseType.nullable) { print("?") } @@ -109,12 +106,9 @@ private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter { - print(" = ", child.name) - if (child.nullable) { - print("?") - } - print(".transform(transformer, data)") - val elementRef = child.typeRef as GenericElementRef<*, *> + print(" = ", child.name, child.call()) + print("transform(transformer, data)") + val elementRef = child.typeRef as GenericElementRef<*> if (!elementRef.element.hasTransformMethod) { print(" as ", elementRef.render()) } @@ -122,15 +116,13 @@ private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter { if (child.isMutable) { - print(" = ", child.name) - if (child.nullable) { - print("?") - } + print(" = ", child.name, child.call()) addImport(transformIfNeeded) - println(".transformIfNeeded(transformer, data)") + println("transformIfNeeded(transformer, data)") } else { addImport(transformInPlace) - println(".transformInPlace(transformer, data)") + print(child.call()) + println("transformInPlace(transformer, data)") } } } diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElement.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElement.kt index b03bc344228..31b17f91746 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElement.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElement.kt @@ -8,11 +8,12 @@ package org.jetbrains.kotlin.generators.tree /** * A class representing a FIR or IR tree element. */ -abstract class AbstractElement( +abstract class AbstractElement( val name: String, -) : ElementOrRef, FieldContainer, ImplementationKindOwner - where Element : AbstractElement, - Field : AbstractField { +) : ElementOrRef, FieldContainer, ImplementationKindOwner + where Element : AbstractElement, + Field : AbstractField, + Implementation : AbstractImplementation { /** * The fully-qualified name of the property in the tree generator that is used to configure this element. @@ -25,7 +26,7 @@ abstract class AbstractElement( abstract val params: List - abstract val elementParents: List> + abstract val elementParents: List> abstract val otherParents: MutableList> @@ -144,6 +145,22 @@ abstract class AbstractElement( val transformerClass: Element get() = transformerReturnType ?: baseTransformerType ?: element + var defaultImplementation: Implementation? = null + + val customImplementations = mutableListOf() + + var doesNotNeedImplementation: Boolean = false + + val allImplementations: List by lazy { + if (doesNotNeedImplementation) { + emptyList() + } else { + val implementations = customImplementations.toMutableList() + defaultImplementation?.let { implementations += it } + implementations + } + } + final override fun get(fieldName: String): Field? { return allFields.firstOrNull { it.name == fieldName } } @@ -159,5 +176,5 @@ abstract class AbstractElement( @Suppress("UNCHECKED_CAST") override fun substitute(map: TypeParameterSubstitutionMap): Element = this as Element - fun withStarArgs(): ElementRef = copy(params.associateWith { TypeRef.Star }) + fun withStarArgs(): ElementRef = copy(params.associateWith { TypeRef.Star }) } diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElementPrinter.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElementPrinter.kt index ca6ddd87991..79bf21eb84e 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElementPrinter.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractElementPrinter.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.utils.withIndent /** * A common class for printing FIR or IR tree elements. */ -abstract class AbstractElementPrinter, Field : AbstractField>( +abstract class AbstractElementPrinter, Field : AbstractField>( private val printer: SmartPrinter, ) { diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt index 219a3d3586e..b1c91faea97 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractField.kt @@ -20,7 +20,7 @@ abstract class AbstractField> { abstract val isFinal: Boolean - abstract val isLateinit: Boolean + open var isLateinit: Boolean = false abstract val isParameter: Boolean @@ -42,7 +42,7 @@ abstract class AbstractField> { * Whether this field can contain an element either directly or e.g. in a list. */ open val containsElement: Boolean - get() = typeRef is ElementOrRef<*, *> || this is ListField && baseType is ElementOrRef<*, *> + get() = typeRef is ElementOrRef<*> || this is ListField && baseType is ElementOrRef<*> open val defaultValueInImplementation: String? get() = null @@ -90,6 +90,7 @@ abstract class AbstractField> { protected open fun updateFieldsInCopy(copy: Field) { copy.kDoc = kDoc + copy.isLateinit = isLateinit copy.arbitraryImportables += arbitraryImportables copy.optInAnnotation = optInAnnotation copy.isMutable = isMutable diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt index 432a219378c..401f9a3aad8 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldPrinter.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly import org.jetbrains.kotlin.utils.SmartPrinter import org.jetbrains.kotlin.utils.withIndent -abstract class AbstractFieldPrinter>( +abstract class AbstractFieldPrinter>( private val printer: SmartPrinter, ) { diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldWithDefaultValue.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldWithDefaultValue.kt new file mode 100644 index 00000000000..1cf3f2db7fc --- /dev/null +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractFieldWithDefaultValue.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.tree + +interface AbstractFieldWithDefaultValue> { + val origin: OriginField + var withGetter: Boolean + var customSetter: String? + var notNull: Boolean + var defaultValueInImplementation: String? +} \ No newline at end of file diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementation.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementation.kt new file mode 100644 index 00000000000..fb3c143c686 --- /dev/null +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementation.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.tree + +/** + * A class representing a non-abstract implementation of an abstract class/interface of a tree node. + */ +@Suppress("LeakingThis") +abstract class AbstractImplementation( + val element: Element, + val name: String?, +) : FieldContainer, ImplementationKindOwner + where Implementation : AbstractImplementation, + Element : AbstractElement, + Field : AbstractField<*> { + + private val isDefault: Boolean + get() = name == null + + override val allParents: List + get() = listOf(element) + + override val typeName: String = name ?: (element.typeName + "Impl") + + 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() + + init { + @Suppress("UNCHECKED_CAST") + if (isDefault) { + element.defaultImplementation = this as Implementation + } else { + element.customImplementations += this as Implementation + } + } + + override val hasAcceptChildrenMethod: Boolean + get() { + val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface + val isAbstract = kind == ImplementationKind.AbstractClass || kind == ImplementationKind.SealedClass + return !isInterface && !isAbstract + } + + override val hasTransformChildrenMethod: Boolean + get() = true + var isPublic = false + + override fun get(fieldName: String): Field? { + return allFields.firstOrNull { it.name == fieldName } + } + + private fun withDefault(field: Field) = !field.isFinal && (field.defaultValueInImplementation != null || field.isLateinit) + + val fieldsWithoutDefault by lazy { allFields.filterNot(::withDefault) } + + val fieldsWithDefault by lazy { allFields.filter(::withDefault) } + + var requiresOptIn = false +} \ No newline at end of file diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementationPrinter.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementationPrinter.kt new file mode 100644 index 00000000000..111d4bc9c60 --- /dev/null +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractImplementationPrinter.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.tree + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.generators.tree.printer.braces +import org.jetbrains.kotlin.generators.tree.printer.printBlock +import org.jetbrains.kotlin.generators.tree.printer.typeParameters +import org.jetbrains.kotlin.utils.SmartPrinter +import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty +import org.jetbrains.kotlin.utils.withIndent + +abstract class AbstractImplementationPrinter( + private val printer: SmartPrinter, +) + where Implementation : AbstractImplementation, + Element : AbstractElement, + ImplementationField : AbstractField<*>, + ImplementationField : AbstractFieldWithDefaultValue<*> { + + protected abstract val implementationOptInAnnotation: ClassRef<*> + + protected abstract val pureAbstractElementType: ClassRef<*> + + protected abstract fun makeFieldPrinter(printer: SmartPrinter): AbstractFieldPrinter + + context(ImportCollector) + protected open fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {} + + context(ImportCollector) + fun printImplementation(implementation: Implementation) { + printer.run { + buildSet { + if (implementation.requiresOptIn) { + add(implementationOptInAnnotation) + } + + for (field in implementation.fieldsWithoutDefault) { + field.optInAnnotation?.let { + add(it) + } + } + }.ifNotEmpty { + println("@OptIn(", joinToString { "${it.render()}::class" }, ")") + } + + if (!implementation.isPublic) { + print("internal ") + } + + val kind = implementation.kind ?: error("Expected non-null element kind") + print("${kind.title} ${implementation.typeName}") + print(implementation.element.params.typeParameters(end = " ")) + + val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface + val isAbstract = kind == ImplementationKind.AbstractClass || kind == ImplementationKind.SealedClass + + val fieldPrinter = makeFieldPrinter(this) + + if (!isInterface && !isAbstract && implementation.fieldsWithoutDefault.isNotEmpty()) { + if (implementation.isPublic) { + print(" @", implementationOptInAnnotation.render(), " constructor") + } + println("(") + withIndent { + implementation.fieldsWithoutDefault.forEachIndexed { _, field -> + if (field.isParameter) { + print(field.name, ": ", field.typeRef.render()) + println(",") + } else if (!field.isFinal) { + fieldPrinter.printField(field, override = true, inConstructor = true) + } + } + } + print(")") + } + + print(" : ") + if (implementation.needPureAbstractElement) { + print(pureAbstractElementType.render(), "(), ") + } + print(implementation.allParents.joinToString { "${it.render()}${it.kind.braces()}" }) + printBlock { + if (isInterface || isAbstract) { + implementation.allFields.forEach { + fieldPrinter.printField(it, override = true, modality = Modality.ABSTRACT.takeIf { isAbstract }) + } + } else { + implementation.fieldsWithDefault.forEach { + fieldPrinter.printField(it, override = true) + } + } + + printAdditionalMethods(implementation) + } + } + } +} \ No newline at end of file diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorPrinter.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorPrinter.kt index 5a4113649e5..0193172d53d 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorPrinter.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorPrinter.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.SmartPrinter import org.jetbrains.kotlin.utils.withIndent -abstract class AbstractVisitorPrinter, Field : AbstractField>( +abstract class AbstractVisitorPrinter, Field : AbstractField>( val printer: SmartPrinter, ) { diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorVoidPrinter.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorVoidPrinter.kt index 8a0d606aad4..249141be799 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorVoidPrinter.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/AbstractVisitorVoidPrinter.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.utils.SmartPrinter abstract class AbstractVisitorVoidPrinter( printer: SmartPrinter, ) : AbstractVisitorPrinter(printer) - where Element : AbstractElement, + where Element : AbstractElement, Field : AbstractField { final override val visitorTypeParameters: List diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/InterfaceAndAbstractClassConfigurator.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/InterfaceAndAbstractClassConfigurator.kt index 55750350a70..b54845d30ae 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/InterfaceAndAbstractClassConfigurator.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/InterfaceAndAbstractClassConfigurator.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.generators.util.solveGraphForClassVsInterface * * @property elements The list of elements of the tree to infer their [ImplementationKind]. */ -open class InterfaceAndAbstractClassConfigurator(val elements: List) { +class InterfaceAndAbstractClassConfigurator(val elements: List) { private inner class NodeImpl(val element: ImplementationKindOwner) : Node { override val parents: List @@ -27,10 +27,8 @@ open class InterfaceAndAbstractClassConfigurator(val elements: List): Boolean = false + private fun shouldBeFinalClass(element: ImplementationKindOwner, allParents: Set): Boolean = + element is AbstractImplementation<*, *, *> && element !in allParents private fun updateKinds(nodes: List, solution: List) { val allParents = nodes.flatMapTo(mutableSetOf()) { element -> element.parents.map { it.origin.element } } @@ -59,7 +57,7 @@ open class InterfaceAndAbstractClassConfigurator(val elements: List) { for (node in nodes) { val element = node.element - if (element is AbstractElement<*, *>) { + if (element is AbstractElement<*, *, *>) { if (element.isSealed) { element.kind = when (element.kind) { ImplementationKind.AbstractClass -> ImplementationKind.SealedClass diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/Model.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/Model.kt index 8aec03e4bb7..7c08d54095d 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/Model.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/Model.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.generators.tree -data class Model>( +data class Model>( val elements: List, val rootElement: Element, ) diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/TypeRef.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/TypeRef.kt index 6afc3c2570b..8a730ea3fd5 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/TypeRef.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/TypeRef.kt @@ -128,19 +128,18 @@ data class TypeRefWithVariance(val variance: Variance, val type TypeRefWithVariance(variance, typeRef.substitute(map)) } -interface ElementOrRef : ParametrizedTypeRef, NamedTypeParameterRef>, ClassOrElementRef - where Element : AbstractElement, - Field : AbstractField { +interface ElementOrRef : ParametrizedTypeRef, NamedTypeParameterRef>, ClassOrElementRef + where Element : AbstractElement { val element: Element - override fun copy(nullable: Boolean): ElementRef + override fun copy(nullable: Boolean): ElementRef } -data class ElementRef, Field : AbstractField>( +data class ElementRef>( override val element: Element, override val args: Map = emptyMap(), override val nullable: Boolean = false, -) : ElementOrRef { +) : ElementOrRef { override fun copy(args: Map) = ElementRef(element, args, nullable) override fun copy(nullable: Boolean) = ElementRef(element, args, nullable) @@ -307,12 +306,12 @@ fun type(packageName: String, name: String, kind: TypeKind = TypeKind.Interface) val ClassOrElementRef.typeKind: TypeKind get() = when (this) { - is ElementOrRef<*, *> -> element.kind!!.typeKind + is ElementOrRef<*> -> element.kind!!.typeKind is ClassRef<*> -> kind } fun ClassOrElementRef.inheritanceClauseParenthesis(): String = when (this) { - is ElementOrRef<*, *> -> element.kind.braces() + is ElementOrRef<*> -> element.kind.braces() is ClassRef<*> -> when (kind) { TypeKind.Class -> "()" TypeKind.Interface -> "" diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/addPureAbstractElement.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/addPureAbstractElement.kt index a05bd507e59..3f8d17dd1fc 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/addPureAbstractElement.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/addPureAbstractElement.kt @@ -9,7 +9,7 @@ val ImplementationKindOwner.needPureAbstractElement: Boolean get() = !(kind?.isInterface ?: false) && allParents.none { it.kind == ImplementationKind.AbstractClass || it.kind == ImplementationKind.SealedClass } -fun addPureAbstractElement(elements: List>, pureAbstractElement: ClassRef<*>) { +fun addPureAbstractElement(elements: List>, pureAbstractElement: ClassRef<*>) { for (el in elements) { if (el.needPureAbstractElement) { el.otherParents.add(pureAbstractElement) diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/config/AbstractImplementationConfigurator.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/config/AbstractImplementationConfigurator.kt new file mode 100644 index 00000000000..ffbaf02e4dc --- /dev/null +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/config/AbstractImplementationConfigurator.kt @@ -0,0 +1,403 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.generators.tree.config + +import org.jetbrains.kotlin.generators.tree.* +import org.jetbrains.kotlin.generators.tree.printer.call + +/** + * Provides a DSL to configure `Impl` classes for tree nodes. + */ +@Suppress("MemberVisibilityCanBePrivate", "unused") +abstract class AbstractImplementationConfigurator + where Implementation : AbstractImplementation, + Element : AbstractElement, + ImplementationField : AbstractField<*>, + ImplementationField : AbstractFieldWithDefaultValue<*> { + + private val elementsWithImpl = mutableSetOf() + + protected abstract fun createImplementation(element: Element, name: String?): Implementation + + fun configureImplementations(model: Model) { + configure() + generateDefaultImplementations(model.elements) + configureAllImplementations() + } + + /** + * A customization point to fine-tune existing implementation classes or add new ones. + * + * Override this method and use [noImpl] or [impl] in it to configure implementations of tree nodes. + */ + protected abstract fun configure() + + /** + * A customization point for batch-applying rules to existing implementations. + * + * Override this method and use [configureFieldInAllImplementations] to configure fields that are common to multiple implementation + * classes. + */ + protected abstract fun configureAllImplementations() + + /** + * Disables generating any implementation classes for [element]. + */ + protected fun noImpl(element: Element) { + element.doesNotNeedImplementation = true + } + + /** + * Provides a way to fine-tune a single implementation class for [element]. + * + * @param element The element whose implementation you want to configure. + * @param name The name of the implementation class, or `null` if you want to configure the default implementation class for this + * element. If an implementation with this name already exists, it will be used, otherwise a new implementation will be created. + * @param config The configuration block. See [ImplementationContext]'s documentation for description of its DSL methods. + * @return The configured implementation. + */ + protected fun impl(element: Element, name: String? = null, config: ImplementationContext.() -> Unit = {}): Implementation { + val implementation = if (name == null) { + element.defaultImplementation + } else { + element.customImplementations.firstOrNull { it.name == name } + } ?: createImplementation(element, name) + val context = ImplementationContext(implementation) + context.apply(config) + elementsWithImpl += element + return implementation + } + + private fun generateDefaultImplementations(elements: List) { + collectLeafsWithoutImplementation(elements).forEach { + impl(it) + } + } + + private fun collectLeafsWithoutImplementation(elements: List): Set { + val leafs = elements.toMutableSet() + elements.forEach { element -> + leafs.removeAll(element.elementParents.map { it.element }.toSet()) + } + leafs.removeAll(elementsWithImpl) + return leafs + } + + /** + * Allows to batch-apply [config] to certain fields in _all_ the implementations that satisfy the given + * [implementationPredicate]. + * + * @param field The name of the field to configure across all `Impl` classes. + * @param implementationPredicate Only implementations satisfying this predicate will be used in this configuration. + * @param fieldPredicate Only fields satisfying this predicate will be configured + * @param config The configuration block. Accepts the field name as an argument. + * See [ImplementationContext]'s documentation for description of its DSL methods. + */ + protected fun configureFieldInAllImplementations( + field: String, + implementationPredicate: (Implementation) -> Boolean = { true }, + fieldPredicate: (ImplementationField) -> Boolean = { true }, + config: ImplementationContext.(field: String) -> Unit, + ) { + for (element in elementsWithImpl) { + for (implementation in element.allImplementations) { + if (!implementationPredicate(implementation)) continue + if (!implementation.allFields.any { it.name == field }) continue + if (!fieldPredicate(implementation.getField(field))) continue + ImplementationContext(implementation).config(field) + } + } + } + + private fun Implementation.getField(name: String): ImplementationField { + val result = this[name] + requireNotNull(result) { + "Field \"$name\" not found in fields of $element\nExisting fields:\n" + + allFields.joinToString(separator = "\n ", prefix = " ") { it.name } + } + return result + } + + /** + * A DSL for configuring one or more implementation classes. + */ + protected inner class ImplementationContext(val implementation: Implementation) { + + /** + * Call this function if you want this implementation class to be marked with an [OptIn] annotation. + * + * This is necessary if some code inside the implementation class requires that [OptIn] annotation. + */ + fun optInToInternals() { + implementation.requiresOptIn = true + } + + /** + * By default, all implementation classes are generated with `internal` visibility. + * + * This method allows to forcibly make this implementation `public`. + */ + fun publicImplementation() { + implementation.isPublic = true + } + + private fun getField(name: String): ImplementationField { + return implementation.getField(name) + } + + /** + * Types/functions that you want to additionally import in the file with the implementation class. + * + * This is useful if, for example, default values of fields reference classes or functions from other packages. + * + * Note that classes referenced in field types will be imported automatically. + */ + fun additionalImports(vararg importables: Importable) { + importables.forEach { implementation.usedTypes += it } + } + + /** + * Makes the specified fields in the implementation class mutable + * (even if they were not configured as mutable in the element configurator). + */ + fun isMutable(vararg fields: String) { + fields.forEach { + val field = getField(it) + field.isMutable = true + } + } + + /** + * Makes the specified fields in the implementation class `lateinit` + * (even if they were not configured as `lateinit` in the element configurator). + */ + fun isLateinit(vararg fields: String) { + fields.forEach { + val field = getField(it) + field.isLateinit = true + } + } + + /** + * Specifies the default value of [field] in this implementation class. The default value can be arbitrary code. + * + * Use [additionalImports] if the default value uses types/functions that are not otherwise imported. + */ + fun default(field: String, value: String) { + default(field) { + this.value = value + } + } + + /** + * Specifies that the default value of each field of [fields] in this implementation class should be `true`. + * + * If [withGetter] is `true`, the fields will be generated as getter-only computed properties with their getter returning `true`, + * otherwise, as stored properties initialized to `true`. + */ + fun defaultTrue(vararg fields: String, withGetter: Boolean = false) { + for (field in fields) { + default(field) { + value = "true" + this.withGetter = withGetter + } + } + } + + /** + * Specifies that the default value of each field of [fields] in this implementation class should be `false`. + * + * If [withGetter] is `true`, the fields will be generated as getter-only computed properties with their getter returning `false`, + * otherwise, as stored properties initialized to `false`. + */ + fun defaultFalse(vararg fields: String, withGetter: Boolean = false) { + for (field in fields) { + default(field) { + value = "false" + this.withGetter = withGetter + } + } + } + + /** + * Specifies that the default value of each field of [fields] in this implementation class should be `null`. + * + * If [withGetter] is `true`, the fields will be generated as getter-only computed properties with their getter returning `null`, + * otherwise, as stored properties initialized to `null`. + */ + fun defaultNull(vararg fields: String, withGetter: Boolean = false) { + for (field in fields) { + default(field) { + value = "null" + this.withGetter = withGetter + } + require(getField(field).nullable) { + "$field is not nullable field" + } + } + } + + /** + * Specifies that the default value of each field of [fields] in this implementation class should be [emptyList]. + * + * Always forces generation of a getter-only computed property. + */ + fun defaultEmptyList(vararg fields: String) { + for (field in fields) { + require(getField(field).origin is ListField) { + "$field is list field" + } + default(field) { + value = "emptyList()" + withGetter = true + } + } + } + + /** + * Allows to configure the default value of [field] in this implementation class. + * + * See the [DefaultValueContext] documentation for description of its DSL methods. + */ + fun default(field: String, init: DefaultValueContext.() -> Unit) { + DefaultValueContext(getField(field)).apply(init).applyConfiguration() + } + + /** + * Specifies that for each field in the [fields] list its getter should be delegated to the [delegate]'s property of the same name. + * + * For example, `delegateFields(listOf("foo", "bar"), "myDelegate")` will result in generating the following properties in + * the implementation class (provided that there are fields with names "foo" and "bar" in this implementation): + * ```kotlin + * val foo: Foo + * get() = myDelegate.foo + * + * val bar: Bar + * get() = myDelegate.bar + * ``` + */ + fun delegateFields(fields: List, delegate: String) { + for (field in fields) { + default(field) { + this.delegate = delegate + } + } + } + + /** + * Allows to customize this implementation class's kind (`open class`, `object` etc.). + * + * If set to `null`, will be chosen automatically by [InterfaceAndAbstractClassConfigurator]. + */ + var kind: ImplementationKind? + get() = implementation.kind + set(value) { + implementation.kind = value + } + + /** + * A DSL for configuring a field's default value. + */ + inner class DefaultValueContext(private val field: ImplementationField) { + + /** + * The default value of this field in the implementation class. Can be arbitrary code. + * + * Use [additionalImports] if the default value uses types/functions that are not otherwise imported. + */ + var value: String? = null + + /** + * The name of the field to which to delegate this field's getter. + * + * For example, setting [delegate] to `"myDelegate"` will result in generating the following in + * the implementation class (provided that we're configuring the field `foo`): + * ```kotlin + * val foo: Foo + * get() = myDelegate.foo + * ``` + * + * If [delegateCall] is not null, then instead of calling `foo` on `myDelegate`, the value of [delegateCall] will be used to + * generate the call. + */ + var delegate: String? = null + set(value) { + field = value + if (value != null) { + withGetter = true + } + } + + /** + * If [delegate] is not null, allows to specify a call that will be generated on [delegate]. + * + * For example, setting [delegate] to `"myDelegate"` and [delegateCall] to `"getFoo()"` will result in generating the following + * in the implementation class (provided that we're configuring the field `foo`): + * ```kotlin + * val foo: Foo + * get() = myDelegate.getFoo() + * ``` + * + * If [delegate] is `null`, setting this property has no effect. + */ + var delegateCall: String? = null + + /** + * Forces the specified mutability on this field in the implementation class. + * + * If set to `null`, the mutability specified in the element configurator will be used. + */ + var isMutable: Boolean? = null + + /** + * If `true`, the field will be generated as a computed property instead of stored one. + */ + var withGetter: Boolean = false + set(value) { + field = value + if (value) { + isMutable = customSetter != null + } + } + + /** + * Specifies the value of this field's setter. + * + * If set to a non-null value, the generated property is automatically made mutable and computed. + * + * Can be arbitrary code. Use [additionalImports] if this code uses types/functions that are not otherwise imported. + */ + var customSetter: String? = null + set(value) { + field = value + isMutable = true + withGetter = true + } + + /** + * Allows to exclude this field from visiting it by visitors in the generated `acceptChildren` and `transformChildren` + * methods. + */ + var needAcceptAndTransform: Boolean = true + + fun applyConfiguration() { + field.withGetter = withGetter + field.customSetter = customSetter + isMutable?.let { field.isMutable = it } + field.needAcceptAndTransform = needAcceptAndTransform + + when { + value != null -> field.defaultValueInImplementation = value + delegate != null -> { + val actualDelegateField = getField(delegate!!) + val name = delegateCall ?: field.name + field.defaultValueInImplementation = "${actualDelegateField.name}${actualDelegateField.call()}$name" + } + } + } + } + } +} diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/printer/printUtils.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/printer/printUtils.kt index ec630a40015..641bf0de2a2 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/printer/printUtils.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/printer/printUtils.kt @@ -85,7 +85,7 @@ fun SmartPrinter.printKDoc(kDoc: String?) { println(" */") } -fun AbstractElement<*, *>.extendedKDoc(defaultKDoc: String? = null): String = buildString { +fun AbstractElement<*, *, *>.extendedKDoc(defaultKDoc: String? = null): String = buildString { val doc = kDoc ?: defaultKDoc if (doc != null) { appendLine(doc) @@ -201,7 +201,7 @@ private val dataParameter = FunctionParameter("data", dataTP) context(ImportCollector) fun SmartPrinter.printAcceptMethod( - element: AbstractElement<*, *>, + element: AbstractElement<*, *, *>, visitorClass: ClassRef, hasImplementation: Boolean, treeName: String, @@ -239,7 +239,7 @@ fun SmartPrinter.printAcceptMethod( context(ImportCollector) fun SmartPrinter.printTransformMethod( - element: AbstractElement<*, *>, + element: AbstractElement<*, *, *>, transformerClass: ClassRef, implementation: String?, returnType: TypeRefWithNullability, @@ -347,3 +347,5 @@ fun SmartPrinter.printTransformChildrenMethod( override = override, ) } + +fun AbstractField<*>.call(): String = if (nullable) "?." else "." diff --git a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/utils.kt b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/utils.kt index 4a89b5b9d7d..b4b8f1f1588 100644 --- a/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/utils.kt +++ b/generators/tree-generator-common/src/org/jetbrains/kotlin/generators/tree/utils.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.generators.tree /** * Runs [block] on this element and all its parents recursively. */ -fun > Element.traverseParents(block: (Element) -> Unit) { +fun > Element.traverseParents(block: (Element) -> Unit) { traverseParentsUntil { block(it); false } } @@ -19,7 +19,7 @@ fun > Element.traverseParents(block: (Elem * * If [block] always returns `false`, visits all the parents and returns `false`. */ -fun > Element.traverseParentsUntil(block: (Element) -> Boolean): Boolean { +fun > Element.traverseParentsUntil(block: (Element) -> Boolean): Boolean { if (block(this)) return true for (parent in elementParents) { if (parent.element.traverseParentsUntil(block)) return true @@ -32,13 +32,13 @@ fun > Element.traverseParentsUntil(block: * a type of a field, except when that field is explicitly opted out of it via * [AbstractField.useInBaseTransformerDetection]. */ -fun > detectBaseTransformerTypes(model: Model) { - val usedAsFieldType = hashSetOf>() +fun > detectBaseTransformerTypes(model: Model) { + val usedAsFieldType = hashSetOf>() for (element in model.elements) { for (field in element.allFields.filter { it.containsElement }) { if (!field.useInBaseTransformerDetection) continue - val fieldElement = (field.typeRef as? ElementOrRef<*, *>)?.element - ?: ((field as? ListField)?.baseType as? ElementOrRef<*, *>)?.element + val fieldElement = (field.typeRef as? ElementOrRef<*>)?.element + ?: ((field as? ListField)?.baseType as? ElementOrRef<*>)?.element ?: continue if (fieldElement.isRootElement) continue usedAsFieldType.add(fieldElement)