FirRenderer: extract separate printer & visitor

This commit is contained in:
Mikhail Glukhikh
2022-07-01 18:04:18 +02:00
committed by Space
parent 38d6f3d548
commit f64a7d3ff9
5 changed files with 1184 additions and 1167 deletions
@@ -50,12 +50,14 @@ fun CFGNode<*>.render(): String =
is ConstExpressionNode -> "Const: ${fir.render()}" is ConstExpressionNode -> "Const: ${fir.render()}"
is VariableDeclarationNode -> is VariableDeclarationNode ->
"Variable declaration: ${buildString { "Variable declaration: ${
buildString {
FirRenderer( FirRenderer(
this, this,
CfgRenderMode CfgRenderMode
).visitCallableDeclaration(fir) ).Visitor().visitCallableDeclaration(fir)
}}" }
}"
is VariableAssignmentNode -> "Assignment: ${fir.lValue.render(CfgRenderMode)}" is VariableAssignmentNode -> "Assignment: ${fir.lValue.render(CfgRenderMode)}"
is FunctionCallNode -> "Function call: ${fir.render(CfgRenderMode)}" is FunctionCallNode -> "Function call: ${fir.render(CfgRenderMode)}"
@@ -83,8 +83,8 @@ val FirContextReceiver.labelName: Name? get() = customLabelName ?: labelNameFrom
fun FirElement.renderWithType(mode: FirRenderer.RenderMode = FirRenderer.RenderMode.Normal): String = buildString { fun FirElement.renderWithType(mode: FirRenderer.RenderMode = FirRenderer.RenderMode.Normal): String = buildString {
append(this@renderWithType) append(this@renderWithType)
append(": ") append(": ")
this@renderWithType.accept(FirRenderer(this, mode)) this@renderWithType.accept(FirRenderer(this, mode).Visitor())
} }
fun FirElement.render(mode: FirRenderer.RenderMode = FirRenderer.RenderMode.Normal): String = fun FirElement.render(mode: FirRenderer.RenderMode = FirRenderer.RenderMode.Normal): String =
buildString { this@render.accept(FirRenderer(this, mode)) } buildString { this@render.accept(FirRenderer(this, mode).Visitor()) }
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2022 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.renderer
import org.jetbrains.kotlin.utils.Printer
abstract class FirPrinter internal constructor(builder: StringBuilder) {
private val printer = Printer(builder)
private var lineBeginning = true
protected fun print(vararg objects: Any) {
if (lineBeginning) {
lineBeginning = false
printer.print(*objects)
} else {
printer.printWithNoIndent(*objects)
}
}
protected fun println(vararg objects: Any) {
print(*objects)
printer.printlnWithNoIndent()
lineBeginning = true
}
protected fun pushIndent() {
printer.pushIndent()
}
protected fun popIndent() {
printer.popIndent()
}
protected fun newLine() {
println()
}
}
@@ -32,12 +32,11 @@ import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.* import java.util.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = RenderMode.Normal) : FirVisitorVoid() { open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = RenderMode.Normal) : FirPrinter(builder) {
companion object { companion object {
private val visibilitiesToRenderEffectiveSet = setOf( private val visibilitiesToRenderEffectiveSet = setOf(
Visibilities.Private, Visibilities.PrivateToThis, Visibilities.Internal, Visibilities.Private, Visibilities.PrivateToThis, Visibilities.Internal,
@@ -133,54 +132,14 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
} }
} }
private val printer = Printer(builder) private val visitor = Visitor()
private var lineBeginning = true
private fun print(vararg objects: Any) {
if (lineBeginning) {
lineBeginning = false
printer.print(*objects)
} else {
printer.printWithNoIndent(*objects)
}
}
private fun println(vararg objects: Any) {
print(*objects)
printer.printlnWithNoIndent()
lineBeginning = true
}
private fun pushIndent() {
printer.pushIndent()
}
private fun popIndent() {
printer.popIndent()
}
fun newLine() {
println()
}
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitFile(file: FirFile) {
println("FILE: ${file.name}")
pushIndent()
visitElement(file)
popIndent()
}
private fun List<FirElement>.renderSeparated() { private fun List<FirElement>.renderSeparated() {
for ((index, element) in this.withIndex()) { for ((index, element) in this.withIndex()) {
if (index > 0) { if (index > 0) {
print(", ") print(", ")
} }
element.accept(this@FirRenderer) element.accept(visitor)
} }
} }
@@ -190,7 +149,7 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
print(",") print(",")
newLine() newLine()
} }
element.accept(this@FirRenderer) element.accept(visitor)
} }
} }
@@ -217,7 +176,7 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
private fun List<FirAnnotation>.renderAnnotations() { private fun List<FirAnnotation>.renderAnnotations() {
if (!mode.renderAnnotation) return if (!mode.renderAnnotation) return
for (annotation in this) { for (annotation in this) {
visitAnnotation(annotation) visitor.visitAnnotation(annotation)
} }
} }
@@ -230,42 +189,6 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
} }
} }
override fun visitCallableDeclaration(callableDeclaration: FirCallableDeclaration) {
renderContexts(callableDeclaration.contextReceivers)
callableDeclaration.annotations.renderAnnotations()
visitMemberDeclaration(callableDeclaration)
val receiverType = callableDeclaration.receiverTypeRef
print(" ")
if (receiverType != null) {
receiverType.accept(this)
print(".")
}
when (callableDeclaration) {
is FirSimpleFunction -> {
if (!mode.renderCallableFqNames) {
print(callableDeclaration.name)
} else {
print(callableDeclaration.symbol.callableId)
}
}
is FirVariable -> {
if (!mode.renderCallableFqNames) {
print(callableDeclaration.name)
} else {
print(callableDeclaration.symbol.callableId)
}
}
else -> {}
}
if (callableDeclaration is FirFunction) {
callableDeclaration.valueParameters.renderParameters()
}
print(": ")
callableDeclaration.returnTypeRef.accept(this)
callableDeclaration.renderContractDescription()
}
private fun renderContexts(contextReceivers: List<FirContextReceiver>) { private fun renderContexts(contextReceivers: List<FirContextReceiver>) {
if (contextReceivers.isEmpty()) return if (contextReceivers.isEmpty()) return
print("context(") print("context(")
@@ -274,18 +197,10 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
newLine() newLine()
} }
override fun visitContextReceiver(contextReceiver: FirContextReceiver) {
contextReceiver.customLabelName?.let {
print(it.asString() + "@")
}
contextReceiver.typeRef.accept(this)
}
private fun FirDeclaration.renderContractDescription() { private fun FirDeclaration.renderContractDescription() {
val contractDescription = (this as? FirContractDescriptionOwner)?.contractDescription ?: return val contractDescription = (this as? FirContractDescriptionOwner)?.contractDescription ?: return
pushIndent() pushIndent()
contractDescription.accept(this@FirRenderer) contractDescription.accept(visitor)
popIndent() popIndent()
} }
@@ -328,6 +243,168 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
} }
} }
private fun FirDeclaration.renderDeclarationData() {
renderDeclarationResolvePhaseIfNeeded()
renderDeclarationAttributesIfNeeded()
renderDeclarationOriginIfNeeded()
}
private fun FirDeclaration.renderDeclarationResolvePhaseIfNeeded() {
if (mode.renderDeclarationResolvePhase) {
print("[${resolvePhase}] ")
}
}
private fun FirDeclaration.renderDeclarationAttributesIfNeeded() {
if (mode.renderDeclarationAttributes && attributes.isNotEmpty()) {
val attributes = getAttributesWithValues().mapNotNull { (klass, value) ->
value?.let { klass.simpleName to value.renderAsDeclarationAttributeValue() }
}.joinToString { (name, value) -> "$name=$value" }
print("[$attributes] ")
}
}
private fun FirDeclaration.renderDeclarationOriginIfNeeded() {
if (mode.renderDeclarationOrigin) {
print("[$origin] ")
}
}
private fun FirDeclaration.getAttributesWithValues(): List<Pair<KClass<out FirDeclarationDataKey>, Any?>> {
val attributesMap = FirDeclarationDataRegistry.allValuesThreadUnsafeForRendering()
return attributesMap.entries.sortedBy { it.key.simpleName }.map { (klass, index) -> klass to attributes[index] }
}
private fun Any.renderAsDeclarationAttributeValue() = when (this) {
is FirCallableSymbol<*> -> callableId.toString()
is FirClassLikeSymbol<*> -> classId.asString()
is FirProperty -> symbol.callableId.toString()
else -> toString()
}
protected fun List<FirDeclaration>.renderDeclarations() {
renderInBraces {
for (declaration in this) {
declaration.accept(visitor)
println()
}
}
}
fun renderInBraces(leftBrace: String = "{", rightBrace: String = "}", f: () -> Unit) {
println(" $leftBrace")
pushIndent()
f()
popIndent()
println(rightBrace)
}
fun renderSupertypes(regularClass: FirRegularClass) {
if (regularClass.superTypeRefs.isNotEmpty()) {
print(" : ")
regularClass.superTypeRefs.renderSeparated()
}
}
protected open fun renderClassDeclarations(regularClass: FirRegularClass) {
if (mode.renderNestedDeclarations) {
regularClass.declarations.renderDeclarations()
}
}
private fun FirBlock.renderBody(additionalStatements: List<FirStatement> = emptyList()) {
if (!mode.renderBodies) return
when (this) {
is FirLazyBlock -> {
println(" { LAZY_BLOCK }")
}
else -> {
renderAnnotations(this)
renderInBraces {
for (statement in additionalStatements + statements) {
statement.accept(visitor)
println()
}
}
}
}
}
private fun Map<Name, FirElement>.renderSeparated() {
for ((index, element) in this.entries.withIndex()) {
val (name, argument) = element
if (index > 0) {
print(", ")
}
print("$name = ")
argument.accept(visitor)
}
}
private fun visitAssignment(operation: FirOperation, rValue: FirExpression) {
print(operation.operator)
print(" ")
rValue.accept(visitor)
}
inner class Visitor : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitFile(file: FirFile) {
println("FILE: ${file.name}")
pushIndent()
visitElement(file)
popIndent()
}
override fun visitCallableDeclaration(callableDeclaration: FirCallableDeclaration) {
renderContexts(callableDeclaration.contextReceivers)
callableDeclaration.annotations.renderAnnotations()
visitMemberDeclaration(callableDeclaration)
val receiverType = callableDeclaration.receiverTypeRef
print(" ")
if (receiverType != null) {
receiverType.accept(this)
print(".")
}
when (callableDeclaration) {
is FirSimpleFunction -> {
if (!mode.renderCallableFqNames) {
print(callableDeclaration.name)
} else {
print(callableDeclaration.symbol.callableId)
}
}
is FirVariable -> {
if (!mode.renderCallableFqNames) {
print(callableDeclaration.name)
} else {
print(callableDeclaration.symbol.callableId)
}
}
else -> {}
}
if (callableDeclaration is FirFunction) {
callableDeclaration.valueParameters.renderParameters()
}
print(": ")
callableDeclaration.returnTypeRef.accept(this)
callableDeclaration.renderContractDescription()
}
override fun visitContextReceiver(contextReceiver: FirContextReceiver) {
contextReceiver.customLabelName?.let {
print(it.asString() + "@")
}
contextReceiver.typeRef.accept(this)
}
override fun visitTypeParameterRef(typeParameterRef: FirTypeParameterRef) { override fun visitTypeParameterRef(typeParameterRef: FirTypeParameterRef) {
typeParameterRef.symbol.fir.accept(this) typeParameterRef.symbol.fir.accept(this)
} }
@@ -439,70 +516,6 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
) )
} }
private fun FirDeclaration.renderDeclarationData() {
renderDeclarationResolvePhaseIfNeeded()
renderDeclarationAttributesIfNeeded()
renderDeclarationOriginIfNeeded()
}
private fun FirDeclaration.renderDeclarationResolvePhaseIfNeeded() {
if (mode.renderDeclarationResolvePhase) {
print("[${resolvePhase}] ")
}
}
private fun FirDeclaration.renderDeclarationAttributesIfNeeded() {
if (mode.renderDeclarationAttributes && attributes.isNotEmpty()) {
val attributes = getAttributesWithValues().mapNotNull { (klass, value) ->
value?.let { klass.simpleName to value.renderAsDeclarationAttributeValue() }
}.joinToString { (name, value) -> "$name=$value" }
print("[$attributes] ")
}
}
private fun FirDeclaration.renderDeclarationOriginIfNeeded() {
if (mode.renderDeclarationOrigin) {
print("[$origin] ")
}
}
private fun FirDeclaration.getAttributesWithValues(): List<Pair<KClass<out FirDeclarationDataKey>, Any?>> {
val attributesMap = FirDeclarationDataRegistry.allValuesThreadUnsafeForRendering()
return attributesMap.entries.sortedBy { it.key.simpleName }.map { (klass, index) -> klass to attributes[index] }
}
private fun Any.renderAsDeclarationAttributeValue() = when (this) {
is FirCallableSymbol<*> -> callableId.toString()
is FirClassLikeSymbol<*> -> classId.asString()
is FirProperty -> symbol.callableId.toString()
else -> toString()
}
protected fun List<FirDeclaration>.renderDeclarations() {
renderInBraces {
for (declaration in this) {
declaration.accept(this@FirRenderer)
println()
}
}
}
fun renderInBraces(leftBrace: String = "{", rightBrace: String = "}", f: () -> Unit) {
println(" $leftBrace")
pushIndent()
f()
popIndent()
println(rightBrace)
}
fun renderSupertypes(regularClass: FirRegularClass) {
if (regularClass.superTypeRefs.isNotEmpty()) {
print(" : ")
regularClass.superTypeRefs.renderSeparated()
}
}
override fun visitRegularClass(regularClass: FirRegularClass) { override fun visitRegularClass(regularClass: FirRegularClass) {
renderContexts(regularClass.contextReceivers) renderContexts(regularClass.contextReceivers)
regularClass.annotations.renderAnnotations() regularClass.annotations.renderAnnotations()
@@ -511,12 +524,6 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
renderClassDeclarations(regularClass) renderClassDeclarations(regularClass)
} }
protected open fun renderClassDeclarations(regularClass: FirRegularClass) {
if (mode.renderNestedDeclarations) {
regularClass.declarations.renderDeclarations()
}
}
override fun visitEnumEntry(enumEntry: FirEnumEntry) { override fun visitEnumEntry(enumEntry: FirEnumEntry) {
visitCallableDeclaration(enumEntry) visitCallableDeclaration(enumEntry)
enumEntry.initializer?.let { enumEntry.initializer?.let {
@@ -696,24 +703,6 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
anonymousInitializer.body?.renderBody() anonymousInitializer.body?.renderBody()
} }
private fun FirBlock.renderBody(additionalStatements: List<FirStatement> = emptyList()) {
if (!mode.renderBodies) return
when (this) {
is FirLazyBlock -> {
println(" { LAZY_BLOCK }")
}
else -> {
renderAnnotations(this)
renderInBraces {
for (statement in additionalStatements + statements) {
statement.accept(this@FirRenderer)
println()
}
}
}
}
}
override fun visitBlock(block: FirBlock) { override fun visitBlock(block: FirBlock) {
block.renderBody() block.renderBody()
} }
@@ -1049,17 +1038,6 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
print(")") print(")")
} }
private fun Map<Name, FirElement>.renderSeparated() {
for ((index, element) in this.entries.withIndex()) {
val (name, argument) = element
if (index > 0) {
print(", ")
}
print("$name = ")
argument.accept(this@FirRenderer)
}
}
override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall) { override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall) {
val dispatchReceiver = delegatedConstructorCall.dispatchReceiver val dispatchReceiver = delegatedConstructorCall.dispatchReceiver
if (dispatchReceiver !is FirNoReceiverExpression) { if (dispatchReceiver !is FirNoReceiverExpression) {
@@ -1336,12 +1314,6 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
visitQualifiedAccessExpression(expressionWithSmartcast) visitQualifiedAccessExpression(expressionWithSmartcast)
} }
private fun visitAssignment(operation: FirOperation, rValue: FirExpression) {
print(operation.operator)
print(" ")
rValue.accept(this)
}
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment) { override fun visitVariableAssignment(variableAssignment: FirVariableAssignment) {
variableAssignment.annotations.renderAnnotations() variableAssignment.annotations.renderAnnotations()
visitQualifiedAccess(variableAssignment) visitQualifiedAccess(variableAssignment)
@@ -1387,9 +1359,9 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
assignmentOperatorStatement.annotations.renderAnnotations() assignmentOperatorStatement.annotations.renderAnnotations()
print(assignmentOperatorStatement.operation.operator) print(assignmentOperatorStatement.operation.operator)
print("(") print("(")
assignmentOperatorStatement.leftArgument.accept(this@FirRenderer) assignmentOperatorStatement.leftArgument.accept(visitor)
print(", ") print(", ")
assignmentOperatorStatement.rightArgument.accept(this@FirRenderer) assignmentOperatorStatement.rightArgument.accept(visitor)
print(")") print(")")
} }
@@ -1509,3 +1481,4 @@ open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode =
} }
} }
} }
}
@@ -39,7 +39,7 @@ class FirDumpHandler(
val renderer = FirRendererWithGeneratedDeclarations(info.session, builderForModule) val renderer = FirRendererWithGeneratedDeclarations(info.session, builderForModule)
allFiles.forEach { allFiles.forEach {
it.accept(renderer) it.accept(renderer.Visitor())
} }
} }