[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`).
This commit is contained in:
committed by
Space Team
parent
85cff98a38
commit
91b5a71f1a
+33
-38
@@ -10,13 +10,8 @@ import org.jetbrains.kotlin.generators.tree.ImplementationKind.Object
|
|||||||
import org.jetbrains.kotlin.generators.tree.ImplementationKind.OpenClass
|
import org.jetbrains.kotlin.generators.tree.ImplementationKind.OpenClass
|
||||||
|
|
||||||
object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() {
|
object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() {
|
||||||
fun configureImplementations() {
|
|
||||||
configure()
|
|
||||||
generateDefaultImplementations(FirTreeBuilder)
|
|
||||||
configureAllImplementations()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun configure() = with(FirTreeBuilder) {
|
override fun configure() = with(FirTreeBuilder) {
|
||||||
impl(constructor) {
|
impl(constructor) {
|
||||||
defaultFalse("isPrimary", withGetter = true)
|
defaultFalse("isPrimary", withGetter = true)
|
||||||
}
|
}
|
||||||
@@ -87,7 +82,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
value = "annotationTypeRef.coneTypeOrNull"
|
value = "annotationTypeRef.coneTypeOrNull"
|
||||||
withGetter = true
|
withGetter = true
|
||||||
}
|
}
|
||||||
useTypes(coneTypeOrNullImport)
|
additionalImports(coneTypeOrNullImport)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(annotation) {
|
impl(annotation) {
|
||||||
@@ -117,7 +112,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(componentCall) {
|
impl(componentCall) {
|
||||||
default("calleeReference", "FirSimpleNamedReference(source, Name.identifier(\"component\$componentIndex\"))")
|
default("calleeReference", "FirSimpleNamedReference(source, Name.identifier(\"component\$componentIndex\"))")
|
||||||
useTypes(simpleNamedReferenceType, nameType)
|
additionalImports(simpleNamedReferenceType, nameType)
|
||||||
optInToInternals()
|
optInToInternals()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +125,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
value = "!isThis"
|
value = "!isThis"
|
||||||
withGetter = true
|
withGetter = true
|
||||||
}
|
}
|
||||||
useTypes(explicitThisReferenceType, explicitSuperReferenceType)
|
additionalImports(explicitThisReferenceType, explicitSuperReferenceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(multiDelegatedConstructorCall) {
|
impl(multiDelegatedConstructorCall) {
|
||||||
@@ -204,7 +199,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(expression, "FirElseIfTrueCondition") {
|
impl(expression, "FirElseIfTrueCondition") {
|
||||||
defaultBuiltInType("Boolean")
|
defaultBuiltInType("Boolean")
|
||||||
useTypes(implicitBooleanTypeRefType)
|
additionalImports(implicitBooleanTypeRefType)
|
||||||
publicImplementation()
|
publicImplementation()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +236,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
impl(errorLoop) {
|
impl(errorLoop) {
|
||||||
default("block", "FirEmptyExpressionBlock()")
|
default("block", "FirEmptyExpressionBlock()")
|
||||||
default("condition", "FirErrorExpressionImpl(source, MutableOrEmptyList.empty(), ConeStubDiagnostic(diagnostic), null, null)")
|
default("condition", "FirErrorExpressionImpl(source, MutableOrEmptyList.empty(), ConeStubDiagnostic(diagnostic), null, null)")
|
||||||
useTypes(emptyExpressionBlock, coneStubDiagnosticType)
|
additionalImports(emptyExpressionBlock, coneStubDiagnosticType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(expression, "FirExpressionStub") {
|
impl(expression, "FirExpressionStub") {
|
||||||
@@ -291,7 +286,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
withGetter = true
|
withGetter = true
|
||||||
}
|
}
|
||||||
|
|
||||||
useTypes(backingFieldSymbolType, delegateFieldSymbolType)
|
additionalImports(backingFieldSymbolType, delegateFieldSymbolType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(errorProperty) {
|
impl(errorProperty) {
|
||||||
@@ -306,7 +301,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
withGetter = true
|
withGetter = true
|
||||||
)
|
)
|
||||||
default("returnTypeRef", "FirErrorTypeRefImpl(null, MutableOrEmptyList.empty(), null, null, diagnostic)")
|
default("returnTypeRef", "FirErrorTypeRefImpl(null, MutableOrEmptyList.empty(), null, null, diagnostic)")
|
||||||
useTypes(errorTypeRefImplType)
|
additionalImports(errorTypeRefImplType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(field) {
|
impl(field) {
|
||||||
@@ -357,7 +352,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(comparisonExpression) {
|
impl(comparisonExpression) {
|
||||||
default("coneTypeOrNull", "StandardClassIds.Boolean.constructClassLikeType()")
|
default("coneTypeOrNull", "StandardClassIds.Boolean.constructClassLikeType()")
|
||||||
useTypes(standardClassIdsType, constructClassLikeTypeImport)
|
additionalImports(standardClassIdsType, constructClassLikeTypeImport)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(typeOperatorCall) {
|
impl(typeOperatorCall) {
|
||||||
@@ -370,7 +365,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(equalityOperatorCall) {
|
impl(equalityOperatorCall) {
|
||||||
default("coneTypeOrNull", "StandardClassIds.Boolean.constructClassLikeType()")
|
default("coneTypeOrNull", "StandardClassIds.Boolean.constructClassLikeType()")
|
||||||
useTypes(standardClassIdsType, constructClassLikeTypeImport)
|
additionalImports(standardClassIdsType, constructClassLikeTypeImport)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(resolvedQualifier) {
|
impl(resolvedQualifier) {
|
||||||
@@ -382,17 +377,17 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(returnExpression) {
|
impl(returnExpression) {
|
||||||
defaultBuiltInType("Nothing")
|
defaultBuiltInType("Nothing")
|
||||||
useTypes(implicitNothingTypeRefType)
|
additionalImports(implicitNothingTypeRefType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(stringConcatenationCall) {
|
impl(stringConcatenationCall) {
|
||||||
defaultBuiltInType("String")
|
defaultBuiltInType("String")
|
||||||
useTypes(implicitStringTypeRefType)
|
additionalImports(implicitStringTypeRefType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(throwExpression) {
|
impl(throwExpression) {
|
||||||
defaultBuiltInType("Nothing")
|
defaultBuiltInType("Nothing")
|
||||||
useTypes(implicitNothingTypeRefType)
|
additionalImports(implicitNothingTypeRefType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(thisReceiverExpression) {
|
impl(thisReceiverExpression) {
|
||||||
@@ -401,7 +396,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(expression, "FirUnitExpression") {
|
impl(expression, "FirUnitExpression") {
|
||||||
defaultBuiltInType("Unit")
|
defaultBuiltInType("Unit")
|
||||||
useTypes(implicitUnitTypeRefType)
|
additionalImports(implicitUnitTypeRefType)
|
||||||
publicImplementation()
|
publicImplementation()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +414,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
value = "!isGetter"
|
value = "!isGetter"
|
||||||
withGetter = true
|
withGetter = true
|
||||||
}
|
}
|
||||||
useTypes(modalityType)
|
additionalImports(modalityType)
|
||||||
kind = OpenClass
|
kind = OpenClass
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,12 +427,12 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
value = "whenRef.value.subject?.coneTypeOrNull ?: StandardClassIds.Unit.constructClassLikeType()"
|
value = "whenRef.value.subject?.coneTypeOrNull ?: StandardClassIds.Unit.constructClassLikeType()"
|
||||||
withGetter = true
|
withGetter = true
|
||||||
}
|
}
|
||||||
useTypes(whenExpression, standardClassIdsType, constructClassLikeTypeImport)
|
additionalImports(whenExpression, standardClassIdsType, constructClassLikeTypeImport)
|
||||||
useTypes(standardClassIdsType, constructClassLikeTypeImport)
|
additionalImports(standardClassIdsType, constructClassLikeTypeImport)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(desugaredAssignmentValueReferenceExpression) {
|
impl(desugaredAssignmentValueReferenceExpression) {
|
||||||
useTypes(expression)
|
additionalImports(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(wrappedDelegateExpression) {
|
impl(wrappedDelegateExpression) {
|
||||||
@@ -450,7 +445,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
noSource()
|
noSource()
|
||||||
default("coneTypeOrNull") {
|
default("coneTypeOrNull") {
|
||||||
value = "enumClassId.toLookupTag().constructClassType(emptyArray(), false)"
|
value = "enumClassId.toLookupTag().constructClassType(emptyArray(), false)"
|
||||||
useTypes(toLookupTagImport, constructClassTypeImport)
|
additionalImports(toLookupTagImport, constructClassTypeImport)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,7 +457,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
default("source") {
|
default("source") {
|
||||||
value = "originalExpression.source?.fakeElement(KtFakeSourceElementKind.SmartCastExpression)"
|
value = "originalExpression.source?.fakeElement(KtFakeSourceElementKind.SmartCastExpression)"
|
||||||
}
|
}
|
||||||
useTypes(fakeElementImport, fakeSourceElementKindImport)
|
additionalImports(fakeElementImport, fakeSourceElementKindImport)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(resolvedNamedReference)
|
impl(resolvedNamedReference)
|
||||||
@@ -528,18 +523,18 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(errorExpression) {
|
impl(errorExpression) {
|
||||||
default("coneTypeOrNull", "ConeErrorType(ConeStubDiagnostic(diagnostic))")
|
default("coneTypeOrNull", "ConeErrorType(ConeStubDiagnostic(diagnostic))")
|
||||||
useTypes(coneErrorTypeType, coneStubDiagnosticType)
|
additionalImports(coneErrorTypeType, coneStubDiagnosticType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(qualifiedErrorAccessExpression) {
|
impl(qualifiedErrorAccessExpression) {
|
||||||
default("coneTypeOrNull", "ConeErrorType(ConeStubDiagnostic(diagnostic))")
|
default("coneTypeOrNull", "ConeErrorType(ConeStubDiagnostic(diagnostic))")
|
||||||
useTypes(coneErrorTypeType, coneStubDiagnosticType)
|
additionalImports(coneErrorTypeType, coneStubDiagnosticType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(errorFunction) {
|
impl(errorFunction) {
|
||||||
defaultNull("receiverParameter", "body", withGetter = true)
|
defaultNull("receiverParameter", "body", withGetter = true)
|
||||||
default("returnTypeRef", "FirErrorTypeRefImpl(null, MutableOrEmptyList.empty(), null, null, diagnostic)")
|
default("returnTypeRef", "FirErrorTypeRefImpl(null, MutableOrEmptyList.empty(), null, null, diagnostic)")
|
||||||
useTypes(errorTypeRefImplType)
|
additionalImports(errorTypeRefImplType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(functionTypeRef)
|
impl(functionTypeRef)
|
||||||
@@ -561,12 +556,12 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
|
|
||||||
impl(breakExpression) {
|
impl(breakExpression) {
|
||||||
defaultBuiltInType("Nothing")
|
defaultBuiltInType("Nothing")
|
||||||
useTypes(implicitNothingTypeRefType)
|
additionalImports(implicitNothingTypeRefType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(continueExpression) {
|
impl(continueExpression) {
|
||||||
defaultBuiltInType("Nothing")
|
defaultBuiltInType("Nothing")
|
||||||
useTypes(implicitNothingTypeRefType)
|
additionalImports(implicitNothingTypeRefType)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(valueParameter) {
|
impl(valueParameter) {
|
||||||
@@ -582,11 +577,11 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
impl(simpleFunction)
|
impl(simpleFunction)
|
||||||
|
|
||||||
impl(safeCallExpression) {
|
impl(safeCallExpression) {
|
||||||
useTypes(checkedSafeCallSubject)
|
additionalImports(checkedSafeCallSubject)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(checkedSafeCallSubject) {
|
impl(checkedSafeCallSubject) {
|
||||||
useTypes(expression)
|
additionalImports(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(resolvedQualifier) {
|
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
|
// If this `FirResolvedQualifier` is a receiver expression of some other qualified access, the value is updated in
|
||||||
// `FirCallResolver` according to the resolution result.
|
// `FirCallResolver` according to the resolution result.
|
||||||
default("resolvedToCompanionObject", "(symbol?.fir as? FirRegularClass)?.companionObjectSymbol != null")
|
default("resolvedToCompanionObject", "(symbol?.fir as? FirRegularClass)?.companionObjectSymbol != null")
|
||||||
useTypes(regularClass)
|
additionalImports(regularClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl(errorResolvedQualifier) {
|
impl(errorResolvedQualifier) {
|
||||||
@@ -637,7 +632,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters }
|
implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters }
|
||||||
) {
|
) {
|
||||||
default(it, "FirResolvedDeclarationStatusImpl.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS")
|
default(it, "FirResolvedDeclarationStatusImpl.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS")
|
||||||
useTypes(resolvedDeclarationStatusImplType)
|
additionalImports(resolvedDeclarationStatusImplType)
|
||||||
}
|
}
|
||||||
|
|
||||||
configureFieldInAllImplementations(
|
configureFieldInAllImplementations(
|
||||||
@@ -645,11 +640,11 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters }
|
implementationPredicate = { it.typeName in implementationsWithoutStatusAndTypeParameters }
|
||||||
) {
|
) {
|
||||||
defaultEmptyList(it)
|
defaultEmptyList(it)
|
||||||
useTypes(resolvedDeclarationStatusImplType)
|
additionalImports(resolvedDeclarationStatusImplType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureAllImplementations() {
|
override fun configureAllImplementations() {
|
||||||
configureFieldInAllImplementations(
|
configureFieldInAllImplementations(
|
||||||
field = "controlFlowGraphReference",
|
field = "controlFlowGraphReference",
|
||||||
implementationPredicate = { it.typeName != "FirAnonymousFunctionImpl" }
|
implementationPredicate = { it.typeName != "FirAnonymousFunctionImpl" }
|
||||||
@@ -688,7 +683,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
fieldPredicate = { it.defaultValueInImplementation == null }
|
fieldPredicate = { it.defaultValueInImplementation == null }
|
||||||
) {
|
) {
|
||||||
default(it, "FirImplicitTypeRefImplWithoutSource")
|
default(it, "FirImplicitTypeRefImplWithoutSource")
|
||||||
useTypes(firImplicitTypeWithoutSourceType)
|
additionalImports(firImplicitTypeWithoutSourceType)
|
||||||
}
|
}
|
||||||
|
|
||||||
configureFieldInAllImplementations(
|
configureFieldInAllImplementations(
|
||||||
@@ -697,7 +692,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
|||||||
fieldPredicate = { it.defaultValueInImplementation == null }
|
fieldPredicate = { it.defaultValueInImplementation == null }
|
||||||
) {
|
) {
|
||||||
default(it, "FirImplicitTypeRefImplWithoutSource")
|
default(it, "FirImplicitTypeRefImplWithoutSource")
|
||||||
useTypes(firImplicitTypeWithoutSourceType)
|
additionalImports(firImplicitTypeWithoutSourceType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -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.context.AbstractFirTreeBuilder
|
||||||
import org.jetbrains.kotlin.fir.tree.generator.printer.generateElements
|
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.Model
|
||||||
import org.jetbrains.kotlin.generators.tree.detectBaseTransformerTypes
|
|
||||||
import org.jetbrains.kotlin.generators.tree.addPureAbstractElement
|
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
|
||||||
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.collectPreviouslyGeneratedFiles
|
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.collectPreviouslyGeneratedFiles
|
||||||
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.removeExtraFilesFromPreviousGeneration
|
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil.removeExtraFilesFromPreviousGeneration
|
||||||
@@ -24,8 +24,9 @@ fun main(args: Array<String>) {
|
|||||||
NodeConfigurator.configureFields()
|
NodeConfigurator.configureFields()
|
||||||
val model = Model(FirTreeBuilder.elements, AbstractFirTreeBuilder.baseFirElement)
|
val model = Model(FirTreeBuilder.elements, AbstractFirTreeBuilder.baseFirElement)
|
||||||
detectBaseTransformerTypes(model)
|
detectBaseTransformerTypes(model)
|
||||||
ImplementationConfigurator.configureImplementations()
|
ImplementationConfigurator.configureImplementations(model)
|
||||||
FirInterfaceAndAbstractClassConfigurator(FirTreeBuilder).configureInterfacesAndAbstractClasses()
|
InterfaceAndAbstractClassConfigurator((model.elements + model.elements.flatMap { it.allImplementations }))
|
||||||
|
.configureInterfacesAndAbstractClasses()
|
||||||
addPureAbstractElement(FirTreeBuilder.elements, pureAbstractElementType)
|
addPureAbstractElement(FirTreeBuilder.elements, pureAbstractElementType)
|
||||||
BuilderConfigurator.configureBuilders()
|
BuilderConfigurator.configureBuilders()
|
||||||
val previouslyGeneratedFiles = collectPreviouslyGeneratedFiles(generationPath)
|
val previouslyGeneratedFiles = collectPreviouslyGeneratedFiles(generationPath)
|
||||||
@@ -33,4 +34,3 @@ fun main(args: Array<String>) {
|
|||||||
generatedFiles.forEach { GeneratorsFileUtil.writeFileIfContentChanged(it.file, it.newText, logNotChanged = false) }
|
generatedFiles.forEach { GeneratorsFileUtil.writeFileIfContentChanged(it.file, it.newText, logNotChanged = false) }
|
||||||
removeExtraFilesFromPreviousGeneration(previouslyGeneratedFiles, generatedFiles.map { it.file })
|
removeExtraFilesFromPreviousGeneration(previouslyGeneratedFiles, generatedFiles.map { it.file })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-211
@@ -6,223 +6,29 @@
|
|||||||
package org.jetbrains.kotlin.fir.tree.generator.context
|
package org.jetbrains.kotlin.fir.tree.generator.context
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.tree.generator.constructClassLikeTypeImport
|
import org.jetbrains.kotlin.fir.tree.generator.constructClassLikeTypeImport
|
||||||
import org.jetbrains.kotlin.fir.tree.generator.model.*
|
import org.jetbrains.kotlin.fir.tree.generator.model.Element
|
||||||
import org.jetbrains.kotlin.fir.tree.generator.printer.call
|
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.fir.tree.generator.standardClassIdsType
|
||||||
import org.jetbrains.kotlin.generators.tree.ImplementationKind
|
import org.jetbrains.kotlin.generators.tree.config.AbstractImplementationConfigurator
|
||||||
import org.jetbrains.kotlin.generators.tree.Importable
|
|
||||||
|
|
||||||
abstract class AbstractFirTreeImplementationConfigurator {
|
abstract class AbstractFirTreeImplementationConfigurator : AbstractImplementationConfigurator<Implementation, Element, FieldWithDefault>() {
|
||||||
private val elementsWithImpl = mutableSetOf<Element>()
|
|
||||||
|
|
||||||
fun noImpl(element: Element) {
|
final override fun createImplementation(element: Element, name: String?) = Implementation(element, name)
|
||||||
element.doesNotNeedImplementation = true
|
|
||||||
|
protected fun ImplementationContext.defaultNoReceivers() {
|
||||||
|
defaultNull("explicitReceiver", "dispatchReceiver", "extensionReceiver")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun impl(element: Element, name: String? = null, config: ImplementationContext.() -> Unit = {}): Implementation {
|
protected fun ImplementationContext.defaultBuiltInType(type: String) {
|
||||||
val implementation = if (name == null) {
|
default("coneTypeOrNull") {
|
||||||
element.defaultImplementation
|
value = "StandardClassIds.$type.constructClassLikeType()"
|
||||||
} else {
|
isMutable = false
|
||||||
element.customImplementations.firstOrNull { it.name == name }
|
}
|
||||||
} ?: Implementation(element, name)
|
additionalImports(standardClassIdsType, constructClassLikeTypeImport)
|
||||||
val context = ImplementationContext(implementation)
|
|
||||||
context.apply(config)
|
|
||||||
elementsWithImpl += element
|
|
||||||
return implementation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun generateDefaultImplementations(builder: AbstractFirTreeBuilder) {
|
protected fun ImplementationContext.noSource() {
|
||||||
collectLeafsWithoutImplementation(builder).forEach {
|
defaultNull("source", withGetter = true)
|
||||||
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<Element> {
|
|
||||||
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<String>, 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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-17
@@ -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.ElementOrRef as GenericElementOrRef
|
||||||
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
|
import org.jetbrains.kotlin.generators.tree.ElementRef as GenericElementRef
|
||||||
|
|
||||||
class Element(name: String, override val propertyName: String, kind: Kind) : AbstractElement<Element, Field>(name) {
|
class Element(name: String, override val propertyName: String, kind: Kind) : AbstractElement<Element, Field, Implementation>(name) {
|
||||||
companion object {
|
companion object {
|
||||||
private val allowedKinds = setOf(
|
private val allowedKinds = setOf(
|
||||||
ImplementationKind.Interface,
|
ImplementationKind.Interface,
|
||||||
@@ -41,9 +41,6 @@ class Element(name: String, override val propertyName: String, kind: Kind) : Abs
|
|||||||
|
|
||||||
override val otherParents = mutableListOf<ClassRef<*>>()
|
override val otherParents = mutableListOf<ClassRef<*>>()
|
||||||
|
|
||||||
var defaultImplementation: Implementation? = null
|
|
||||||
val customImplementations = mutableListOf<Implementation>()
|
|
||||||
|
|
||||||
override val params = mutableListOf<TypeVariable>()
|
override val params = mutableListOf<TypeVariable>()
|
||||||
|
|
||||||
override var kind: ImplementationKind? = null
|
override var kind: ImplementationKind? = null
|
||||||
@@ -76,18 +73,7 @@ class Element(name: String, override val propertyName: String, kind: Kind) : Abs
|
|||||||
override val visitorParameterName: String
|
override val visitorParameterName: String
|
||||||
get() = safeDecapitalizedName
|
get() = safeDecapitalizedName
|
||||||
|
|
||||||
var doesNotNeedImplementation: Boolean = false
|
|
||||||
|
|
||||||
val needTransformOtherChildren: Boolean get() = _needTransformOtherChildren || elementParents.any { it.element.needTransformOtherChildren }
|
val needTransformOtherChildren: Boolean get() = _needTransformOtherChildren || elementParents.any { it.element.needTransformOtherChildren }
|
||||||
val allImplementations: List<Implementation> by lazy {
|
|
||||||
if (doesNotNeedImplementation) {
|
|
||||||
emptyList()
|
|
||||||
} else {
|
|
||||||
val implementations = customImplementations.toMutableList()
|
|
||||||
defaultImplementation?.let { implementations += it }
|
|
||||||
implementations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return with(ImportCollector("")) { render() }
|
return with(ImportCollector("")) { render() }
|
||||||
@@ -104,6 +90,6 @@ class Element(name: String, override val propertyName: String, kind: Kind) : Abs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias ElementRef = GenericElementRef<Element, Field>
|
typealias ElementRef = GenericElementRef<Element>
|
||||||
|
|
||||||
typealias ElementOrRef = GenericElementOrRef<Element, Field>
|
typealias ElementOrRef = GenericElementOrRef<Element>
|
||||||
|
|||||||
+1
-3
@@ -31,8 +31,6 @@ sealed class Field : AbstractField<Field>() {
|
|||||||
|
|
||||||
abstract override var isFinal: Boolean
|
abstract override var isFinal: Boolean
|
||||||
|
|
||||||
abstract override var isLateinit: Boolean
|
|
||||||
|
|
||||||
abstract override var isParameter: Boolean
|
abstract override var isParameter: Boolean
|
||||||
|
|
||||||
abstract override var isMutable: Boolean
|
abstract override var isMutable: Boolean
|
||||||
@@ -69,7 +67,7 @@ sealed class Field : AbstractField<Field>() {
|
|||||||
|
|
||||||
// ----------- Field with default -----------
|
// ----------- Field with default -----------
|
||||||
|
|
||||||
class FieldWithDefault(val origin: Field) : Field() {
|
class FieldWithDefault(override val origin: Field) : Field(), AbstractFieldWithDefaultValue<Field> {
|
||||||
override val name: String get() = origin.name
|
override val name: String get() = origin.name
|
||||||
override val typeRef: TypeRefWithNullability get() = origin.typeRef
|
override val typeRef: TypeRefWithNullability get() = origin.typeRef
|
||||||
override var isVolatile: Boolean = origin.isVolatile
|
override var isVolatile: Boolean = origin.isVolatile
|
||||||
|
|||||||
+1
-46
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.fir.tree.generator.model
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.generators.tree.*
|
import org.jetbrains.kotlin.generators.tree.*
|
||||||
|
|
||||||
class Implementation(val element: Element, val name: String?) : FieldContainer<FieldWithDefault>, ImplementationKindOwner {
|
class Implementation(element: Element, name: String?) : AbstractImplementation<Implementation, Element, FieldWithDefault>(element, name) {
|
||||||
override val allParents: List<ImplementationKindOwner> get() = listOf(element)
|
|
||||||
val isDefault = name == null
|
|
||||||
override val typeName = name ?: (element.typeName + "Impl")
|
|
||||||
|
|
||||||
override val allFields = element.allFields.toMutableList().mapTo(mutableListOf()) {
|
override val allFields = element.allFields.toMutableList().mapTo(mutableListOf()) {
|
||||||
FieldWithDefault(it)
|
FieldWithDefault(it)
|
||||||
@@ -28,49 +25,7 @@ class Implementation(val element: Element, val name: String?) : FieldContainer<F
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context(ImportCollector)
|
|
||||||
override fun renderTo(appendable: Appendable) {
|
|
||||||
addImport(this)
|
|
||||||
appendable.append(this.typeName)
|
|
||||||
if (element.params.isNotEmpty()) {
|
|
||||||
element.params.joinTo(appendable, prefix = "<", postfix = ">") { it.name }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun substitute(map: TypeParameterSubstitutionMap) = this
|
|
||||||
|
|
||||||
override val packageName = element.packageName + ".impl"
|
|
||||||
val usedTypes = mutableListOf<Importable>()
|
|
||||||
|
|
||||||
var isPublic = false
|
|
||||||
var requiresOptIn = false
|
|
||||||
var builder: LeafBuilder? = null
|
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
|
val ImplementationKind.hasLeafBuilder: Boolean
|
||||||
|
|||||||
+30
-77
@@ -25,10 +25,10 @@ fun Implementation.generateCode(generationPath: File): GeneratedFile =
|
|||||||
fileSuppressions = listOf("DuplicatedCode", "unused"),
|
fileSuppressions = listOf("DuplicatedCode", "unused"),
|
||||||
) {
|
) {
|
||||||
addAllImports(usedTypes)
|
addAllImports(usedTypes)
|
||||||
printImplementation(this@generateCode)
|
ImplementationPrinter(this).printImplementation(this@generateCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldPrinter<Field>(printer) {
|
private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldPrinter<FieldWithDefault>(printer) {
|
||||||
|
|
||||||
private fun Field.isMutableOrEmptyIfList(): Boolean = when (this) {
|
private fun Field.isMutableOrEmptyIfList(): Boolean = when (this) {
|
||||||
is FieldList -> isMutableOrEmptyList
|
is FieldList -> isMutableOrEmptyList
|
||||||
@@ -36,91 +36,44 @@ private class ImplementationFieldPrinter(printer: SmartPrinter) : AbstractFieldP
|
|||||||
else -> true
|
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)
|
private class ImplementationPrinter(
|
||||||
fun SmartPrinter.printImplementation(implementation: Implementation) {
|
printer: SmartPrinter
|
||||||
fun Field.transform() {
|
) : AbstractImplementationPrinter<Implementation, Element, FieldWithDefault>(printer) {
|
||||||
when (this) {
|
|
||||||
is FieldWithDefault -> origin.transform()
|
|
||||||
|
|
||||||
is FirField ->
|
override val implementationOptInAnnotation: ClassRef<*>
|
||||||
println("$name = ${name}${call()}transform(transformer, data)")
|
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) {
|
override fun makeFieldPrinter(printer: SmartPrinter) = ImplementationFieldPrinter(printer)
|
||||||
buildSet {
|
|
||||||
if (requiresOptIn) {
|
|
||||||
add(firImplementationDetailType)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (field in fieldsWithoutDefault) {
|
context(ImportCollector)
|
||||||
field.optInAnnotation?.let {
|
override fun SmartPrinter.printAdditionalMethods(implementation: Implementation) {
|
||||||
add(it)
|
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" }})")
|
|
||||||
}
|
}
|
||||||
|
with(implementation) {
|
||||||
if (!isPublic) {
|
val isInterface = kind == ImplementationKind.Interface || kind == ImplementationKind.SealedInterface
|
||||||
print("internal ")
|
val isAbstract = kind == ImplementationKind.AbstractClass || kind == ImplementationKind.SealedClass
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val bindingCalls = element.allFields.filter {
|
val bindingCalls = element.allFields.filter {
|
||||||
it.withBindThis && it.hasSymbolType && it !is FieldList && it.name != "companionObjectSymbol"
|
it.withBindThis && it.hasSymbolType && it !is FieldList && it.name != "companionObjectSymbol"
|
||||||
}.takeIf {
|
}.takeIf {
|
||||||
@@ -199,7 +152,7 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is FieldList -> {
|
is FieldList -> {
|
||||||
println("${field.name}.forEach { it.accept(visitor, data) }")
|
println(field.name, field.call(), "forEach { it.accept(visitor, data) }")
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
|
|||||||
-2
@@ -88,6 +88,4 @@ fun Field.getMutableType(forBuilder: Boolean = false): TypeRefWithNullability =
|
|||||||
else -> typeRef
|
else -> typeRef
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Field.call(): String = if (nullable) "?." else "."
|
|
||||||
|
|
||||||
val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" else name.replaceFirstChar(Char::lowercaseChar)
|
val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" else name.replaceFirstChar(Char::lowercaseChar)
|
||||||
|
|||||||
-19
@@ -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<ImplementationKindOwner>): Boolean =
|
|
||||||
element is Implementation && element !in allParents
|
|
||||||
}
|
|
||||||
|
|
||||||
+3
-6
@@ -18,7 +18,7 @@ class Element(
|
|||||||
name: String,
|
name: String,
|
||||||
override val propertyName: String,
|
override val propertyName: String,
|
||||||
category: Category,
|
category: Category,
|
||||||
) : AbstractElement<Element, Field>(name) {
|
) : AbstractElement<Element, Field, Nothing>(name) {
|
||||||
|
|
||||||
enum class Category(private val packageDir: String, val defaultVisitorParam: String) {
|
enum class Category(private val packageDir: String, val defaultVisitorParam: String) {
|
||||||
Expression("expressions", "expression"),
|
Expression("expressions", "expression"),
|
||||||
@@ -136,8 +136,8 @@ class Element(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias ElementRef = GenericElementRef<Element, Field>
|
typealias ElementRef = GenericElementRef<Element>
|
||||||
typealias ElementOrRef = GenericElementOrRef<Element, Field>
|
typealias ElementOrRef = GenericElementOrRef<Element>
|
||||||
|
|
||||||
sealed class Field(
|
sealed class Field(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
@@ -179,9 +179,6 @@ sealed class Field(
|
|||||||
override val isFinal: Boolean
|
override val isFinal: Boolean
|
||||||
get() = defaultValueInImplementation != null
|
get() = defaultValueInImplementation != null
|
||||||
|
|
||||||
override val isLateinit: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val isParameter: Boolean
|
override val isParameter: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
|
|||||||
+10
-18
@@ -75,14 +75,11 @@ private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter<Ele
|
|||||||
if (!element.isRootElement) {
|
if (!element.isRootElement) {
|
||||||
printBlock {
|
printBlock {
|
||||||
for (child in element.walkableChildren) {
|
for (child in element.walkableChildren) {
|
||||||
print(child.name)
|
print(child.name, child.call())
|
||||||
if (child.nullable) {
|
|
||||||
print("?")
|
|
||||||
}
|
|
||||||
when (child) {
|
when (child) {
|
||||||
is SingleField -> println(".accept(visitor, data)")
|
is SingleField -> println("accept(visitor, data)")
|
||||||
is ListField -> {
|
is ListField -> {
|
||||||
print(".forEach { it")
|
print("forEach { it")
|
||||||
if (child.baseType.nullable) {
|
if (child.baseType.nullable) {
|
||||||
print("?")
|
print("?")
|
||||||
}
|
}
|
||||||
@@ -109,12 +106,9 @@ private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter<Ele
|
|||||||
print(child.name)
|
print(child.name)
|
||||||
when (child) {
|
when (child) {
|
||||||
is SingleField -> {
|
is SingleField -> {
|
||||||
print(" = ", child.name)
|
print(" = ", child.name, child.call())
|
||||||
if (child.nullable) {
|
print("transform(transformer, data)")
|
||||||
print("?")
|
val elementRef = child.typeRef as GenericElementRef<*>
|
||||||
}
|
|
||||||
print(".transform(transformer, data)")
|
|
||||||
val elementRef = child.typeRef as GenericElementRef<*, *>
|
|
||||||
if (!elementRef.element.hasTransformMethod) {
|
if (!elementRef.element.hasTransformMethod) {
|
||||||
print(" as ", elementRef.render())
|
print(" as ", elementRef.render())
|
||||||
}
|
}
|
||||||
@@ -122,15 +116,13 @@ private class ElementPrinter(printer: SmartPrinter) : AbstractElementPrinter<Ele
|
|||||||
}
|
}
|
||||||
is ListField -> {
|
is ListField -> {
|
||||||
if (child.isMutable) {
|
if (child.isMutable) {
|
||||||
print(" = ", child.name)
|
print(" = ", child.name, child.call())
|
||||||
if (child.nullable) {
|
|
||||||
print("?")
|
|
||||||
}
|
|
||||||
addImport(transformIfNeeded)
|
addImport(transformIfNeeded)
|
||||||
println(".transformIfNeeded(transformer, data)")
|
println("transformIfNeeded(transformer, data)")
|
||||||
} else {
|
} else {
|
||||||
addImport(transformInPlace)
|
addImport(transformInPlace)
|
||||||
println(".transformInPlace(transformer, data)")
|
print(child.call())
|
||||||
|
println("transformInPlace(transformer, data)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-6
@@ -8,11 +8,12 @@ package org.jetbrains.kotlin.generators.tree
|
|||||||
/**
|
/**
|
||||||
* A class representing a FIR or IR tree element.
|
* A class representing a FIR or IR tree element.
|
||||||
*/
|
*/
|
||||||
abstract class AbstractElement<Element, Field>(
|
abstract class AbstractElement<Element, Field, Implementation>(
|
||||||
val name: String,
|
val name: String,
|
||||||
) : ElementOrRef<Element, Field>, FieldContainer<Field>, ImplementationKindOwner
|
) : ElementOrRef<Element>, FieldContainer<Field>, ImplementationKindOwner
|
||||||
where Element : AbstractElement<Element, Field>,
|
where Element : AbstractElement<Element, Field, Implementation>,
|
||||||
Field : AbstractField<Field> {
|
Field : AbstractField<Field>,
|
||||||
|
Implementation : AbstractImplementation<Implementation, Element, *> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The fully-qualified name of the property in the tree generator that is used to configure this element.
|
* 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<Element, Field>(
|
|||||||
|
|
||||||
abstract val params: List<TypeVariable>
|
abstract val params: List<TypeVariable>
|
||||||
|
|
||||||
abstract val elementParents: List<ElementRef<Element, Field>>
|
abstract val elementParents: List<ElementRef<Element>>
|
||||||
|
|
||||||
abstract val otherParents: MutableList<ClassRef<*>>
|
abstract val otherParents: MutableList<ClassRef<*>>
|
||||||
|
|
||||||
@@ -144,6 +145,22 @@ abstract class AbstractElement<Element, Field>(
|
|||||||
val transformerClass: Element
|
val transformerClass: Element
|
||||||
get() = transformerReturnType ?: baseTransformerType ?: element
|
get() = transformerReturnType ?: baseTransformerType ?: element
|
||||||
|
|
||||||
|
var defaultImplementation: Implementation? = null
|
||||||
|
|
||||||
|
val customImplementations = mutableListOf<Implementation>()
|
||||||
|
|
||||||
|
var doesNotNeedImplementation: Boolean = false
|
||||||
|
|
||||||
|
val allImplementations: List<Implementation> by lazy {
|
||||||
|
if (doesNotNeedImplementation) {
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
val implementations = customImplementations.toMutableList()
|
||||||
|
defaultImplementation?.let { implementations += it }
|
||||||
|
implementations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final override fun get(fieldName: String): Field? {
|
final override fun get(fieldName: String): Field? {
|
||||||
return allFields.firstOrNull { it.name == fieldName }
|
return allFields.firstOrNull { it.name == fieldName }
|
||||||
}
|
}
|
||||||
@@ -159,5 +176,5 @@ abstract class AbstractElement<Element, Field>(
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun substitute(map: TypeParameterSubstitutionMap): Element = this as Element
|
override fun substitute(map: TypeParameterSubstitutionMap): Element = this as Element
|
||||||
|
|
||||||
fun withStarArgs(): ElementRef<Element, Field> = copy(params.associateWith { TypeRef.Star })
|
fun withStarArgs(): ElementRef<Element> = copy(params.associateWith { TypeRef.Star })
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.utils.withIndent
|
|||||||
/**
|
/**
|
||||||
* A common class for printing FIR or IR tree elements.
|
* A common class for printing FIR or IR tree elements.
|
||||||
*/
|
*/
|
||||||
abstract class AbstractElementPrinter<Element : AbstractElement<Element, Field>, Field : AbstractField<Field>>(
|
abstract class AbstractElementPrinter<Element : AbstractElement<Element, Field, *>, Field : AbstractField<Field>>(
|
||||||
private val printer: SmartPrinter,
|
private val printer: SmartPrinter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -20,7 +20,7 @@ abstract class AbstractField<Field : AbstractField<Field>> {
|
|||||||
|
|
||||||
abstract val isFinal: Boolean
|
abstract val isFinal: Boolean
|
||||||
|
|
||||||
abstract val isLateinit: Boolean
|
open var isLateinit: Boolean = false
|
||||||
|
|
||||||
abstract val isParameter: Boolean
|
abstract val isParameter: Boolean
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ abstract class AbstractField<Field : AbstractField<Field>> {
|
|||||||
* Whether this field can contain an element either directly or e.g. in a list.
|
* Whether this field can contain an element either directly or e.g. in a list.
|
||||||
*/
|
*/
|
||||||
open val containsElement: Boolean
|
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
|
open val defaultValueInImplementation: String? get() = null
|
||||||
|
|
||||||
@@ -90,6 +90,7 @@ abstract class AbstractField<Field : AbstractField<Field>> {
|
|||||||
|
|
||||||
protected open fun updateFieldsInCopy(copy: Field) {
|
protected open fun updateFieldsInCopy(copy: Field) {
|
||||||
copy.kDoc = kDoc
|
copy.kDoc = kDoc
|
||||||
|
copy.isLateinit = isLateinit
|
||||||
copy.arbitraryImportables += arbitraryImportables
|
copy.arbitraryImportables += arbitraryImportables
|
||||||
copy.optInAnnotation = optInAnnotation
|
copy.optInAnnotation = optInAnnotation
|
||||||
copy.isMutable = isMutable
|
copy.isMutable = isMutable
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
|||||||
import org.jetbrains.kotlin.utils.SmartPrinter
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
import org.jetbrains.kotlin.utils.withIndent
|
import org.jetbrains.kotlin.utils.withIndent
|
||||||
|
|
||||||
abstract class AbstractFieldPrinter<Field : AbstractField<Field>>(
|
abstract class AbstractFieldPrinter<Field : AbstractField<*>>(
|
||||||
private val printer: SmartPrinter,
|
private val printer: SmartPrinter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|||||||
+14
@@ -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<OriginField : AbstractField<OriginField>> {
|
||||||
|
val origin: OriginField
|
||||||
|
var withGetter: Boolean
|
||||||
|
var customSetter: String?
|
||||||
|
var notNull: Boolean
|
||||||
|
var defaultValueInImplementation: String?
|
||||||
|
}
|
||||||
+74
@@ -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<Implementation, Element, Field>(
|
||||||
|
val element: Element,
|
||||||
|
val name: String?,
|
||||||
|
) : FieldContainer<Field>, ImplementationKindOwner
|
||||||
|
where Implementation : AbstractImplementation<Implementation, Element, Field>,
|
||||||
|
Element : AbstractElement<Element, *, Implementation>,
|
||||||
|
Field : AbstractField<*> {
|
||||||
|
|
||||||
|
private val isDefault: Boolean
|
||||||
|
get() = name == null
|
||||||
|
|
||||||
|
override val allParents: List<ImplementationKindOwner>
|
||||||
|
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<Importable>()
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
+101
@@ -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<Implementation, Element, ImplementationField>(
|
||||||
|
private val printer: SmartPrinter,
|
||||||
|
)
|
||||||
|
where Implementation : AbstractImplementation<Implementation, Element, ImplementationField>,
|
||||||
|
Element : AbstractElement<Element, *, Implementation>,
|
||||||
|
ImplementationField : AbstractField<*>,
|
||||||
|
ImplementationField : AbstractFieldWithDefaultValue<*> {
|
||||||
|
|
||||||
|
protected abstract val implementationOptInAnnotation: ClassRef<*>
|
||||||
|
|
||||||
|
protected abstract val pureAbstractElementType: ClassRef<*>
|
||||||
|
|
||||||
|
protected abstract fun makeFieldPrinter(printer: SmartPrinter): AbstractFieldPrinter<ImplementationField>
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.types.Variance
|
|||||||
import org.jetbrains.kotlin.utils.SmartPrinter
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
import org.jetbrains.kotlin.utils.withIndent
|
import org.jetbrains.kotlin.utils.withIndent
|
||||||
|
|
||||||
abstract class AbstractVisitorPrinter<Element : AbstractElement<Element, Field>, Field : AbstractField<Field>>(
|
abstract class AbstractVisitorPrinter<Element : AbstractElement<Element, Field, *>, Field : AbstractField<Field>>(
|
||||||
val printer: SmartPrinter,
|
val printer: SmartPrinter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.utils.SmartPrinter
|
|||||||
abstract class AbstractVisitorVoidPrinter<Element, Field>(
|
abstract class AbstractVisitorVoidPrinter<Element, Field>(
|
||||||
printer: SmartPrinter,
|
printer: SmartPrinter,
|
||||||
) : AbstractVisitorPrinter<Element, Field>(printer)
|
) : AbstractVisitorPrinter<Element, Field>(printer)
|
||||||
where Element : AbstractElement<Element, Field>,
|
where Element : AbstractElement<Element, Field, *>,
|
||||||
Field : AbstractField<Field> {
|
Field : AbstractField<Field> {
|
||||||
|
|
||||||
final override val visitorTypeParameters: List<TypeVariable>
|
final override val visitorTypeParameters: List<TypeVariable>
|
||||||
|
|||||||
+4
-6
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.generators.util.solveGraphForClassVsInterface
|
|||||||
*
|
*
|
||||||
* @property elements The list of elements of the tree to infer their [ImplementationKind].
|
* @property elements The list of elements of the tree to infer their [ImplementationKind].
|
||||||
*/
|
*/
|
||||||
open class InterfaceAndAbstractClassConfigurator(val elements: List<ImplementationKindOwner>) {
|
class InterfaceAndAbstractClassConfigurator(val elements: List<ImplementationKindOwner>) {
|
||||||
|
|
||||||
private inner class NodeImpl(val element: ImplementationKindOwner) : Node {
|
private inner class NodeImpl(val element: ImplementationKindOwner) : Node {
|
||||||
override val parents: List<NodeImpl>
|
override val parents: List<NodeImpl>
|
||||||
@@ -27,10 +27,8 @@ open class InterfaceAndAbstractClassConfigurator(val elements: List<Implementati
|
|||||||
override fun hashCode(): Int = element.hashCode()
|
override fun hashCode(): Int = element.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun shouldBeFinalClass(element: ImplementationKindOwner, allParents: Set<ImplementationKindOwner>): Boolean =
|
||||||
* If [element]'s kind was inferred as abstract class, allows to forcibly make that element a final class instead.
|
element is AbstractImplementation<*, *, *> && element !in allParents
|
||||||
*/
|
|
||||||
protected open fun shouldBeFinalClass(element: ImplementationKindOwner, allParents: Set<ImplementationKindOwner>): Boolean = false
|
|
||||||
|
|
||||||
private fun updateKinds(nodes: List<NodeImpl>, solution: List<Boolean>) {
|
private fun updateKinds(nodes: List<NodeImpl>, solution: List<Boolean>) {
|
||||||
val allParents = nodes.flatMapTo(mutableSetOf()) { element -> element.parents.map { it.origin.element } }
|
val allParents = nodes.flatMapTo(mutableSetOf()) { element -> element.parents.map { it.origin.element } }
|
||||||
@@ -59,7 +57,7 @@ open class InterfaceAndAbstractClassConfigurator(val elements: List<Implementati
|
|||||||
private fun updateSealedKinds(nodes: Collection<NodeImpl>) {
|
private fun updateSealedKinds(nodes: Collection<NodeImpl>) {
|
||||||
for (node in nodes) {
|
for (node in nodes) {
|
||||||
val element = node.element
|
val element = node.element
|
||||||
if (element is AbstractElement<*, *>) {
|
if (element is AbstractElement<*, *, *>) {
|
||||||
if (element.isSealed) {
|
if (element.isSealed) {
|
||||||
element.kind = when (element.kind) {
|
element.kind = when (element.kind) {
|
||||||
ImplementationKind.AbstractClass -> ImplementationKind.SealedClass
|
ImplementationKind.AbstractClass -> ImplementationKind.SealedClass
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.generators.tree
|
package org.jetbrains.kotlin.generators.tree
|
||||||
|
|
||||||
data class Model<Element : AbstractElement<Element, *>>(
|
data class Model<Element : AbstractElement<Element, *, *>>(
|
||||||
val elements: List<Element>,
|
val elements: List<Element>,
|
||||||
val rootElement: Element,
|
val rootElement: Element,
|
||||||
)
|
)
|
||||||
|
|||||||
+7
-8
@@ -128,19 +128,18 @@ data class TypeRefWithVariance<out T : TypeRef>(val variance: Variance, val type
|
|||||||
TypeRefWithVariance(variance, typeRef.substitute(map))
|
TypeRefWithVariance(variance, typeRef.substitute(map))
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ElementOrRef<Element, Field> : ParametrizedTypeRef<ElementOrRef<Element, Field>, NamedTypeParameterRef>, ClassOrElementRef
|
interface ElementOrRef<Element> : ParametrizedTypeRef<ElementOrRef<Element>, NamedTypeParameterRef>, ClassOrElementRef
|
||||||
where Element : AbstractElement<Element, Field>,
|
where Element : AbstractElement<Element, *, *> {
|
||||||
Field : AbstractField<Field> {
|
|
||||||
val element: Element
|
val element: Element
|
||||||
|
|
||||||
override fun copy(nullable: Boolean): ElementRef<Element, Field>
|
override fun copy(nullable: Boolean): ElementRef<Element>
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ElementRef<Element : AbstractElement<Element, Field>, Field : AbstractField<Field>>(
|
data class ElementRef<Element : AbstractElement<Element, *, *>>(
|
||||||
override val element: Element,
|
override val element: Element,
|
||||||
override val args: Map<NamedTypeParameterRef, TypeRef> = emptyMap(),
|
override val args: Map<NamedTypeParameterRef, TypeRef> = emptyMap(),
|
||||||
override val nullable: Boolean = false,
|
override val nullable: Boolean = false,
|
||||||
) : ElementOrRef<Element, Field> {
|
) : ElementOrRef<Element> {
|
||||||
override fun copy(args: Map<NamedTypeParameterRef, TypeRef>) = ElementRef(element, args, nullable)
|
override fun copy(args: Map<NamedTypeParameterRef, TypeRef>) = ElementRef(element, args, nullable)
|
||||||
override fun copy(nullable: Boolean) = 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
|
val ClassOrElementRef.typeKind: TypeKind
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
is ElementOrRef<*, *> -> element.kind!!.typeKind
|
is ElementOrRef<*> -> element.kind!!.typeKind
|
||||||
is ClassRef<*> -> kind
|
is ClassRef<*> -> kind
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ClassOrElementRef.inheritanceClauseParenthesis(): String = when (this) {
|
fun ClassOrElementRef.inheritanceClauseParenthesis(): String = when (this) {
|
||||||
is ElementOrRef<*, *> -> element.kind.braces()
|
is ElementOrRef<*> -> element.kind.braces()
|
||||||
is ClassRef<*> -> when (kind) {
|
is ClassRef<*> -> when (kind) {
|
||||||
TypeKind.Class -> "()"
|
TypeKind.Class -> "()"
|
||||||
TypeKind.Interface -> ""
|
TypeKind.Interface -> ""
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ val ImplementationKindOwner.needPureAbstractElement: Boolean
|
|||||||
get() = !(kind?.isInterface ?: false) &&
|
get() = !(kind?.isInterface ?: false) &&
|
||||||
allParents.none { it.kind == ImplementationKind.AbstractClass || it.kind == ImplementationKind.SealedClass }
|
allParents.none { it.kind == ImplementationKind.AbstractClass || it.kind == ImplementationKind.SealedClass }
|
||||||
|
|
||||||
fun addPureAbstractElement(elements: List<AbstractElement<*, *>>, pureAbstractElement: ClassRef<*>) {
|
fun addPureAbstractElement(elements: List<AbstractElement<*, *, *>>, pureAbstractElement: ClassRef<*>) {
|
||||||
for (el in elements) {
|
for (el in elements) {
|
||||||
if (el.needPureAbstractElement) {
|
if (el.needPureAbstractElement) {
|
||||||
el.otherParents.add(pureAbstractElement)
|
el.otherParents.add(pureAbstractElement)
|
||||||
|
|||||||
+403
@@ -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<Implementation, Element, ImplementationField>
|
||||||
|
where Implementation : AbstractImplementation<Implementation, Element, ImplementationField>,
|
||||||
|
Element : AbstractElement<Element, *, Implementation>,
|
||||||
|
ImplementationField : AbstractField<*>,
|
||||||
|
ImplementationField : AbstractFieldWithDefaultValue<*> {
|
||||||
|
|
||||||
|
private val elementsWithImpl = mutableSetOf<Element>()
|
||||||
|
|
||||||
|
protected abstract fun createImplementation(element: Element, name: String?): Implementation
|
||||||
|
|
||||||
|
fun configureImplementations(model: Model<Element>) {
|
||||||
|
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<Element>) {
|
||||||
|
collectLeafsWithoutImplementation(elements).forEach {
|
||||||
|
impl(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectLeafsWithoutImplementation(elements: List<Element>): Set<Element> {
|
||||||
|
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<String>, 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-3
@@ -85,7 +85,7 @@ fun SmartPrinter.printKDoc(kDoc: String?) {
|
|||||||
println(" */")
|
println(" */")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AbstractElement<*, *>.extendedKDoc(defaultKDoc: String? = null): String = buildString {
|
fun AbstractElement<*, *, *>.extendedKDoc(defaultKDoc: String? = null): String = buildString {
|
||||||
val doc = kDoc ?: defaultKDoc
|
val doc = kDoc ?: defaultKDoc
|
||||||
if (doc != null) {
|
if (doc != null) {
|
||||||
appendLine(doc)
|
appendLine(doc)
|
||||||
@@ -201,7 +201,7 @@ private val dataParameter = FunctionParameter("data", dataTP)
|
|||||||
|
|
||||||
context(ImportCollector)
|
context(ImportCollector)
|
||||||
fun SmartPrinter.printAcceptMethod(
|
fun SmartPrinter.printAcceptMethod(
|
||||||
element: AbstractElement<*, *>,
|
element: AbstractElement<*, *, *>,
|
||||||
visitorClass: ClassRef<PositionTypeParameterRef>,
|
visitorClass: ClassRef<PositionTypeParameterRef>,
|
||||||
hasImplementation: Boolean,
|
hasImplementation: Boolean,
|
||||||
treeName: String,
|
treeName: String,
|
||||||
@@ -239,7 +239,7 @@ fun SmartPrinter.printAcceptMethod(
|
|||||||
|
|
||||||
context(ImportCollector)
|
context(ImportCollector)
|
||||||
fun SmartPrinter.printTransformMethod(
|
fun SmartPrinter.printTransformMethod(
|
||||||
element: AbstractElement<*, *>,
|
element: AbstractElement<*, *, *>,
|
||||||
transformerClass: ClassRef<PositionTypeParameterRef>,
|
transformerClass: ClassRef<PositionTypeParameterRef>,
|
||||||
implementation: String?,
|
implementation: String?,
|
||||||
returnType: TypeRefWithNullability,
|
returnType: TypeRefWithNullability,
|
||||||
@@ -347,3 +347,5 @@ fun SmartPrinter.printTransformChildrenMethod(
|
|||||||
override = override,
|
override = override,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun AbstractField<*>.call(): String = if (nullable) "?." else "."
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.generators.tree
|
|||||||
/**
|
/**
|
||||||
* Runs [block] on this element and all its parents recursively.
|
* Runs [block] on this element and all its parents recursively.
|
||||||
*/
|
*/
|
||||||
fun <Element : AbstractElement<Element, *>> Element.traverseParents(block: (Element) -> Unit) {
|
fun <Element : AbstractElement<Element, *, *>> Element.traverseParents(block: (Element) -> Unit) {
|
||||||
traverseParentsUntil { block(it); false }
|
traverseParentsUntil { block(it); false }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ fun <Element : AbstractElement<Element, *>> Element.traverseParents(block: (Elem
|
|||||||
*
|
*
|
||||||
* If [block] always returns `false`, visits all the parents and returns `false`.
|
* If [block] always returns `false`, visits all the parents and returns `false`.
|
||||||
*/
|
*/
|
||||||
fun <Element : AbstractElement<Element, *>> Element.traverseParentsUntil(block: (Element) -> Boolean): Boolean {
|
fun <Element : AbstractElement<Element, *, *>> Element.traverseParentsUntil(block: (Element) -> Boolean): Boolean {
|
||||||
if (block(this)) return true
|
if (block(this)) return true
|
||||||
for (parent in elementParents) {
|
for (parent in elementParents) {
|
||||||
if (parent.element.traverseParentsUntil(block)) return true
|
if (parent.element.traverseParentsUntil(block)) return true
|
||||||
@@ -32,13 +32,13 @@ fun <Element : AbstractElement<Element, *>> Element.traverseParentsUntil(block:
|
|||||||
* a type of a field, except when that field is explicitly opted out of it via
|
* a type of a field, except when that field is explicitly opted out of it via
|
||||||
* [AbstractField.useInBaseTransformerDetection].
|
* [AbstractField.useInBaseTransformerDetection].
|
||||||
*/
|
*/
|
||||||
fun <Element : AbstractElement<Element, *>> detectBaseTransformerTypes(model: Model<Element>) {
|
fun <Element : AbstractElement<Element, *, *>> detectBaseTransformerTypes(model: Model<Element>) {
|
||||||
val usedAsFieldType = hashSetOf<AbstractElement<*, *>>()
|
val usedAsFieldType = hashSetOf<AbstractElement<*, *, *>>()
|
||||||
for (element in model.elements) {
|
for (element in model.elements) {
|
||||||
for (field in element.allFields.filter { it.containsElement }) {
|
for (field in element.allFields.filter { it.containsElement }) {
|
||||||
if (!field.useInBaseTransformerDetection) continue
|
if (!field.useInBaseTransformerDetection) continue
|
||||||
val fieldElement = (field.typeRef as? ElementOrRef<*, *>)?.element
|
val fieldElement = (field.typeRef as? ElementOrRef<*>)?.element
|
||||||
?: ((field as? ListField)?.baseType as? ElementOrRef<*, *>)?.element
|
?: ((field as? ListField)?.baseType as? ElementOrRef<*>)?.element
|
||||||
?: continue
|
?: continue
|
||||||
if (fieldElement.isRootElement) continue
|
if (fieldElement.isRootElement) continue
|
||||||
usedAsFieldType.add(fieldElement)
|
usedAsFieldType.add(fieldElement)
|
||||||
|
|||||||
Reference in New Issue
Block a user