diff --git a/compiler/fir/tree/visitors-generator/build.gradle.kts b/compiler/fir/tree/visitors-generator/build.gradle.kts index f1c7a9db23e..01de96a48f2 100644 --- a/compiler/fir/tree/visitors-generator/build.gradle.kts +++ b/compiler/fir/tree/visitors-generator/build.gradle.kts @@ -16,6 +16,10 @@ runtimeOnly.extendsFrom(compileOnly) dependencies { compile(project(":compiler:psi")) + compile(project(":compiler:frontend.common")) + compile(project(":core:descriptors")) + compile(project(":compiler:fir:cones")) + compile(project(":compiler:ir.tree")) compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) } compileOnly(intellijDep()) { @@ -25,6 +29,7 @@ dependencies { Platform[192].orHigher { runtimeOnly(intellijCoreDep()) { includeJars("jdom") } } + implementation(kotlin("reflect")) } val writeCopyright by task { diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/FieldSets.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/FieldSets.kt new file mode 100644 index 00000000000..d2fa57c119e --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/FieldSets.kt @@ -0,0 +1,79 @@ +/* + * 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 + +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.annotationCall +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.block +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.controlFlowGraphReference +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.declaration +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.declarationStatus +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.expression +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.reference +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeParameter +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeProjection +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.typeRef +import org.jetbrains.kotlin.fir.tree.generator.FirTreeBuilder.valueParameter +import org.jetbrains.kotlin.fir.tree.generator.context.type +import org.jetbrains.kotlin.fir.tree.generator.model.* + +object FieldSets { + val calleeReference = field("calleeReference", reference) + + val receivers = fieldSet( + field("explicitReceiver", expression, nullable = true).withTransform(), + field("dispatchReceiver", expression).withTransform(), + field("extensionReceiver", expression).withTransform() + ) + + val typeArguments = + fieldList("typeArguments", typeProjection) + + val arguments = + fieldList("arguments", expression) + + val declarations = fieldList(declaration) + + val annotations = + fieldList("annotations", annotationCall) + + fun symbolWithPackage(packageName: String?, symbolClassName: String, argument: String? = null): Field { + return field("symbol", type(packageName, symbolClassName), argument) + } + + fun symbol(symbolClassName: String, argument: String? = null): Field = + symbolWithPackage("fir.symbols.impl", symbolClassName, argument) + + fun body(nullable: Boolean = false) = + field("body", block, nullable) + + val returnTypeRef = + field("returnTypeRef", typeRef) + + val typeRefField = + field(typeRef, withReplace = true) + + fun receiverTypeRef(nullable: Boolean = false) = field("receiverTypeRef", typeRef, nullable) + + val valueParameters = fieldList(valueParameter) + + val typeParameters = fieldList(typeParameter) + + val name = field(nameType) + + val initializer = field("initializer", expression, nullable = true) + + fun superTypeRefs(withReplace: Boolean = false) = fieldList("superTypeRefs", typeRef, withReplace) + + val classKind = field(classKindType) + + val status = field("status", declarationStatus) + + val controlFlowGraphReferenceField = field("controlFlowGraphReference", controlFlowGraphReference) + + val visibility = field(visibilityType) + + val modality = field(modalityType, nullable = true) +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt new file mode 100644 index 00000000000..97247c9e4ee --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/FirTreeBuilder.kt @@ -0,0 +1,132 @@ +/* + * 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 + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.model.Element.Kind.* + +object FirTreeBuilder : AbstractFirTreeBuilder() { + val annotationContainer = element("AnnotationContainer", Other) + val typeRef = element("TypeRef", TypeRef, annotationContainer) + val reference = element("Reference", Reference) + val label = element("Label", Other) + val import = element("Import", Declaration) + val resolvedImport = element("ResolvedImport", Declaration, import) + val symbolOwner = element("SymbolOwner", Other) + val resolvable = element("Resolvable", Expression) + + val controlFlowGraphOwner = element("ControlFlowGraphOwner", Other) + val targetElement = element("TargetElement", Other) + + val declarationStatus = element("DeclarationStatus", Declaration) + val resolvedDeclarationStatus = element("ResolvedDeclarationStatus", Declaration, declarationStatus) + + val statement = element("Statement", Expression, annotationContainer) + val expression = element("Expression", Expression, statement) + val declaration = element("Declaration", Declaration) + val anonymousInitializer = element("AnonymousInitializer", Declaration, declaration) + val typedDeclaration = element("TypedDeclaration", Declaration, declaration, annotationContainer) + val callableDeclaration = element("CallableDeclaration", Declaration, typedDeclaration, symbolOwner) + val namedDeclaration = element("NamedDeclaration", Declaration, declaration) + val typeParameter = element("TypeParameter", Declaration, namedDeclaration, symbolOwner, annotationContainer) + val typeParametersOwner = element("TypeParametersOwner", Declaration) + val memberDeclaration = element("MemberDeclaration", Declaration, namedDeclaration, annotationContainer) + val callableMemberDeclaration = element("CallableMemberDeclaration", Declaration, callableDeclaration, memberDeclaration) + + val variable = element("Variable", Declaration, callableDeclaration, namedDeclaration, statement) + val valueParameter = element("ValueParameter", Declaration, variable) + val property = element("Property", Declaration, variable, controlFlowGraphOwner, typeParametersOwner, callableMemberDeclaration) + val field = element("Field", Declaration, variable, callableMemberDeclaration) // TODO: add noImpl + val klass = element("Class", Declaration, declaration, statement, annotationContainer) + val classLikeDeclaration = element("ClassLikeDeclaration", Declaration, statement, memberDeclaration, symbolOwner, typeParametersOwner) + val regularClass = element("RegularClass", Declaration, namedDeclaration, classLikeDeclaration, klass) + val typeAlias = element("TypeAlias", Declaration, classLikeDeclaration) + val enumEntry = element("EnumEntry", Declaration, regularClass) + + val function = element("Function", Declaration, callableDeclaration, controlFlowGraphOwner, targetElement, annotationContainer, typeParametersOwner, statement) + + val memberFunction = element("MemberFunction", Declaration, function, callableMemberDeclaration) + val simpleFunction = element("SimpleFunction", Declaration, memberFunction) + val propertyAccessor = element("PropertyAccessor", Declaration, function) + val constructor = element("Constructor", Declaration, memberFunction) + val file = element("File", Declaration, annotationContainer, declaration) + + val anonymousFunction = element("AnonymousFunction", Declaration, function, expression) + val anonymousObject = element("AnonymousObject", Declaration, klass, expression) + + val loop = element("Loop", Expression, statement, targetElement, annotationContainer) + val doWhileLoop = element("DoWhileLoop", Expression, loop) + val whileLoop = element("WhileLoop", Expression, loop) + + val block = element("Block", Expression, expression) + val binaryLogicExpression = element("BinaryLogicExpression", Expression, expression) + val jump = element("Jump", Expression, expression) + val loopJump = element("LoopJump", Expression, jump) + val breakExpression = element("BreakExpression", Expression, loopJump) + val continueExpression = element("ContinueExpression", Expression, loopJump) + val catchClause = element("Catch", Expression) + val tryExpression = element("TryExpression", Expression, expression, resolvable) + val constExpression = element("ConstExpression", Expression, expression) + val typeProjection = element("TypeProjection", TypeRef) + val starProjection = element("StarProjection", TypeRef, typeProjection) + val typeProjectionWithVariance = element("TypeProjectionWithVariance", TypeRef, typeProjection) + val call = element("Call", Expression, statement) // TODO: may smth like `CallWithArguments` or `ElementWithArguments`? + val annotationCall = element("AnnotationCall", Expression, expression, call) + val operatorCall = element("OperatorCall", Expression, expression, call) + val typeOperatorCall = element("TypeOperatorCall", Expression, expression, call) + val whenExpression = element("WhenExpression", Expression, expression, resolvable) + val whenBranch = element("WhenBranch", Expression) + val delegatedConstructorCall = element("DelegatedConstructorCall", Expression, call) + val qualifiedAccessWithoutCallee = element("QualifiedAccessWithoutCallee", Expression, statement) + val qualifiedAccess = element("QualifiedAccess", Expression, qualifiedAccessWithoutCallee, resolvable) + + val arrayOfCall = element("ArrayOfCall", Expression, expression, call) + val arraySetCall = element("ArraySetCall", Expression, qualifiedAccess, call) + val classReferenceExpression = element("ClassReferenceExpression", Expression, expression) + val errorExpression = element("ErrorExpression", Expression, expression) + val errorFunction = element("ErrorFunction", Declaration, function) + val qualifiedAccessExpression = element("QualifiedAccessExpression", Expression, expression, qualifiedAccess) + val functionCall = element("FunctionCall", Expression, qualifiedAccessExpression, call) + val componentCall = element("ComponentCall", Expression, functionCall) + val callableReferenceAccess = element("CallableReferenceAccess", Expression, qualifiedAccessExpression) + val thisReceiverExpression = element("ThisReceiverExpression", Expression, qualifiedAccessExpression) + val expressionWithSmartcast = element("ExpressionWithSmartcast", Expression, qualifiedAccessExpression) + val getClassCall = element("GetClassCall", Expression, expression, call) + val wrappedExpression = element("WrappedExpression", Expression, expression) + val wrappedArgumentExpression = element("WrappedArgumentExpression", Expression, wrappedExpression) + val lambdaArgumentExpression = element("LambdaArgumentExpression", Expression, wrappedArgumentExpression) + val spreadArgumentExpression = element("SpreadArgumentExpression", Expression, wrappedArgumentExpression) + val namedArgumentExpression = element("NamedArgumentExpression", Expression, wrappedArgumentExpression) + + val resolvedQualifier = element("ResolvedQualifier", Expression, expression) + val returnExpression = element("ReturnExpression", Expression, jump) + val stringConcatenationCall = element("StringConcatenationCall", Expression, call, expression) + val throwExpression = element("ThrowExpression", Expression, expression) + val variableAssignment = element("VariableAssignment", Expression, qualifiedAccess) + val whenSubjectExpression = element("WhenSubjectExpression", Expression, expression) + + val wrappedDelegateExpression = element("WrappedDelegateExpression", Expression, wrappedExpression) + + val namedReference = element("NamedReference", Reference, reference) + val errorNamedReference = element("ErrorNamedReference", Reference, namedReference) + val superReference = element("SuperReference", Reference, reference) + val thisReference = element("ThisReference", Reference, reference) + val controlFlowGraphReference = element("ControlFlowGraphReference", Reference, reference) + + val resolvedCallableReference = element("ResolvedCallableReference", Reference, namedReference) + val delegateFieldReference = element("DelegateFieldReference", Reference, resolvedCallableReference) + val backingFieldReference = element("BackingFieldReference", Reference, resolvedCallableReference) + + val resolvedTypeRef = element("ResolvedTypeRef", TypeRef, typeRef) + val errorTypeRef = element("ErrorTypeRef", TypeRef, resolvedTypeRef) + val delegatedTypeRef = element("DelegatedTypeRef", TypeRef, typeRef) + val typeRefWithNullability = element("TypeRefWithNullability", TypeRef, typeRef) + val userTypeRef = element("UserTypeRef", TypeRef, typeRefWithNullability) + val dynamicTypeRef = element("DynamicTypeRef", TypeRef, typeRefWithNullability) + val functionTypeRef = element("FunctionTypeRef", TypeRef, typeRefWithNullability) + val resolvedFunctionTypeRef = element("ResolvedFunctionTypeRef", TypeRef, resolvedTypeRef, functionTypeRef) + val implicitTypeRef = element("ImplicitTypeRef", TypeRef, typeRef) +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt new file mode 100644 index 00000000000..0e765d6d925 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt @@ -0,0 +1,625 @@ +/* + * Copyright 2000-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 + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeImplementationConfigurator +import org.jetbrains.kotlin.fir.tree.generator.model.Implementation +import org.jetbrains.kotlin.fir.tree.generator.model.Implementation.Kind.* + +object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() { + private lateinit var abstractAnnotatedElement: Implementation + + fun configureImplementations() { + configure() + generateDefaultImplementations(FirTreeBuilder) + configureAllImplementations() + } + + private fun configure() = with(FirTreeBuilder) { + val callWithArgumentList = impl(call, "FirCallWithArgumentList") { + kind = Interface + } + + abstractAnnotatedElement = impl(annotationContainer, "FirAbstractAnnotatedElement") { + kind = Interface + } + + val modifiableTypeParametersOwner = impl(typeParametersOwner, "FirModifiableTypeParametersOwner") { + kind = Interface + } + + val modifiableConstructor = impl(constructor, "FirModifiableConstructor") { + kind = Interface + parents += modifiableTypeParametersOwner + } + + impl(constructor) { + kind = OpenClass + parents += modifiableConstructor + defaultNull("delegatedConstructor") + defaultNull("body") + default("name", "Name.special(\"\")") + + default("isPrimary") { + value = "false" + withGetter = true + } + + default("typeParameters") { + needAcceptAndTransform = false + } + } + + noImpl(declarationStatus) + noImpl(resolvedDeclarationStatus) + noImpl(field) + + val modifiableClass = impl(klass, "FirModifiableClass") { + kind = Interface + } + + impl(regularClass, "FirClassImpl") { + parents += modifiableClass + parents += modifiableTypeParametersOwner + defaultNull("companionObject") + defaultSupertypesComputationStatus() + } + + impl(anonymousObject) { + parents += modifiableClass + default("classKind") { + value = "ClassKind.OBJECT" + withGetter = true + } + } + + impl(enumEntry) { + parents += modifiableClass + parents += modifiableTypeParametersOwner + default("status", "FirDeclarationStatusImpl(Visibilities.UNKNOWN, Modality.FINAL)") + default("classKind") { + value = "ClassKind.ENUM_ENTRY" + withGetter = true + } + default("companionObject") { + value = "null" + withGetter = true + } + default("typeRef", "session.builtinTypes.enumType") + defaultSupertypesComputationStatus() + useTypes(visibilitiesType, modalityType) + } + + impl(typeAlias) { + parents += modifiableTypeParametersOwner + defaultSupertypesComputationStatus() + } + + impl(import) + + impl(resolvedImport) { + delegateFields(listOf("aliasName", "importedFqName", "isAllUnder"), "delegate") + + default("psi") { + delegate = "delegate" + } + + default("resolvedClassId") { + delegate = "relativeClassName" + delegateCall = "let { ClassId(packageFqName, it, false) }" + withGetter = true + } + + default("importedName") { + delegate = "importedFqName" + delegateCall = "shortName()" + withGetter = true + } + + default("delegate") { + needAcceptAndTransform = false + } + } + + impl(breakExpression) { + lateinit("target") + } + + impl(continueExpression) { + lateinit("target") + } + + impl(annotationCall) { + parents += callWithArgumentList + default("typeRef") { + value = "annotationTypeRef" + withGetter = true + } + } + + impl(arrayOfCall) { + parents += callWithArgumentList + } + + val modifiableQualifiedAccess = impl(qualifiedAccessWithoutCallee, "FirModifiableQualifiedAccess") { + kind = Interface + isMutable("safe") + } + + impl(arraySetCall) { + parents += modifiableQualifiedAccess + lateinit("calleeReference") + default("arguments") { + value = "indexes + rValue" + withGetter = true + } + default("lValue") { + value = "calleeReference" + customSetter = "calleeReference = value" + } + default("safe", "false") + defaultNoReceivers() + } + + impl(callableReferenceAccess) { + parents += modifiableQualifiedAccess + defaultNull("explicitReceiver") + default("safe", "false") + defaultNoReceivers() + lateinit("calleeReference") + } + + impl(componentCall) { + parents += callWithArgumentList // modifiableQualifiedAccess + default("safe") { + value = "false" + withGetter = true + } + listOf("dispatchReceiver", "extensionReceiver").forEach { + default(it) { + value = "FirNoReceiverExpression" + withGetter = true + } + } + default("calleeReference", "FirSimpleNamedReference(psi, Name.identifier(\"component\$componentIndex\"), null)") + useTypes(simpleNamedReferenceType, nameType, noReceiverExpressionType) + } + + val abstractLoop = impl(loop, "FirAbstractLoop") { + kind = Interface + } + + impl(whileLoop) { + parents += abstractLoop + defaultNull("label") + lateinit("block") + } + + impl(doWhileLoop) { + parents += abstractLoop + defaultNull("label") + lateinit("block") + } + + impl(delegatedConstructorCall) { + parents += callWithArgumentList + default( + "calleeReference", + "if (isThis) FirExplicitThisReference(psi, null) else FirExplicitSuperReference(psi, constructedTypeRef)" + ) + default("isSuper") { + value = "!isThis" + withGetter = true + } + useTypes(explicitThisReferenceType, explicitSuperReferenceType) + } + + impl(expression, "FirElseIfTrueCondition") { + default("typeRef", "FirImplicitBooleanTypeRef(psi)") + useTypes(implicitBooleanTypeRefType) + } + + impl(block) { + } + + val emptyExpressionBlock = impl(block, "FirEmptyExpressionBlock") { + // TODO: make statements immutable + defaultNull("psi") + } + + impl(errorExpression) + + impl(loop, "FirErrorLoop") { + default("block", "FirEmptyExpressionBlock()") + default("condition", "FirErrorExpressionImpl(psi, \"error loop\")") + defaultNull("label") + useTypes(emptyExpressionBlock) + } + + impl(expression, "FirExpressionStub") + + impl(functionCall) { + parents += modifiableQualifiedAccess + parents += callWithArgumentList + defaultFalse("safe") + lateinit("calleeReference") + defaultNoReceivers() + } + + impl(qualifiedAccessExpression) { + parents += modifiableQualifiedAccess + defaultFalse("safe") + lateinit("calleeReference") + defaultNoReceivers() + } + + noImpl(expressionWithSmartcast) + + impl(getClassCall) { + parents += callWithArgumentList + default("argument") { + value = "arguments.first()" + withGetter = true + } + } + + val modifiableVariable = impl(variable, "FirModifiableVariable") { + kind = Interface + } + + impl(property) { + parents += modifiableVariable.withArg(property) + parents += modifiableTypeParametersOwner + default("isVal") { + value = "!isVar" + withGetter = true + } + + default("backingFieldSymbol", "FirBackingFieldSymbol(symbol.callableId)") + default("delegateFieldSymbol", "delegate?.let { FirDelegateFieldSymbol(symbol.callableId) }") + defaultNull("getter", "setter") + default("resolvePhase") { + value = "if (isLocal) FirResolvePhase.DECLARATIONS else FirResolvePhase.RAW_FIR" + } + useTypes(backingFieldSymbolType, delegateFieldSymbolType) + } + + impl(namedArgumentExpression) { + default("typeRef") { + delegate = "expression" + } + } + + impl(lambdaArgumentExpression) { + default("isSpread") { + value = "false" + withGetter = true + } + default("typeRef") { + delegate = "expression" + } + } + + impl(spreadArgumentExpression) { + default("isSpread") { + value = "true" + withGetter = true + } + default("typeRef") { + delegate = "expression" + } + } + + impl(operatorCall) { + parents += callWithArgumentList + default("typeRef", """ + |if (operation in FirOperation.BOOLEANS) { + | FirImplicitBooleanTypeRef(null) + | } else { + | FirImplicitTypeRefImpl(null) + | } + """.trimMargin()) + + useTypes(implicitTypeRefType, implicitBooleanTypeRefType) + } + + impl(typeOperatorCall) { + parents += callWithArgumentList + } + + impl(resolvedQualifier) { + isMutable("packageFqName", "relativeClassFqName") + default("classId") { + value = """ + |relativeClassFqName?.let { + | ClassId(packageFqName, it, false) + |} + """.trimMargin() + withGetter = true + } + } + + impl(returnExpression) { + lateinit("target") + default("typeRef", "FirImplicitNothingTypeRef(psi)") + useTypes(implicitNothingTypeRefType) + } + + impl(stringConcatenationCall) { + parents += callWithArgumentList + default("typeRef", "FirImplicitStringTypeRef(psi)") + useTypes(implicitStringTypeRefType) + } + + impl(throwExpression) { + default("typeRef", "FirImplicitNothingTypeRef(psi)") + useTypes(implicitNothingTypeRefType) + } + + impl(thisReceiverExpression) { + parents += modifiableQualifiedAccess + default("safe") { + value = "false" + withGetter = true + } + defaultNoReceivers() + } + + impl(tryExpression) { + default("calleeReference", "FirStubReference()") + useTypes(stubReferenceType) + } + + impl(expression, "FirUnitExpression") { + default("typeRef", "FirImplicitUnitTypeRef(psi)") + useTypes(implicitUnitTypeRefType) + } + + impl(variableAssignment) { + parents += modifiableQualifiedAccess + isMutable("operation") + lateinit("calleeReference") + defaultNoReceivers() + + default("lValue") { + value = "calleeReference" + customSetter = "calleeReference = value" + } + } + + val modifiableFunction = impl(function, "FirModifiableFunction") { + kind = Interface + } + + impl(anonymousFunction) { + parents += modifiableFunction.withArg(anonymousFunction) + defaultNull("invocationKind", "label", "body") + default("resolvePhase", "FirResolvePhase.DECLARATIONS") + } + + impl(propertyAccessor) { + parents += modifiableFunction.withArg(propertyAccessor) + default("receiverTypeRef") { + value = "null" + withGetter = true + } + default("isSetter") { + value = "!isGetter" + withGetter = true + } + defaultNull("body") + useTypes(modalityType) + kind = OpenClass + } + + impl(whenExpression) { + default("calleeReference", "FirStubReference()") + useTypes(stubReferenceType) + } + + impl(whenSubjectExpression) { + default("typeRef") { + value = "whenSubject.whenExpression.subject!!.typeRef" + withGetter = true + } + } + + impl(wrappedDelegateExpression) { + lateinit("delegateProvider") + default("typeRef") { + delegate = "expression" + } + } + + impl(resolvedCallableReference) { + defaultNull("candidateSymbol", withGetter = true) + } + + impl(resolvedCallableReference, "FirPropertyFromParameterCallableReference") { + defaultNull("candidateSymbol", withGetter = true) + } + + impl(namedReference, "FirSimpleNamedReference") { + kind = OpenClass + } + + impl(delegateFieldReference) { + default("name") { + value = "Name.identifier(\"\\\$delegate\")" + withGetter = true + } + } + + impl(backingFieldReference) { + default("name") { + value = "Name.identifier(\"\\\$field\")" + withGetter = true + } + } + + impl(thisReference, "FirExplicitThisReference") { + default("boundSymbol") { + value = "null" + isMutable = true + } + } + + impl(thisReference, "FirImplicitThisReference") { + defaultNull("psi") + default("labelName") { + value = "null" + withGetter = true + } + } + + impl(superReference, "FirExplicitSuperReference") + + impl(controlFlowGraphReference, "FirEmptyControlFlowGraphReference") { + noPsi() + } + + impl(resolvedTypeRef) + + val errorTypeRefImpl = impl(errorTypeRef) { + default("type", "ConeClassErrorType(reason)") + useTypes(coneClassErrorTypeType) + } + + impl(errorFunction) { + defaultNull("receiverTypeRef", "body", withGetter = true) + default("returnTypeRef", "FirErrorTypeRefImpl(null, reason)") + useTypes(errorTypeRefImpl) + } + + impl(functionTypeRef) + impl(implicitTypeRef) { + defaultEmptyList("annotations") + } + + impl(implicitTypeRef, "FirComputingImplicitTypeRef") { + kind = Object + defaultNull("psi", withGetter = true) + } + + impl(reference, "FirStubReference") { + default("psi") { + value = "null" + withGetter = true + } + } + + impl(errorNamedReference) { + default("name", "Name.special(\"<\$errorReason>\")") + defaultNull("candidateSymbol", withGetter = true) + } + + impl(typeProjection, "FirTypePlaceholderProjection") { + kind = Object + defaultNull("psi") + } + + val abstractLoopJump = impl(loopJump, "FirAbstractLoopJump") { + kind = Interface + lateinit("target") + } + + impl(breakExpression) { + parents += abstractLoopJump + default("typeRef", "FirImplicitNothingTypeRef(psi)") + useTypes(implicitNothingTypeRefType) + } + + impl(continueExpression) { + parents += abstractLoopJump + default("typeRef", "FirImplicitNothingTypeRef(psi)") + useTypes(implicitNothingTypeRefType) + } + + impl(valueParameter) { + kind = OpenClass + parents += modifiableVariable.withArg(valueParameter) + defaultTrue("isVal", true) + defaultFalse("isVar", withGetter = true) + defaultNull("getter", "setter", "initializer", "delegate", "receiverTypeRef", "delegateFieldSymbol", withGetter = true) + } + + impl(valueParameter, "FirDefaultSetterValueParameter") { + default("name", "Name.identifier(\"value\")") + defaultNull("defaultValue", "initializer", "delegate", "receiverTypeRef", "delegateFieldSymbol", "getter", "setter") + defaultFalse("isCrossinline", "isNoinline", "isVararg", "isVar") + defaultTrue("isVal") + } + + impl(simpleFunction) { + kind = OpenClass + parents += modifiableFunction.withArg(simpleFunction) + parents += modifiableTypeParametersOwner + defaultNull("body") + } + + impl(delegatedTypeRef) { + listOf("psi", "annotations").forEach { + default(it) { + delegate = "typeRef" + } + } + } + + noImpl(userTypeRef) + } + + private fun findImplementationsWithAnnotations(implementationPredicate: (Implementation) -> Boolean): Collection { + return FirTreeBuilder.elements.flatMap { it.allImplementations }.mapNotNullTo(mutableSetOf()) { + if (!implementationPredicate(it)) return@mapNotNullTo null + var hasAnnotations = false + if (it.element == FirTreeBuilder.annotationContainer) return@mapNotNullTo null + it.element.traverseParents { + if (it == FirTreeBuilder.annotationContainer) { + hasAnnotations = true + } + } + it.takeIf { hasAnnotations } + } + } + + private fun configureAllImplementations() { + configureFieldInAllImplementations("controlFlowGraphReference") { + default(it, "FirEmptyControlFlowGraphReference()") + useTypes(emptyCfgReferenceType) + } + + configureFieldInAllImplementations( + field = "typeRef", + implementationPredicate = { it.type !in listOf("FirDelegatedTypeRefImpl", "FirTypeProjectionWithVarianceImpl") }, + fieldPredicate = { it.defaultValue == null } + ) { + default(it, "FirImplicitTypeRefImpl(null)") + useTypes(implicitTypeRefType) + } + + configureFieldInAllImplementations( + field = "resolvePhase", + fieldPredicate = { it.defaultValue == null } + ) { + default(it, "FirResolvePhase.RAW_FIR") + } + + configureFieldInAllImplementations( + field = "containerSource" + ) { + default(it) { + value = "null" + isMutable = true + } + } + + findImplementationsWithAnnotations { + it.type !in setOf("FirDelegatedTypeRefImpl", "FirImplicitTypeRefImpl") + }.forEach { + it.addParent(abstractAnnotatedElement) + } + } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt new file mode 100644 index 00000000000..91331f68d44 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Main.kt @@ -0,0 +1,94 @@ +/* + * 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 + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.model.* +import java.io.File + + +fun main(args: Array) { + val generationPath = args.firstOrNull()?.let { if (!it.endsWith("/")) "$it/" else it } + if (generationPath == null) { + println("Not enough arguments") + return + } + + NodeConfigurator.configureFields() + detectBaseTransformerTypes(FirTreeBuilder) + ImplementationConfigurator.configureImplementations() + removePreviousGeneratedFiles(generationPath) + printElements(FirTreeBuilder, generationPath) +// printTable(FirTreeBuilder) +} + +fun Element.traverseParents(block: (Element) -> Unit) { + block(this) + parents.forEach { it.traverseParents(block) } +} + +private fun detectBaseTransformerTypes(builder: AbstractFirTreeBuilder) { + val usedAsFieldType = mutableMapOf().withDefault { false } + for (element in builder.elements) { + for (field in element.allFirFields) { + val fieldElement = when (field) { + is FirField -> field.element + is FieldList -> field.baseType as Element + else -> throw IllegalArgumentException() + } + usedAsFieldType[fieldElement] = true + } + } + + for (element in builder.elements) { + element.traverseParents { + if (usedAsFieldType.getValue(it)) { + element.baseTransformerType = it + return@traverseParents + } + } + } +} + +private fun removePreviousGeneratedFiles(generationPath: String) { + File(generationPath).walkTopDown().forEach { + if (it.isFile && it.readText().contains(GENERATED_MESSAGE)) { + it.delete() + } + } +} + +private fun printTable(builder: AbstractFirTreeBuilder) { + val elements = builder.elements.filter { it.allImplementations.isNotEmpty() } + val fields = elements.flatMapTo(mutableSetOf()) { it.allFields } + + val mapping = mutableMapOf>() + val fieldsCount = mutableMapOf() + for (element in elements) { + val containingFields = mutableSetOf() + for (field in fields) { + if (field in element.allFields) { + containingFields += field + fieldsCount[field] = fieldsCount.getOrDefault(field, 0) + 1 + } + } + mapping[element] = containingFields + } + + val sortedFields = fields.sortedByDescending { fieldsCount[it] } + File("compiler/fir/tree/table.csv").printWriter().use { printer -> + with(printer) { + val delim = "," + print(delim) + println(sortedFields.joinToString(delim) { "${it.name}:${fieldsCount.getValue(it)}" }) + for (element in elements) { + print(element.name + delim) + val containingFields = mapping.getValue(element) + println(sortedFields.joinToString(delim) { if (it in containingFields) "+" else "-" }) + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt new file mode 100644 index 00000000000..5f8cb11e010 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -0,0 +1,517 @@ +/* + * 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 + +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.annotations +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.arguments +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.body +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.calleeReference +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.classKind +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.controlFlowGraphReferenceField +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.declarations +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.initializer +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.modality +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.name +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.receivers +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.returnTypeRef +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.status +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.superTypeRefs +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbol +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.symbolWithPackage +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeArguments +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeParameters +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.typeRefField +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.valueParameters +import org.jetbrains.kotlin.fir.tree.generator.FieldSets.visibility +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFieldConfigurator +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.context.type +import org.jetbrains.kotlin.fir.tree.generator.model.* +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource + +object NodeConfigurator : AbstractFieldConfigurator() { + fun configureFields() = with(FirTreeBuilder) { + AbstractFirTreeBuilder.baseFirElement.configure { + +field("psi", psiElementType, nullable = true) + } + + annotationContainer.configure { + +annotations + } + + symbolOwner.configure { + withArg("E", symbolOwner, declaration) + +symbolWithPackage("fir.symbols", "AbstractFirBasedSymbol", "E") + } + + controlFlowGraphOwner.configure { + +controlFlowGraphReferenceField.withTransform() + } + + typeParametersOwner.configure { + +typeParameters + } + + resolvable.configure { + +field("calleeReference", reference).withTransform() + } + + declaration.configure { + +field("session", firSessionType) + +field("resolvePhase", resolvePhaseType, withReplace = true).apply { isMutable = true } + } + + typedDeclaration.configure { + +field("returnTypeRef", typeRef).withTransform() + } + + callableDeclaration.configure { + withArg("F", "FirCallableDeclaration") + parentArg(symbolOwner, "E", "F") + +field("receiverTypeRef", typeRef, nullable = true) + +symbol("FirCallableSymbol", "F") + } + + callableMemberDeclaration.configure { + withArg("F", "FirCallableMemberDeclaration") + parentArg(callableDeclaration, "F", "F") + +field("containerSource", type(DeserializedContainerSource::class), nullable = true) + } + + namedDeclaration.configure { + +name + } + + function.configure { + withArg("F", "FirFunction") + parentArg(callableDeclaration, "F", "F") + +symbol("FirFunctionSymbol", "F") + +valueParameters.withTransform() + +body(nullable = true) + } + + errorFunction.configure { + parentArg(function, "F", errorFunction) + +stringField("reason") + +symbol("FirErrorFunctionSymbol") + } + + memberDeclaration.configure { + +typeParameters + +status + } + + expression.configure { + +typeRefField + +annotations + } + + call.configure { + +arguments.withTransform() + } + + block.configure { + +fieldList(statement) + +typeRefField + } + + binaryLogicExpression.configure { + +field("leftOperand", expression).withTransform() + +field("rightOperand", expression).withTransform() + +field("kind", operationKindType) + needTransformOtherChildren() + } + + jump.configure { + withArg("E", targetElement) + +field("target", jumpTargetType.withArgs("E")) + } + + loopJump.configure { + parentArg(jump, "E", loop) + } + + returnExpression.configure { + parentArg(jump, "E", function.withArgs("F" to "*")) + +field("result", expression) + } + + label.configure { + +stringField("name") + } + + loop.configure { + +field(block).withTransform() + +field("condition", expression).withTransform() + +field(label, nullable = true) + needTransformOtherChildren() + } + + whileLoop.configure { + +field("condition", expression).withTransform() + +field(block).withTransform() + } + + catchClause.configure { + +field("parameter", valueParameter).withTransform() + +field(block).withTransform() + needTransformOtherChildren() + } + + tryExpression.configure { + +field("tryBlock", block).withTransform() + +fieldList("catches", catchClause).withTransform() + +field("finallyBlock", block, nullable = true).withTransform() + needTransformOtherChildren() + } + + qualifiedAccessWithoutCallee.configure { + +booleanField("safe") + +receivers + } + + constExpression.configure { + withArg("T") + +field("kind", constKindType.withArgs("T")) + +field("value", "T", null) + } + + functionCall.configure { + +typeArguments + +field("calleeReference", namedReference) + } + + operatorCall.configure { + +field("operation", operationType) + } + + typeOperatorCall.configure { + +field("operation", operationType) + +field("conversionTypeRef", typeRef) + } + + whenBranch.configure { + +field("condition", expression).withTransform() + +field("result", block).withTransform() + needTransformOtherChildren() + } + + klass.configure { + +classKind + +superTypeRefs(withReplace = true) + +declarations + +annotations + } + + classLikeDeclaration.configure { + withArg("F", "FirClassLikeDeclaration") + parentArg(symbolOwner, "F", "F") + +field("supertypesComputationStatus", type("fir.declarations", "SupertypesComputationStatus"), withReplace = true).apply { isMutable = true } + +symbol("FirClassLikeSymbol", "F") + } + + regularClass.configure { + parentArg(classLikeDeclaration, "F", regularClass) + +symbol("FirClassSymbol") + +field("companionObject", regularClass, nullable = true) + +superTypeRefs(withReplace = true) + } + + typeAlias.configure { + parentArg(classLikeDeclaration, "F", typeAlias) + +symbol("FirTypeAliasSymbol") + +field("expandedTypeRef", typeRef, withReplace = true) + +annotations + } + + enumEntry.configure { + +arguments.withTransform() + +field(typeRef) + } + + anonymousFunction.configure { + parentArg(function, "F", anonymousFunction) + +symbol("FirAnonymousFunctionSymbol") + +field(label, nullable = true) + +field(invocationKindType, nullable = true, withReplace = true).apply { + isMutable = true + } + } + + typeParameter.configure { + parentArg(symbolOwner, "F", typeParameter) + +symbol("FirTypeParameterSymbol") + +field(varianceType) + +booleanField("isReified") + +fieldList("bounds", typeRef) + +annotations + } + + memberFunction.configure { + withArg("F", memberFunction) + parentArg(function, "F", "F") + parentArg(callableMemberDeclaration, "F", "F") + +symbol("FirFunctionSymbol", "F") + +annotations + } + + simpleFunction.configure { + parentArg(memberFunction, "F", simpleFunction) + } + + property.configure { + parentArg(variable, "F", property) + parentArg(callableMemberDeclaration, "F", property) + +symbol("FirPropertySymbol") + +field("backingFieldSymbol", backingFieldSymbolType) + +booleanField("isLocal") + +typeParameters + +status + } + + propertyAccessor.configure { + parentArg(function, "F", propertyAccessor) + +symbol("FirPropertyAccessorSymbol") + +booleanField("isGetter") + +booleanField("isSetter") + +status + +annotations + } + + declarationStatus.configure { + +visibility + +modality + generateBooleanFields( + "expect", "actual", "override", "operator", "infix", "inline", "tailRec", + "external", "const", "lateInit", "inner", "companion", "data", "suspend", "static" + ) + } + + constructor.configure { + parentArg(memberFunction, "F", constructor) + +symbol("FirConstructorSymbol") + +field("delegatedConstructor", delegatedConstructorCall, nullable = true) + +booleanField("isPrimary") + } + + delegatedConstructorCall.configure { + +field("constructedTypeRef", typeRef) + generateBooleanFields("this", "super") + +calleeReference.withTransform() + } + + valueParameter.configure { + parentArg(variable, "F", valueParameter) + +field("defaultValue", expression, nullable = true) + generateBooleanFields("crossinline", "noinline", "vararg") + } + + variable.configure { + withArg("F", variable) + parentArg(callableDeclaration, "F", "F") + +symbol("FirVariableSymbol", "F") + +initializer + +field("delegate", expression, nullable = true) + +field("delegateFieldSymbol", delegateFieldSymbolType, "F", nullable = true) + generateBooleanFields("var", "val") + +field("getter", propertyAccessor, nullable = true).withTransform() + +field("setter", propertyAccessor, nullable = true).withTransform() + +annotations + needTransformOtherChildren() + } + + field.configure { + parentArg(variable, "F", field) + parentArg(callableMemberDeclaration, "F", field) + } + + anonymousInitializer.configure { + +body(nullable = true) + } + + file.configure { + +fieldList(import) + +declarations + +stringField("name") + +field("packageFqName", fqNameType) + } + + import.configure { + +field("importedFqName", fqNameType, nullable = true) + +booleanField("isAllUnder") + +field("aliasName", nameType, nullable = true) + } + + resolvedImport.configure { + +field("delegate", import) + +field("packageFqName", fqNameType) + +field("relativeClassName", fqNameType, nullable = true) + +field("resolvedClassId", classIdType, nullable = true) + +field( + "importedName", + nameType, + nullable = true + ) + } + + annotationCall.configure { + +field("useSiteTarget", annotationUseSiteTargetType, nullable = true) + +field("annotationTypeRef", typeRef) + } + + arraySetCall.configure { + +field("rValue", expression).withTransform() + +field("operation", operationType) + +field("lValue", reference) + +fieldList("indexes", expression).withTransform() + } + + classReferenceExpression.configure { + +field("classTypeRef", typeRef) + } + + componentCall.configure { + +field("explicitReceiver", expression) + +intField("componentIndex") + } + + errorExpression.configure { + +stringField("reason") + } + + expressionWithSmartcast.configure { + +field("originalExpression", qualifiedAccessExpression) + +field("typesFromSmartcast", "Collection", null, customType = coneKotlinTypeType) + +field("originalType", typeRef) + } + + getClassCall.configure { + +field("argument", expression) + } + + wrappedArgumentExpression.configure { + +booleanField("isSpread") + } + + namedArgumentExpression.configure { + +name + } + + resolvedQualifier.configure { + +field("packageFqName", fqNameType) + +field("relativeClassFqName", fqNameType, nullable = true) + +field("classId", classIdType, nullable = true) + } + + stringConcatenationCall.configure { + } + + throwExpression.configure { + +field("exception", expression) + } + + variableAssignment.configure { + +field("lValue", reference) + +field("rValue", expression).withTransform() + +field("operation", operationType) + } + + whenSubjectExpression.configure { + +field("whenSubject", whenSubjectType) + } + + wrappedExpression.configure { + +field(expression) + } + + wrappedDelegateExpression.configure { + +field("delegateProvider", expression) + } + + namedReference.configure { + +name + +field("candidateSymbol", abstractFirBasedSymbolType, "*", nullable = true) + } + + resolvedCallableReference.configure { + +field("resolvedSymbol", abstractFirBasedSymbolType, "*") + } + + delegateFieldReference.configure { + +field("resolvedSymbol", delegateFieldSymbolType.withArgs("*")) + } + + backingFieldReference.configure { + +field("resolvedSymbol", backingFieldSymbolType) + } + + superReference.configure { + +field("superTypeRef", typeRef, withReplace = true) + } + + thisReference.configure { + +stringField("labelName", nullable = true) + +field("boundSymbol", abstractFirBasedSymbolType, "*", nullable = true, withReplace = true) + } + + typeRef.configure { + +annotations + } + + resolvedTypeRef.configure { + +field("type", coneKotlinTypeType) + } + + errorTypeRef.configure { + +stringField("reason") + } + + delegatedTypeRef.configure { + +field("delegate", expression, nullable = true) + +field(typeRef) + } + + typeRefWithNullability.configure { + +booleanField("isMarkedNullable") + } + + userTypeRef.configure { + +fieldList("qualifier", firQualifierPartType) + } + + functionTypeRef.configure { + +field("receiverTypeRef", typeRef, nullable = true) + +valueParameters + +returnTypeRef + } + + thisReceiverExpression.configure { + +field("calleeReference", thisReference) + } + + whenExpression.configure { + +field("subject", expression, nullable = true).withTransform() + +field("subjectVariable", variable.withArgs("F" to "*"), nullable = true) + +fieldList("branches", whenBranch).withTransform() + needTransformOtherChildren() + } + + typeProjectionWithVariance.configure { + +field(typeRef) + +field(varianceType) + } + + errorNamedReference.configure { + +stringField("errorReason") + } + } +} + +private fun Element.withArgs(vararg replacements: Pair): AbstractElement { + val replaceMap = replacements.toMap() + val newArguments = typeArguments.map { replaceMap[it.name]?.let { SimpleTypeArgument(it, null) } ?: it } + return ElementWithArguments(this, newArguments) +} diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Printer.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Printer.kt new file mode 100644 index 00000000000..e70d9ecfbbe --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Printer.kt @@ -0,0 +1,725 @@ +/* + * 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 + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.model.* +import java.io.File +import java.io.PrintWriter +import java.util.* + +val COPYRIGHT = """ +/* + * Copyright 2010-${GregorianCalendar()[Calendar.YEAR]} 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. + */ +""".trimIndent() + +const val BASE_PACKAGE = "org.jetbrains.kotlin.fir" +//const val BASE_PATH = "compiler/fir/tree/src/" +private const val VISITOR_PACKAGE = "org.jetbrains.kotlin.fir.visitors" +private const val INDENT = " " +val GENERATED_MESSAGE = """ + /* + * This file was generated automatically + * DO NOT MODIFY IT MANUALLY + */ + """.trimIndent() + +fun printElements(builder: AbstractFirTreeBuilder, generationPath: String) { + builder.elements.forEach { it.generateCode(generationPath) } + builder.elements.flatMap { it.allImplementations }.forEach { it.generateCode(generationPath) } + + printVisitor(builder.elements, generationPath) + printVisitorVoid(builder.elements, generationPath) + printTransformer(builder.elements, generationPath) +} + +fun PrintWriter.printCopyright() { + println(COPYRIGHT) + println() +} + +fun PrintWriter.printGeneratedMessage() { + println(GENERATED_MESSAGE) + println() +} + +fun printVisitor(elements: List, generationPath: String) { + val dir = File(generationPath + VISITOR_PACKAGE.replace(".", "/")) + dir.mkdirs() + File(dir, "FirVisitor.kt").printWriter().use { printer -> + with(printer) { + printCopyright() + println("package $VISITOR_PACKAGE") + println() + elements.forEach { println("import ${it.fullQualifiedName}") } + println() + printGeneratedMessage() + + println("abstract class FirVisitor {") + + indent() + println("abstract fun visitElement(element: FirElement, data: D): R") + println() + for (element in elements) { + if (element == AbstractFirTreeBuilder.baseFirElement) continue + with(element) { + indent() + val varName = safeDecapitalizedName + println("open fun ${typeParameters}visit$name($varName: $typeWithArguments, data: D): R${multipleUpperBoundsList()} = visitElement($varName, data)") + println() + } + } + println("}") + } + } +} + +fun printVisitorVoid(elements: List, generationPath: String) { + val dir = File(generationPath + VISITOR_PACKAGE.replace(".", "/")) + dir.mkdirs() + File(dir, "FirVisitorVoid.kt").printWriter().use { printer -> + with(printer) { + printCopyright() + println("package $VISITOR_PACKAGE") + println() + elements.forEach { println("import ${it.fullQualifiedName}") } + println() + printGeneratedMessage() + + println("abstract class FirVisitorVoid : FirVisitor() {") + + indent() + println("abstract fun visitElement(element: FirElement)") + println() + for (element in elements) { + if (element == AbstractFirTreeBuilder.baseFirElement) continue + with(element) { + indent() + val varName = safeDecapitalizedName + println("open fun ${typeParameters}visit$name($varName: $typeWithArguments)${multipleUpperBoundsList()}{") + indent(2) + println("visitElement($varName)") + indent() + println("}") + println() + } + } + + for (element in elements) { + with(element) { + indent() + val varName = safeDecapitalizedName + println("final override fun ${typeParameters}visit$name($varName: $typeWithArguments, data: Nothing?)${multipleUpperBoundsList()}{") + indent(2) + println("visit$name($varName)") + indent() + println("}") + println() + } + } + println("}") + } + } +} + +fun Element.generateCode(generationPath: String) { + val dir = File(generationPath + packageName.replace(".", "/")) + dir.mkdirs() + val file = File(dir, "$type.kt") + file.printWriter().use { printer -> + with(printer) { + printCopyright() + println("package $packageName") + println() + val imports = collectImports() + imports.forEach { println("import $it") } + if (imports.isNotEmpty()) { + println() + } + printGeneratedMessage() + printElement(this@generateCode) + } + } +} + +fun Implementation.generateCode(generationPath: String) { + val dir = File(generationPath + packageName.replace(".", "/")) + dir.mkdirs() + val file = File(dir, "$type.kt") + file.printWriter().use { printer -> + with(printer) { + printCopyright() + println("package $packageName") + println() + val imports = collectImports() + imports.forEach { println("import $it") } + if (imports.isNotEmpty()) { + println() + } + printGeneratedMessage() + printImplementation(this@generateCode) + } + } +} + +fun Implementation.collectImports(): List { + return element.collectImportsInternal( + listOf(element.fullQualifiedName) + usedTypes.mapNotNull { it.fullQualifiedName } + parents.mapNotNull { it.fullQualifiedName }, + isImpl = true + ) +} + +fun Element.collectImports(): List { + val baseTypes = parents.mapTo(mutableListOf()) { it.fullQualifiedName } + baseTypes += parentsArguments.values.flatMap { it.values }.mapNotNull { it.fullQualifiedName } + val isBaseFirElement = this == AbstractFirTreeBuilder.baseFirElement + if (isBaseFirElement) { + baseTypes += compositeTransformResultType.fullQualifiedName!! + } + return collectImportsInternal( + baseTypes, + isImpl = false + ) +} + +fun Element.collectImportsInternal(base: List, isImpl: Boolean): List { + val fqns = base + allFields.mapNotNull { it.fullQualifiedName } + + allFields.flatMap { it.arguments.mapNotNull { it.fullQualifiedName } } + + typeArguments.flatMap { it.upperBounds.mapNotNull { it.fullQualifiedName } } + val realPackageName = if (isImpl) "$packageName.impl." else "$packageName." + return fqns.filter { fqn -> + fqn.dropLastWhile { it != '.' } != realPackageName + }.distinct().sorted() + "$VISITOR_PACKAGE.*" +} + +val Field.isVal: Boolean get() = this is FieldList || (this is FieldWithDefault && origin is FieldList) || !isMutable + +fun PrintWriter.printFieldWithDefaultInImplementation(field: Field) { + val defaultValue = field.defaultValue + indent() + print("override ") + if (field.isLateinit) { + print("lateinit ") + } + if (field.isVal) { + print("val") + } else { + print("var") + } + print(" ${field.name}: ${field.mutableType}") + if (field.isLateinit) { + println() + return + } else { + print(" ") + } + if (field.withGetter) { + if (field.customSetter != null) { + println() + indent(2) + } + print("get() ") + } + requireNotNull(defaultValue) { + "No default value for $field" + } + println("= $defaultValue") + field.customSetter?.let { + indent(2) + println("set(value) {") + indent(3) + println(it) + indent(2) + println("}") + } +} + +fun PrintWriter.printImplementation(implementation: Implementation) { + fun Field.transform() { + when (this) { + is FieldWithDefault -> origin.transform() + + is FirField -> + println("$name = ${name}${call()}transformSingle(transformer, data)") + + is FieldList -> { + println("${name}.transformInplace(transformer, data)") + } + + else -> throw IllegalStateException() + } + } + + with(implementation) { + print("${kind.title} $type") + print(element.typeParameters) + val fieldsWithoutDefault = allFields.filter { it.defaultValue == null && !it.isLateinit } + val fieldsWithDefault = allFields.filter { it.defaultValue != null || it.isLateinit } + + if (kind != Implementation.Kind.Interface && fieldsWithoutDefault.isNotEmpty()) { + println("(") + fieldsWithoutDefault.forEachIndexed { i, field -> + val end = if (i == fieldsWithoutDefault.size - 1) "" else "," + printField(field, isImplementation = true, override = true, end = end) + } + print(")") + } + + print(" : ${element.typeWithArguments}") + parents.forEach { + print(", ${it.typeWithArguments}") + } + println(" {") + + if (kind == Implementation.Kind.Interface) { + allFields.forEach { printField(it, isImplementation = true, override = true, end = "") } + } else { + fieldsWithDefault.forEach { + printFieldWithDefaultInImplementation(it) + } + if (fieldsWithDefault.isNotEmpty()) { + println() + } + } + + element.allFields.filter { it.type.contains("Symbol") } + .takeIf { it.isNotEmpty() && kind != Implementation.Kind.Interface && !element.type.contains("Reference")} + ?.let { symbolFields -> + indent(1) + println("init {") + for (symbolField in symbolFields) { + indent(2) + println("${symbolField.name}${symbolField.call()}bind(this)") + } + indent(1) + println("}") + println() + } + + indent(1) + print("override fun acceptChildren(visitor: FirVisitor, data: D) {") + + fun Field.acceptString(): String = "${name}${call()}accept(visitor, data)" + + if (element.allFirFields.isNotEmpty()) { + println() + for (field in allFields.filter { it.isFirType }) { + if (field.withGetter || !field.needAcceptAndTransform) continue + when (field.name) { + "explicitReceiver" -> { + val explicitReceiver = implementation["explicitReceiver"]!! + val dispatchReceiver = implementation["dispatchReceiver"]!! + val extensionReceiver = implementation["extensionReceiver"]!! + println(""" + | ${explicitReceiver.acceptString()} + | if (dispatchReceiver !== explicitReceiver) { + | ${dispatchReceiver.acceptString()} + | } + | if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) { + | ${extensionReceiver.acceptString()} + | } + """.trimMargin()) + } + + "dispatchReceiver", "extensionReceiver", "subjectVariable" -> {} + "companionObject" -> {} + + else -> { + if (type == "FirClassImpl" && field.name == "declarations") { + indent(2) + println("(declarations.firstOrNull { it is FirConstructorImpl } as? FirConstructorImpl)?.typeParameters?.forEach { it.accept(visitor, data) }") + } + if (type == "FirWhenExpressionImpl" && field.name == "subject") { + println( + """ + | if (subjectVariable != null) { + | subjectVariable.accept(visitor, data) + | } else { + | subject?.accept(visitor, data) + | } + """.trimMargin() + ) + } else { + indent(2) + when (field.origin) { + is FirField -> { + println(field.acceptString()) + } + + is FieldList -> { + println("${field.name}.forEach { it.accept(visitor, data) }") + } + + else -> throw IllegalStateException() + } + } + } + + } + } + indent() + } + println("}") + println() + + indent() + println("override fun transformChildren(transformer: FirTransformer, data: D): $typeWithArguments {") + for (field in allFields) { + when { + !field.isMutable || !field.isFirType || field.withGetter || !field.needAcceptAndTransform -> {} + field.name == "explicitReceiver" -> { + val explicitReceiver = implementation["explicitReceiver"]!! + val dispatchReceiver = implementation["dispatchReceiver"]!! + val extensionReceiver = implementation["extensionReceiver"]!! + if (explicitReceiver.isMutable) { + indent(2) + println("explicitReceiver = explicitReceiver${explicitReceiver.call()}transformSingle(transformer, data)") + } + if (dispatchReceiver.isMutable) { + println(""" + | if (dispatchReceiver !== explicitReceiver) { + | dispatchReceiver = dispatchReceiver.transformSingle(transformer, data) + | } + """.trimMargin()) + } + if (extensionReceiver.isMutable) { + println(""" + | if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) { + | extensionReceiver = extensionReceiver.transformSingle(transformer, data) + | } + """.trimMargin()) + } + } + field.name in setOf("dispatchReceiver", "extensionReceiver") -> {} + type == "FirClassImpl" && field.name == "declarations" -> { + indent(2) + println("(declarations.firstOrNull { it is FirConstructorImpl } as? FirConstructorImpl)?.typeParameters?.transformInplace(transformer, data)") + indent(2) + println("declarations.transformInplace(transformer, data)") + } + field.name == "companionObject" -> { + indent(2) + println("companionObject = declarations.asSequence().filterIsInstance().firstOrNull { it.status.isCompanion }") + } + field.needsSeparateTransform -> { + indent(2) + println("transform${field.name.capitalize()}(transformer, data)") + } + !element.needTransformOtherChildren -> { + indent(2) + field.transform() + } + else -> {} + } + } + if (element.needTransformOtherChildren) { + indent(2) + println("transformOtherChildren(transformer, data)") + } + indent(2) + println("return this") + indent() + println("}") + + for (field in allFields) { + if (!field.needsSeparateTransform) continue + println() + indent() + print("override ${field.transformFunctionDeclaration(typeWithArguments)} {") + println() + if (field.isMutable && field.isFirType) { + // TODO: replace with smth normal + if (type == "FirWhenExpressionImpl" && field.name == "subject") { + println(""" + | if (subjectVariable != null) { + | subjectVariable = subjectVariable?.transformSingle(transformer, data) + | } else { + | subject = subject?.transformSingle(transformer, data) + | } + """.trimMargin()) + } else { + indent(2) + field.transform() + } + } + indent(2) + println("return this") + indent() + println("}") + } + + if (element.needTransformOtherChildren) { + println() + indent() + println("override fun transformOtherChildren(transformer: FirTransformer, data: D): $typeWithArguments {") + for (field in allFields) { + if (!field.isMutable || !field.isFirType || field.name == "subjectVariable") continue + if (!field.needsSeparateTransform) { + indent(2) + field.transform() + } + } + indent(2) + println("return this") + indent() + println("}") + } + + for (field in allFields.filter { it.withReplace }) { + println() + indent() + print("override ${field.replaceFunctionDeclaration()} {") + if (!field.isMutable) { + println("}") + continue + } + println() + indent(2) + val newValue = "new${field.name.capitalize()}" + when { + field.withGetter -> { + } + + field.origin is FieldList -> { + println("${field.name}.clear()") + indent(2) + println("${field.name}.addAll($newValue)") + } + + else -> { + println("${field.name} = $newValue") + } + } + indent() + println("}") + } + + print("}") + } +} + +fun Field.transformFunctionDeclaration(returnType: String): String { + return transformFunctionDeclaration(name.capitalize(), returnType) +} + +fun transformFunctionDeclaration(transformName: String, returnType: String): String { + return "fun transform$transformName(transformer: FirTransformer, data: D): $returnType" +} + +fun Field.replaceFunctionDeclaration(): String { + val capName = name.capitalize() + return "fun replace$capName(new$capName: $typeWithArgumentsWithoutNullablity)" +} + +fun printTransformer(elements: List, generationPath: String) { + val dir = File(generationPath + VISITOR_PACKAGE.replace(".", "/")) + dir.mkdirs() + File(dir, "FirTransformer.kt").printWriter().use { printer -> + with(printer) { + printCopyright() + println("package $VISITOR_PACKAGE") + println() + elements.forEach { println("import ${it.fullQualifiedName}") } + println("import ${compositeTransformResultType.fullQualifiedName}") + println() + printGeneratedMessage() + + println("abstract class FirTransformer : FirVisitor, D>() {") + println() + indent() + println("abstract fun transformElement(element: E, data: D): CompositeTransformResult") + println() + for (element in elements) { + if (element == AbstractFirTreeBuilder.baseFirElement) continue + indent() + val varName = element.safeDecapitalizedName + print("open fun ") + element.typeParameters.takeIf { it.isNotBlank() }?.let { print(it) } + println("transform${element.name}($varName: ${element.typeWithArguments}, data: D): CompositeTransformResult<${element.transformerType.typeWithArguments}>${element.multipleUpperBoundsList()}{") + indent(2) + println("return transformElement($varName, data)") + indent() + println("}") + println() + } + + for (element in elements) { + indent() + val varName = element.safeDecapitalizedName + print("final override fun ") + element.typeParameters.takeIf { it.isNotBlank() }?.let { print(it) } + + println("visit${element.name}($varName: ${element.typeWithArguments}, data: D): CompositeTransformResult<${element.transformerType.typeWithArguments}>${element.multipleUpperBoundsList()}{") + indent(2) + println("return transform${element.name}($varName, data)") + indent() + println("}") + println() + } + println("}") + } + } +} + +fun PrintWriter.printField(field: Field, isImplementation: Boolean, override: Boolean, end: String) { + indent() + if (override) { + print("override ") + } + if (!isImplementation || field.isVal) { + print("val") + } else { + print("var") + } + val type = if (isImplementation) field.mutableType else field.typeWithArguments + println(" ${field.name}: $type$end") +} + +val Field.mutableType: String get() = when (this) { + is FieldList -> if (isMutable) "Mutable$typeWithArguments" else typeWithArguments + is FieldWithDefault -> if (isMutable) origin.mutableType else typeWithArguments + else -> typeWithArguments + } + +fun Field.call(): String = if (nullable) "?." else "." + +fun Element.multipleUpperBoundsList(): String { + return typeArguments.filterIsInstance().takeIf { it.isNotEmpty() }?.let { arguments -> + val upperBoundsList = arguments.joinToString(", ", postfix = " ") { argument -> + argument.upperBounds.joinToString(", ") { upperBound -> "${argument.name} : ${upperBound.typeWithArguments}" } + } + " where $upperBoundsList" + } ?: " " +} + +fun PrintWriter.printElement(element: Element) { + fun Element.override() { + indent() + if (this != AbstractFirTreeBuilder.baseFirElement) { + print("override ") + } + } + + with(element) { + print("interface $type") + if (typeArguments.isNotEmpty()) { + print(typeArguments.joinToString(", ", "<", ">") { it.toString() }) + } + if (parents.isNotEmpty()) { + print(" : ") + print(parents.joinToString(", ") { + var result = it.type + parentsArguments[it]?.let { arguments -> + result += arguments.values.joinToString(", ", "<", ">") { it.typeWithArguments } + } + result + }) + } + print(multipleUpperBoundsList()) + println("{") + allFields.forEach { + printField(it, isImplementation = false, override = it.fromParent, end = "") + } + if (allFields.isNotEmpty()) { + println() + } + + override() + println("fun accept(visitor: FirVisitor, data: D): R = visitor.visit$name(this, data)") + + fields.filter { it.withReplace }.forEach { + println() + indent() + if (it.fromParent) print("override ") + println(it.replaceFunctionDeclaration()) + } + + for (field in allFields) { + if (!field.needsSeparateTransform) continue + println() + indent() + if (field.fromParent) { + print("override ") + } + println(field.transformFunctionDeclaration(typeWithArguments)) + } + if (needTransformOtherChildren) { + println() + indent() + if (element.parents.any { it.needTransformOtherChildren }) { + print("override ") + } + println(transformFunctionDeclaration("OtherChildren", typeWithArguments)) + } + + if (element == AbstractFirTreeBuilder.baseFirElement) { + println() + indent() + println("fun accept(visitor: FirVisitorVoid) = accept(visitor, null)") + println() + indent() + println("fun acceptChildren(visitor: FirVisitor, data: D)") + println() + indent() + println("fun acceptChildren(visitor: FirVisitorVoid) = acceptChildren(visitor, null)") + println() + indent() + println("@Suppress(\"UNCHECKED_CAST\")") + indent() + println("fun transform(visitor: FirTransformer, data: D): CompositeTransformResult =") + indent(2) + println("accept(visitor, data) as CompositeTransformResult") + println() + indent() + println("fun transformChildren(transformer: FirTransformer, data: D): FirElement") + } + print("}") + } +} + +// --------------------------------------- Helpers --------------------------------------- + +fun PrintWriter.indent(n: Int = 1) { + print(INDENT.repeat(n)) +} + +val Element.safeDecapitalizedName: String get() = if (name == "Class") "klass" else name.decapitalize() + +val Importable.typeWithArguments: String + get() = when (this) { + is AbstractElement -> type + generics + is Implementation -> type + element.generics + is FirField -> element.typeWithArguments + if (nullable) "?" else "" + is Field -> type + generics + if (nullable) "?" else "" + is Type -> type + generics + is ImplementationWithArg -> type + generics + else -> throw IllegalArgumentException() + } + +val Importable.typeWithArgumentsWithoutNullablity: String get() = typeWithArguments.dropLastWhile { it == '?' } + +val ImplementationWithArg.generics: String + get() = argument?.let { "<${it.type}>" } ?: "" + +val AbstractElement.generics: String + get() = typeArguments.takeIf { it.isNotEmpty() } + ?.let { it.joinToString(", ", "<", ">") { it.name } } + ?: "" + +val Field.generics: String + get() = arguments.takeIf { it.isNotEmpty() } + ?.let { it.joinToString(", ", "<", ">") { it.typeWithArguments } } + ?: "" + +val Element.typeParameters: String + get() = typeArguments.takeIf { it.isNotEmpty() } + ?.joinToString(", ", "<", "> ") + ?: "" + +val Type.generics: String + get() = arguments.takeIf { it.isNotEmpty() }?.joinToString(",", "<", ">") ?: "" \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt new file mode 100644 index 00000000000..6718d9ac84e --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt @@ -0,0 +1,61 @@ +/* + * 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 + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.contracts.description.InvocationKind +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.fir.types.ConeClassErrorType +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.tree.generator.context.generatedType +import org.jetbrains.kotlin.fir.tree.generator.context.type +import org.jetbrains.kotlin.ir.expressions.IrConstKind +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.Variance + +val psiElementType = type(PsiElement::class) +val jumpTargetType = type("fir", "FirTarget") +val constKindType = type(IrConstKind::class) +val operationType = type("fir.expressions", "FirOperation") +val classKindType = type(ClassKind::class) +val invocationKindType = type(InvocationKind::class) +val varianceType = type(Variance::class) +val nameType = type(Name::class) +val visibilityType = type(Visibility::class) +val visibilitiesType = type(Visibilities::class) +val modalityType = type(Modality::class) +val fqNameType = type(FqName::class) +val classIdType = type(ClassId::class) +val annotationUseSiteTargetType = type(AnnotationUseSiteTarget::class) +val operationKindType = type("fir.expressions", "LogicOperationKind") +val coneKotlinTypeType = type(ConeKotlinType::class) +val whenSubjectType = type("fir", "FirWhenSubject") +val firSessionType = type("fir", "FirSession") +val emptyCfgReferenceType = generatedType("references.impl", "FirEmptyControlFlowGraphReference") +val noReceiverExpressionType = generatedType("expressions.impl", "FirNoReceiverExpression") +val implicitTypeRefType = generatedType("types.impl", "FirImplicitTypeRefImpl") +val firQualifierPartType = type("fir.types", "FirQualifierPart") +val coneClassErrorTypeType = type(ConeClassErrorType::class) +val simpleNamedReferenceType = generatedType("references.impl", "FirSimpleNamedReference") +val explicitThisReferenceType = generatedType("references.impl", "FirExplicitThisReference") +val explicitSuperReferenceType = generatedType("references.impl", "FirExplicitSuperReference") +val implicitBooleanTypeRefType = generatedType("types.impl", "FirImplicitBooleanTypeRef") +val implicitNothingTypeRefType = generatedType("types.impl", "FirImplicitNothingTypeRef") +val implicitStringTypeRefType = generatedType("types.impl", "FirImplicitStringTypeRef") +val implicitUnitTypeRefType = generatedType("types.impl", "FirImplicitUnitTypeRef") +val resolvePhaseType = type("fir.declarations", "FirResolvePhase") +val stubReferenceType = generatedType("references.impl", "FirStubReference") +val compositeTransformResultType = type("fir.visitors", "CompositeTransformResult") + +val abstractFirBasedSymbolType = type("fir.symbols", "AbstractFirBasedSymbol") +val backingFieldSymbolType = type("fir.symbols.impl", "FirBackingFieldSymbol") +val delegateFieldSymbolType = type("fir.symbols.impl", "FirDelegateFieldSymbol") \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFieldConfigurator.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFieldConfigurator.kt new file mode 100644 index 00000000000..ed9c564bd68 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFieldConfigurator.kt @@ -0,0 +1,80 @@ +/* + * 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.context + +import org.jetbrains.kotlin.fir.tree.generator.model.* + +abstract class AbstractFieldConfigurator { + inner class ConfigureContext(val element: Element) { + operator fun FieldSet.unaryPlus() { + element.fields.addAll(this.map { it.copy() }) + } + + operator fun Field.unaryPlus() { + val doesNotContains = element.fields.add(this.copy()) + require(doesNotContains) { + "$element already contains field $this}" + } + } + + fun generateBooleanFields(vararg names: String) { + names.forEach { + +booleanField("is${it.capitalize()}") + } + } + + fun withArg(name: String, vararg upperBounds: String) { + withArg(name, upperBounds.map { Type(null, it) }) + } + + fun withArg(name: String, upperBound: Importable, vararg upperBounds: Importable) { + val allUpperBounds = mutableListOf(upperBound).apply { this += upperBounds } + withArg(name, allUpperBounds) + } + + private fun withArg(name: String, upperBounds: List) { + element.typeArguments += when (upperBounds.size) { + in 0..1 -> SimpleTypeArgument(name, upperBounds.firstOrNull()) + else -> TypeArgumentWithMultipleUpperBounds(name, upperBounds.toList()) + } + } + + fun parentArg(parent: Element, argument: String, type: String) { + parentArg(parent, Type(null, argument), Type(null, type)) + } + + fun parentArg(parent: Element, argument: String, type: Importable) { + parentArg(parent, Type(null, argument), type) + } + + fun parentArg(parent: Element, argument: Importable, type: Importable) { + require(parent in element.parents) { + "$parent is not parent of $element" + } + val argMap = element.parentsArguments.getOrPut(parent) { mutableMapOf() } + require(argument !in argMap) { + "Argument $argument already defined for parent $parent of $element" + } + argMap[argument] = type + } + + fun Type.withArgs(vararg args: Importable): Pair> { + return this to args.toList() + } + + fun Type.withArgs(vararg args: String): Pair> { + return this to args.map { Type(null, it) } + } + + fun needTransformOtherChildren() { + element._needTransformOtherChildren = true + } + } + + inline fun Element.configure(block: ConfigureContext.() -> Unit) { + ConfigureContext(this).block() + } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeBuilder.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeBuilder.kt new file mode 100644 index 00000000000..b8c1bd4261e --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeBuilder.kt @@ -0,0 +1,55 @@ +/* + * 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.context + +import org.jetbrains.kotlin.fir.tree.generator.BASE_PACKAGE +import org.jetbrains.kotlin.fir.tree.generator.model.Element +import org.jetbrains.kotlin.fir.tree.generator.model.Type +import kotlin.reflect.KClass + +abstract class AbstractFirTreeBuilder { + companion object { + val baseFirElement = Element( + "Element", + Element.Kind.Other + ) + + const val string = "String" + const val boolean = "Boolean" + const val int = "Int" + } + + val elements = mutableListOf(baseFirElement) + + protected fun element(name: String, kind: Element.Kind, vararg dependencies: Element, init: Element.() -> Unit = {}): Element = + Element(name, kind).apply(init).also { + if (dependencies.isEmpty()) { + it.parents.add(baseFirElement) + } + it.parents.addAll(dependencies) + elements += it + } +} + +fun generatedType(type: String): Type = generatedType("", type) + +fun generatedType(packageName: String, type: String): Type { + val realPackage = BASE_PACKAGE + if (packageName.isNotBlank()) ".$packageName" else "" + return type(realPackage, type, exactPackage = true) +} + +fun type(packageName: String?, type: String, exactPackage: Boolean = false): Type { + val realPackage = if (exactPackage) packageName else packageName?.let { "org.jetbrains.kotlin.$it" } + return Type(realPackage, type) +} + +fun type(type: String): Type = type(null, type) + +fun type(klass: KClass<*>): Type { + val fqn = klass.qualifiedName!! + val name = klass.simpleName!! + return type(fqn.dropLast(name.length + 1), name, exactPackage = true) +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt new file mode 100644 index 00000000000..cdf413e4478 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/context/AbstractFirTreeImplementationConfigurator.kt @@ -0,0 +1,235 @@ +/* + * 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.context + +import org.jetbrains.kotlin.fir.tree.generator.call +import org.jetbrains.kotlin.fir.tree.generator.model.* +import org.jetbrains.kotlin.fir.tree.generator.noReceiverExpressionType + +abstract class AbstractFirTreeImplementationConfigurator { + private val elementsWithImpl = mutableSetOf() + + fun noImpl(element: Element) { + element.doesNotNeedImplementation = true + } + + fun impl(element: Element, name: String? = null, config: ImplementationContext.() -> Unit = {}): Implementation { + val implementation = if (name == null) { + element.defaultImplementation + } else { + element.customImplementations.firstOrNull { it.name == name } + } ?: Implementation(element, name) + val context = ImplementationContext(implementation) + context.apply(config) + implementation.updateMutabilityAccordingParents() + elementsWithImpl += element + return implementation + } + + protected fun generateDefaultImplementations(builder: AbstractFirTreeBuilder) { + collectLeafsWithoutImplementation(builder).forEach { + impl(it) + } + } + + protected fun configureFieldInAllImplementations( + field: String, + implementationPredicate: ((Implementation) -> Boolean)? = null, + fieldPredicate: ((Field) -> Boolean)? = null, + init: ImplementationContext.(field: String) -> Unit + ) { + for (element in elementsWithImpl) { + for (implementation in element.allImplementations) { + if (implementationPredicate != null && !implementationPredicate(implementation)) continue + if (!implementation.allFields.any { it.name == field }) continue + if (fieldPredicate != null && !fieldPredicate(implementation.getField(field))) continue + ImplementationContext(implementation).init(field) + } + } + } + + private fun collectLeafsWithoutImplementation(builder: AbstractFirTreeBuilder): Set { + val elements = builder.elements.toMutableSet() + builder.elements.forEach { + elements.removeAll(it.parents) + } + 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) + } + + inner class ParentsHolder { + operator fun plusAssign(parent: Implementation) { + implementation.addParent(parent) + } + + operator fun plusAssign(parent: ImplementationWithArg) { + implementation.addParent(parent.implementation, parent.argument) + parent.argument?.let { useTypes(it) } + } + } + + val parents = ParentsHolder() + + fun Implementation.withArg(argument: Importable): ImplementationWithArg = ImplementationWithArg(this, argument) + + fun useTypes(vararg types: Importable) { + types.forEach { implementation.usedTypes += it } + } + + fun lateinit(vararg fields: String) { + for (fieldName in fields) { + val field = getField(fieldName) + require(field.origin !is FieldList) + field.isLateinit = true + field.isMutable = true + } + } + + fun isMutable(vararg fields: String) { + fields.forEach { + val field = getField(it) + field.isMutable = true + } + } + + fun defaultNoReceivers() { + defaultNull("explicitReceiver") + default("dispatchReceiver", "FirNoReceiverExpression") + default("extensionReceiver", "FirNoReceiverExpression") + useTypes(noReceiverExpressionType) + } + + fun default(field: String, value: String) { + default(field) { + this.value = value + } + } + + fun defaultTrue(field: String, 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 noPsi() { + defaultNull("psi") + } + + fun defaultEmptyList(field: String) { + require(getField(field).origin is FieldList) { + "$field is list field" + } + default(field) { + value = "emptyList()" + withGetter = true + } + } + + fun defaultSupertypesComputationStatus() { + default("supertypesComputationStatus", "SupertypesComputationStatus.NOT_COMPUTED") + } + + fun default(field: String, init: DefaultValueContext.() -> Unit) { + DefaultValueContext(getField(field)).apply(init).applyConfiguration() + } + + fun delegateFields(fields: List, delegate: String) { + for (field in fields) { + default(field) { + this.delegate = delegate + } + } + } + + var kind: Implementation.Kind + 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 + + fun applyConfiguration() { + field.withGetter = withGetter + field.customSetter = customSetter + isMutable?.let { field.isMutable = it } + field.needAcceptAndTransform = needAcceptAndTransform + when { + value != null -> field.defaultValue = value + delegate != null -> { + val actualDelegateField = getField(delegate!!) + val name = delegateCall ?: field.name + field.defaultValue = "${actualDelegateField.name}${actualDelegateField.call()}$name" + } + } + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt new file mode 100644 index 00000000000..268fb68bd9e --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Element.kt @@ -0,0 +1,147 @@ +/* + * 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.model + +import org.jetbrains.kotlin.fir.tree.generator.BASE_PACKAGE +import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments + +interface FieldContainer { + val allFields: List + operator fun get(fieldName: String): Field? +} + +interface AbstractElement : FieldContainer, Importable { + val fields: Set + val parents: List + val typeArguments: List + val parentsArguments: Map> + val baseTransformerType: AbstractElement? + val transformerType: AbstractElement + val doesNotNeedImplementation: Boolean + val needTransformOtherChildren: Boolean + val allImplementations: List + val allFirFields: List + val defaultImplementation: Implementation? + val customImplementations: List +} + +class Element(val name: String, kind: Kind) : AbstractElement { + override val fields = mutableSetOf() + override val type: String = "Fir$name" + override val packageName: String = BASE_PACKAGE + kind.packageName.let { if (it.isBlank()) it else "." + it } + override val fullQualifiedName: String get() = super.fullQualifiedName!! + override val parents = mutableListOf() + override var defaultImplementation: Implementation? = null + override val customImplementations = mutableListOf() + override val typeArguments = mutableListOf() + override val parentsArguments = mutableMapOf>() + var _needTransformOtherChildren: Boolean = false + + override var baseTransformerType: Element? = null + override val transformerType: Element get() = baseTransformerType ?: this + + override var doesNotNeedImplementation: Boolean = false + + override val needTransformOtherChildren: Boolean get() = _needTransformOtherChildren || parents.any { it.needTransformOtherChildren } + + override val allImplementations: List by lazy { + if (doesNotNeedImplementation) { + emptyList() + } else { + val implementations = customImplementations.toMutableList() + defaultImplementation?.let { implementations += it } + implementations + } + } + + override val allFields: List by lazy { + val result = LinkedHashSet() + result.addAll(fields.toList().asReversed()) + for (field in parentFields.asReversed()) { + val overrides = !result.add(field) + if (overrides) { + val existingField = result.first { it == field } + if (field.name != "symbol" && field.type == existingField.type) println("Duplicate [element: $this, field: $field]") + existingField.fromParent = true + existingField.needsSeparateTransform = existingField.needsSeparateTransform || field.needsSeparateTransform + } + } + result.toList().asReversed() + } + + val parentFields: List by lazy { + val result = LinkedHashSet() + parents.forEach { parent -> + val fields = parent.allFields.map { field -> + val copy = (field as? SimpleField)?.let { simpleField -> + parentsArguments[parent]?.get(Type(null, simpleField.type))?.let { + simpleField.replaceType(Type(it.packageName, it.type)) + } + } ?: field.copy() + copy.apply { + arguments.replaceAll { + parentsArguments[parent]?.get(it) ?: it + } + fromParent = true + } + } + result.addAll(fields) + } + result.toList() + } + + override val allFirFields: List by lazy { + allFields.filter { it.isFirType } + } + + override fun toString(): String { + return typeWithArguments + } + + override fun get(fieldName: String): Field? { + return allFields.firstOrNull { it.name == fieldName } + } + + enum class Kind(val packageName: String) { + Expression("expressions"), + Declaration("declarations"), + Reference("references"), + TypeRef("types"), + Other("") + } +} + +class ElementWithArguments(val element: Element, override val typeArguments: List) : AbstractElement by element { + override fun equals(other: Any?): Boolean { + return element.equals(other) + } + + override fun hashCode(): Int { + return element.hashCode() + } +} + +sealed class TypeArgument(val name: String) { + abstract val upperBounds: List +} + +class SimpleTypeArgument(name: String, val upperBound: Importable?) : TypeArgument(name) { + override val upperBounds: List = listOfNotNull(upperBound) + + override fun toString(): String { + var result = name + if (upperBound != null) { + result += " : ${upperBound.typeWithArguments}" + } + return result + } +} + +class TypeArgumentWithMultipleUpperBounds(name: String, override val upperBounds: List) : TypeArgument(name) { + override fun toString(): String { + return name + } +} diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/ElementUtils.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/ElementUtils.kt new file mode 100644 index 00000000000..0aeb84bdcb0 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/ElementUtils.kt @@ -0,0 +1,92 @@ +/* + * 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.model + +import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder +import org.jetbrains.kotlin.fir.tree.generator.context.type +import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments + +// ----------- Simple field ----------- + +fun field(name: String, type: String, packageName: String?, customType: Importable? = null, nullable: Boolean = false, withReplace: Boolean = false): Field { + return SimpleField(name, type, packageName, customType, nullable, withReplace) +} + +fun field(name: String, type: Type, nullable: Boolean = false, withReplace: Boolean = false): Field { + return SimpleField(name, type.typeWithArguments, type.packageName, null, nullable, withReplace) +} + +fun field(name: String, typeWithArgs: Pair>, nullable: Boolean = false, withReplace: Boolean = false): Field { + val (type, args) = typeWithArgs + return SimpleField(name, type.typeWithArguments, type.packageName, null, nullable, withReplace).apply { + arguments += args + } +} + +fun field(type: Type, nullable: Boolean = false, withReplace: Boolean = false): Field { + return SimpleField(type.type.decapitalize(), type.typeWithArguments, type.packageName, null, nullable, withReplace) +} + +fun booleanField(name: String): Field { + return field(name, AbstractFirTreeBuilder.boolean, null) +} + +fun stringField(name: String, nullable: Boolean = false): Field { + return field(name, AbstractFirTreeBuilder.string, null, null, nullable) +} + +fun intField(name: String): Field { + return field(name, AbstractFirTreeBuilder.int, null) +} + +// ----------- Fir field ----------- + +fun field(name: String, type: Type, argument: String? = null, nullable: Boolean = false, withReplace: Boolean = false): Field { + return if (argument == null) { + field(name, type, nullable, withReplace) + } else { + field(name, type to listOf(type(argument)), nullable, withReplace) + } +} + +fun field(name: String, element: AbstractElement, nullable: Boolean = false, withReplace: Boolean = false): Field { + return FirField(name, element, nullable, withReplace) +} + +fun field(element: Element, nullable: Boolean = false, withReplace: Boolean = false): Field { + return FirField(element.name.decapitalize(), element, nullable, withReplace) +} + +// ----------- Field list ----------- + +fun fieldList(name: String, type: Importable, withReplace: Boolean = false): Field { + return FieldList(name, type, withReplace) +} + +fun fieldList(element: Element, withReplace: Boolean = false): Field { + return FieldList(element.name.decapitalize() + "s", element, withReplace) +} + +// ----------- Field set ----------- + +typealias FieldSet = List + +fun fieldSet(vararg fields: Field): FieldSet { + return fields.toList() +} + +@JvmName("foo") +infix fun FieldSet.with(sets: List
): FieldSet { + return sets.flatten() +} + +infix fun FieldSet.with(set: FieldSet): FieldSet { + return this + set +} + +fun Field.withTransform(): Field = copy().apply { needsSeparateTransform = true } + +fun FieldSet.withTransform(): FieldSet = this.map { it.withTransform() } \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt new file mode 100644 index 00000000000..11bed1b7dfe --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Field.kt @@ -0,0 +1,181 @@ +/* + * 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.model + +import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments + +sealed class Field : Importable { + abstract val name: String + open val arguments = mutableListOf() + abstract val nullable: Boolean + abstract val withReplace: Boolean + abstract val isFirType: Boolean + + var fromParent: Boolean = false + open var needsSeparateTransform: Boolean = false + + open val defaultValue: String? get() = null + abstract var isMutable: Boolean + open var isMutableInInterface: Boolean = false + open val withGetter: Boolean get() = false + open val isLateinit: Boolean get() = false + open val customSetter: String? get() = null + open val fromDelegate: Boolean get() = false + + fun copy(): Field = internalCopy().also { + updateFieldsInCopy(it) + } + + protected fun updateFieldsInCopy(copy: Field) { + copy.arguments.clear() + copy.arguments.addAll(arguments) + copy.needsSeparateTransform = needsSeparateTransform + copy.fromParent = fromParent + copy.isMutable = isMutable + } + + protected abstract fun internalCopy(): Field + + override fun toString(): String { + return name + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null) return false + if (javaClass != other.javaClass) return false + other as Field + return name == other.name + } + + override fun hashCode(): Int { + return name.hashCode() + } +} + +// ----------- Field with default ----------- + +class FieldWithDefault(val origin: Field) : Field() { + override val name: String get() = origin.name + override val type: String get() = origin.type + override val nullable: Boolean get() = origin.nullable + override val withReplace: Boolean get() = origin.withReplace + override val packageName: String? get() = origin.packageName + override val isFirType: Boolean get() = origin.isFirType + override var needsSeparateTransform: Boolean + get() = origin.needsSeparateTransform + set(_) {} + + override val arguments: MutableList + get() = origin.arguments + + override var defaultValue: String? = origin.defaultValue + override var isMutable: Boolean = origin.isMutable + override var isMutableInInterface: Boolean = origin.isMutableInInterface + override var withGetter: Boolean = false + override var isLateinit: Boolean = false + override var customSetter: String? = null + override var fromDelegate: Boolean = false + var needAcceptAndTransform: Boolean = true + + override fun internalCopy(): Field { + return FieldWithDefault(origin).also { + it.defaultValue = defaultValue + it.isMutable = isMutable + it.withGetter = withGetter + it.isLateinit = isLateinit + it.fromDelegate = fromDelegate + it.needAcceptAndTransform = needAcceptAndTransform + } + } +} + +open class SimpleField( + override val name: String, + override val type: String, + override val packageName: String?, + val customType: Importable? = null, + override val nullable: Boolean, + override val withReplace: Boolean +) : Field() { + override val isFirType: Boolean = false + override val fullQualifiedName: String? + get() = customType?.fullQualifiedName ?: super.fullQualifiedName + + override var isMutable: Boolean = false + + override fun internalCopy(): Field { + return SimpleField( + name, + type, + packageName, + customType, + nullable, + withReplace + ) + } + + fun replaceType(newType: Type) = SimpleField( + name, + newType.type, + newType.packageName, + customType, + nullable, + withReplace + ).also { + updateFieldsInCopy(it) + } +} + +class FirField( + override val name: String, + val element: AbstractElement, + override val nullable: Boolean, + override val withReplace: Boolean +) : Field() { + override val type: String get() = element.type + override val packageName: String? get() = element.packageName + override val isFirType: Boolean = true + + override var isMutable: Boolean = true + + override fun internalCopy(): Field { + return FirField( + name, + element, + nullable, + withReplace + ) + } +} + +// ----------- Field list ----------- + +class FieldList( + override val name: String, + val baseType: Importable, + override val withReplace: Boolean +) : Field() { + override val defaultValue: String? get() = if (isMutable) "mutableListOf()" else "emptyListOf()" + override val packageName: String? get() = baseType.packageName + override val fullQualifiedName: String? get() = baseType.fullQualifiedName + override val type: String = "List<${baseType.typeWithArguments}>" + + override val nullable: Boolean + get() = false + + override var isMutable: Boolean = true + + override fun internalCopy(): Field { + return FieldList( + name, + baseType, + withReplace + ) + } + + override val isFirType: Boolean = baseType is Element +} diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Implementation.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Implementation.kt new file mode 100644 index 00000000000..4baef748e4a --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Implementation.kt @@ -0,0 +1,64 @@ +/* + * 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.model + +class ImplementationWithArg( + val implementation: Implementation, + val argument: Importable? +) : Importable by implementation, FieldContainer by implementation { + val element: Element get() = implementation.element +} + +class Implementation(val element: Element, val name: String?) : Importable, FieldContainer { + private val _parents = mutableListOf() + val parents: List get() = _parents + + val isDefault = name == null + override val type = name ?: element.type + "Impl" + override val allFields = element.allFields.toMutableList().mapTo(mutableListOf()) { + FieldWithDefault(it) + } + var kind: Kind = Kind.FinalClass + + override val packageName = element.packageName + ".impl" + val usedTypes = mutableListOf() + + init { + if (isDefault) { + element.defaultImplementation = this + } else { + element.customImplementations += this + } + } + + fun addParent(parent: Implementation, arg: Importable? = null) { + _parents += ImplementationWithArg(parent, arg) + } + + override fun get(fieldName: String): FieldWithDefault? { + return allFields.firstOrNull { it.name == fieldName } + } + + fun updateMutabilityAccordingParents() { + for (parent in parents) { + for (field in allFields) { + val fieldFromParent = parent[field.name] ?: continue + field.isMutable = field.isMutable || fieldFromParent.isMutable + if (field.isMutable && field.customSetter == null) { + field.withGetter = false + } + } + } + } + + enum class Kind(val title: String) { + Interface("interface"), + FinalClass("class"), + OpenClass("open class"), + AbstractClass("abstract class"), + Object("object") + } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Importable.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Importable.kt new file mode 100644 index 00000000000..fa2279bccc0 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Importable.kt @@ -0,0 +1,12 @@ +/* + * 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.model + +interface Importable { + val type: String + val packageName: String? + val fullQualifiedName: String? get() = packageName?.let { "$it.${type.replace(Regex("<.+>"), "")}" } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Type.kt b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Type.kt new file mode 100644 index 00000000000..9584284ab43 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/org/jetbrains/kotlin/fir/tree/generator/model/Type.kt @@ -0,0 +1,10 @@ +/* + * 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.model + +data class Type(override val packageName: String?, override val type: String) : Importable { + val arguments = mutableListOf() +} \ No newline at end of file