Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.fir.FirRenderer.kt Maven / Gradle / Ivy
/*
* Copyright 2000-2018 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
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.contracts.*
import org.jetbrains.kotlin.fir.contracts.description.ConeContractRenderer
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.*
import kotlin.reflect.KClass
fun FirElement.renderWithType(mode: FirRenderer.RenderMode = FirRenderer.RenderMode.Normal): String = buildString {
append(this@renderWithType)
append(": ")
[email protected] (FirRenderer(this, mode))
}
fun FirElement.render(mode: FirRenderer.RenderMode = FirRenderer.RenderMode.Normal): String =
buildString { [email protected] (FirRenderer(this, mode)) }
open class FirRenderer(builder: StringBuilder, protected val mode: RenderMode = RenderMode.Normal) : FirVisitorVoid() {
companion object {
private val visibilitiesToRenderEffectiveSet = setOf(
Visibilities.Private, Visibilities.PrivateToThis, Visibilities.Internal,
Visibilities.Protected, Visibilities.Public, Visibilities.Local
)
}
data class RenderMode(
val renderLambdaBodies: Boolean,
val renderCallArguments: Boolean,
val renderCallableFqNames: Boolean,
val renderDeclarationResolvePhase: Boolean,
val renderAnnotation: Boolean,
val renderBodies: Boolean = true,
val renderPropertyAccessors: Boolean = true,
val renderDeclarationAttributes: Boolean = false,
val renderDeclarationOrigin: Boolean = false,
val renderPackageDirective: Boolean = false,
val renderNestedDeclarations: Boolean = true,
val renderDefaultParameterValues: Boolean = true,
) {
companion object {
val Normal = RenderMode(
renderLambdaBodies = true,
renderCallArguments = true,
renderCallableFqNames = false,
renderDeclarationResolvePhase = false,
renderAnnotation = true,
)
val WithFqNames = RenderMode(
renderLambdaBodies = true,
renderCallArguments = true,
renderCallableFqNames = true,
renderDeclarationResolvePhase = false,
renderAnnotation = true,
)
val WithFqNamesExceptAnnotationAndBody = RenderMode(
renderLambdaBodies = true,
renderCallArguments = true,
renderCallableFqNames = true,
renderDeclarationResolvePhase = false,
renderAnnotation = false,
renderBodies = false,
)
val WithResolvePhases = RenderMode(
renderLambdaBodies = true,
renderCallArguments = true,
renderCallableFqNames = false,
renderDeclarationResolvePhase = true,
renderAnnotation = true,
)
val NoBodies = RenderMode(
renderLambdaBodies = false,
renderCallArguments = false,
renderCallableFqNames = false,
renderDeclarationResolvePhase = false,
renderAnnotation = false,
renderBodies = false,
renderPropertyAccessors = false,
)
val DeclarationHeader = RenderMode(
renderLambdaBodies = false,
renderCallArguments = false,
renderCallableFqNames = false,
renderDeclarationResolvePhase = false,
renderAnnotation = true,
renderBodies = false,
renderPropertyAccessors = false,
renderDeclarationAttributes = false,
renderDeclarationOrigin = false,
renderPackageDirective = false,
renderNestedDeclarations = false,
renderDefaultParameterValues = false,
)
val WithDeclarationAttributes = RenderMode(
renderLambdaBodies = true,
renderCallArguments = true,
renderCallableFqNames = false,
renderDeclarationResolvePhase = false,
renderAnnotation = true,
renderDeclarationAttributes = true,
)
}
}
private val printer = Printer(builder)
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.renderSeparated() {
for ((index, element) in this.withIndex()) {
if (index > 0) {
print(", ")
}
element.accept(this@FirRenderer)
}
}
private fun List.renderSeparatedWithNewlines() {
for ((index, element) in this.withIndex()) {
if (index > 0) {
print(",")
newLine()
}
element.accept(this@FirRenderer)
}
}
private fun List.renderTypesSeparated() {
for ((index, element) in this.withIndex()) {
if (index > 0) {
print(", ")
}
print(element.render())
}
}
private fun List.renderParameters() {
print("(")
renderSeparated()
print(")")
}
fun renderAnnotations(annotationContainer: FirAnnotationContainer) {
annotationContainer.annotations.renderAnnotations()
}
private fun List.renderAnnotations() {
if (!mode.renderAnnotation) return
for (annotation in this) {
visitAnnotation(annotation)
}
}
private fun Variance.renderVariance() {
label.let {
print(it)
if (it.isNotEmpty()) {
print(" ")
}
}
}
override fun visitCallableDeclaration(callableDeclaration: FirCallableDeclaration) {
renderContexts(callableDeclaration.contextReceivers)
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) {
if (contextReceivers.isEmpty()) return
print("context(")
contextReceivers.renderSeparated()
print(")")
newLine()
}
override fun visitContextReceiver(contextReceiver: FirContextReceiver) {
contextReceiver.customLabelName?.let {
print(it.asString() + "@")
}
contextReceiver.typeRef.accept(this)
}
private fun FirDeclaration.renderContractDescription() {
val contractDescription = (this as? FirContractDescriptionOwner)?.contractDescription ?: return
pushIndent()
contractDescription.accept(this@FirRenderer)
popIndent()
}
private fun Visibility.asString(effectiveVisibility: EffectiveVisibility? = null): String {
val itself = when (this) {
Visibilities.Unknown -> return "public?"
else -> toString()
}
if (effectiveVisibility == null) return itself
val effectiveAsVisibility = effectiveVisibility.toVisibility()
if (effectiveAsVisibility == this) return itself
if (effectiveAsVisibility == Visibilities.Private && this == Visibilities.PrivateToThis) return itself
if (this !in visibilitiesToRenderEffectiveSet) return itself
return itself + "[${effectiveVisibility.name}]"
}
private fun FirMemberDeclaration.modalityAsString(): String {
return modality?.name?.toLowerCaseAsciiOnly() ?: run {
if (this is FirCallableDeclaration && this.isOverride) {
"open?"
} else {
"final?"
}
}
}
private fun List.renderTypeParameters() {
if (isNotEmpty()) {
print("<")
renderSeparated()
print(">")
}
}
private fun List.renderTypeArguments() {
if (isNotEmpty()) {
print("<")
renderSeparated()
print(">")
}
}
override fun visitTypeParameterRef(typeParameterRef: FirTypeParameterRef) {
typeParameterRef.symbol.fir.accept(this)
}
override fun visitMemberDeclaration(memberDeclaration: FirMemberDeclaration) {
if (memberDeclaration !is FirProperty || !memberDeclaration.isLocal) {
// we can't access session.effectiveVisibilityResolver from here!
// print(memberDeclaration.visibility.asString(memberDeclaration.getEffectiveVisibility(...)) + " ")
print(memberDeclaration.visibility.asString() + " ")
print(memberDeclaration.modalityAsString() + " ")
}
if (memberDeclaration.isExpect) {
print("expect ")
}
if (memberDeclaration.isActual) {
print("actual ")
}
if (memberDeclaration.isExternal) {
print("external ")
}
if (memberDeclaration.isOverride) {
print("override ")
}
if (memberDeclaration.isStatic) {
print("static ")
}
if (memberDeclaration.isInner) {
print("inner ")
}
// `companion/data/fun` modifiers are only valid for FirRegularClass, but we render them to make sure they are not
// incorrectly loaded for other declarations during deserialization.
if (memberDeclaration.status.isCompanion) {
print("companion ")
}
if (memberDeclaration.status.isData) {
print("data ")
}
// All Java interfaces are considered `fun` (functional interfaces) for resolution purposes
// (see JavaSymbolProvider.createFirJavaClass). Don't render `fun` for Java interfaces; it's not a modifier in Java.
val isJavaInterface =
memberDeclaration is FirRegularClass && memberDeclaration.classKind == ClassKind.INTERFACE && memberDeclaration.isJava
if (memberDeclaration.status.isFun && !isJavaInterface) {
print("fun ")
}
if (memberDeclaration.isInline) {
print("inline ")
}
if (memberDeclaration.isOperator) {
print("operator ")
}
if (memberDeclaration.isInfix) {
print("infix ")
}
if (memberDeclaration.isTailRec) {
print("tailrec ")
}
if (memberDeclaration.isSuspend) {
print("suspend ")
}
if (memberDeclaration.isConst) {
print("const ")
}
if (memberDeclaration.isLateInit) {
print("lateinit ")
}
visitDeclaration(memberDeclaration as FirDeclaration)
when (memberDeclaration) {
is FirClassLikeDeclaration -> {
if (memberDeclaration is FirRegularClass) {
print(" " + memberDeclaration.name)
}
if (memberDeclaration is FirTypeAlias) {
print(" " + memberDeclaration.name)
}
memberDeclaration.typeParameters.renderTypeParameters()
}
is FirCallableDeclaration -> {
// Name is handled by visitCallableDeclaration
if (memberDeclaration.typeParameters.isNotEmpty()) {
print(" ")
memberDeclaration.typeParameters.renderTypeParameters()
}
}
}
}
override fun visitDeclaration(declaration: FirDeclaration) {
declaration.renderDeclarationData()
print(
when (declaration) {
is FirRegularClass -> declaration.classKind.name.toLowerCaseAsciiOnly().replace("_", " ")
is FirTypeAlias -> "typealias"
is FirSimpleFunction -> "fun"
is FirProperty -> {
val prefix = if (declaration.isLocal) "l" else ""
prefix + if (declaration.isVal) "val" else "var"
}
is FirField -> "field"
is FirEnumEntry -> "enum entry"
else -> "unknown"
}
)
}
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, 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.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) {
renderContexts(regularClass.contextReceivers)
regularClass.annotations.renderAnnotations()
visitMemberDeclaration(regularClass)
renderSupertypes(regularClass)
renderClassDeclarations(regularClass)
}
protected open fun renderClassDeclarations(regularClass: FirRegularClass) {
if (mode.renderNestedDeclarations) {
regularClass.declarations.renderDeclarations()
}
}
override fun visitEnumEntry(enumEntry: FirEnumEntry) {
visitCallableDeclaration(enumEntry)
enumEntry.initializer?.let {
print(" = ")
it.accept(this)
}
}
override fun visitAnonymousObjectExpression(anonymousObjectExpression: FirAnonymousObjectExpression) {
anonymousObjectExpression.anonymousObject.accept(this)
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject) {
anonymousObject.annotations.renderAnnotations()
print("object : ")
anonymousObject.superTypeRefs.renderSeparated()
anonymousObject.declarations.renderDeclarations()
}
override fun visitVariable(variable: FirVariable) {
visitCallableDeclaration(variable)
variable.initializer?.let {
print(" = ")
it.accept(this)
}
variable.delegate?.let {
print("by ")
it.accept(this)
}
}
override fun visitField(field: FirField) {
visitVariable(field)
println()
}
override fun visitProperty(property: FirProperty) {
visitVariable(property)
if (property.isLocal) return
if (!mode.renderPropertyAccessors) return
println()
pushIndent()
if (property.hasExplicitBackingField) {
property.backingField?.accept(this)
println()
}
property.getter?.accept(this)
if (property.getter?.body == null) {
println()
}
if (property.isVar) {
property.setter?.accept(this)
if (property.setter?.body == null) {
println()
}
}
popIndent()
}
override fun visitBackingField(backingField: FirBackingField) {
print(backingField.visibility.asString() + " ")
print(": ")
backingField.returnTypeRef.accept(this)
backingField.initializer?.let {
print(" = ")
it.accept(this)
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
visitCallableDeclaration(simpleFunction)
simpleFunction.body?.renderBody()
if (simpleFunction.body == null) {
println()
}
}
override fun visitConstructor(constructor: FirConstructor) {
constructor.annotations.renderAnnotations()
// we can't access session.effectiveVisibilityResolver from here!
// print(constructor.visibility.asString(constructor.getEffectiveVisibility(...)) + " ")
print(constructor.visibility.asString() + " ")
if (constructor.isExpect) {
print("expect ")
}
if (constructor.isActual) {
print("actual ")
}
constructor.renderDeclarationData()
constructor.dispatchReceiverType?.let {
print(it.render())
print(".")
}
print("constructor")
constructor.typeParameters.renderTypeParameters()
constructor.valueParameters.renderParameters()
print(": ")
constructor.returnTypeRef.accept(this)
val body = constructor.body
val delegatedConstructor = constructor.delegatedConstructor
if (body == null && mode.renderBodies) {
if (delegatedConstructor != null) {
renderInBraces {
delegatedConstructor.accept(this)
println()
}
} else {
println()
}
}
body?.renderBody(listOfNotNull(delegatedConstructor))
}
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor) {
propertyAccessor.renderDeclarationData()
propertyAccessor.annotations.renderAnnotations()
print(propertyAccessor.visibility.asString() + " ")
print(if (propertyAccessor.isInline) "inline " else "")
print(if (propertyAccessor.isExternal) "external " else "")
print(if (propertyAccessor.isGetter) "get" else "set")
propertyAccessor.valueParameters.renderParameters()
print(": ")
propertyAccessor.returnTypeRef.accept(this)
propertyAccessor.renderContractDescription()
propertyAccessor.body?.renderBody()
}
override fun visitAnonymousFunctionExpression(anonymousFunctionExpression: FirAnonymousFunctionExpression) {
visitAnonymousFunction(anonymousFunctionExpression.anonymousFunction)
}
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction) {
anonymousFunction.renderDeclarationData()
anonymousFunction.annotations.renderAnnotations()
val label = anonymousFunction.label
if (label != null) {
print("${label.name}@")
}
print("fun ")
val receiverType = anonymousFunction.receiverTypeRef
if (receiverType != null) {
receiverType.accept(this)
print(".")
}
print("")
if (anonymousFunction.valueParameters.isEmpty() &&
anonymousFunction.hasExplicitParameterList &&
anonymousFunction.returnTypeRef is FirImplicitTypeRef
) {
print("()")
}
anonymousFunction.valueParameters.renderParameters()
print(": ")
anonymousFunction.returnTypeRef.accept(this)
print(" ")
if (mode.renderLambdaBodies) {
anonymousFunction.body?.renderBody()
}
}
override fun visitFunction(function: FirFunction) {
function.valueParameters.renderParameters()
visitDeclaration(function)
function.body?.renderBody()
}
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer) {
print("init")
anonymousInitializer.body?.renderBody()
}
private fun FirBlock.renderBody(additionalStatements: List = 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) {
block.renderBody()
}
override fun visitTypeAlias(typeAlias: FirTypeAlias) {
typeAlias.annotations.renderAnnotations()
visitMemberDeclaration(typeAlias)
print(" = ")
typeAlias.expandedTypeRef.accept(this)
println()
}
override fun visitTypeParameter(typeParameter: FirTypeParameter) {
typeParameter.annotations.renderAnnotations()
if (typeParameter.isReified) {
print("reified ")
}
typeParameter.variance.renderVariance()
print(typeParameter.name)
val meaningfulBounds = typeParameter.bounds.filter {
if (it !is FirResolvedTypeRef) return@filter true
if (!it.type.isNullable) return@filter true
val type = it.type as? ConeLookupTagBasedType ?: return@filter true
type.lookupTag.safeAs()?.classId != StandardClassIds.Any
}
if (meaningfulBounds.isNotEmpty()) {
print(" : ")
meaningfulBounds.renderSeparated()
}
}
override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression) {
safeCallExpression.receiver.accept(this)
print("?.{ ")
safeCallExpression.selector.accept(this)
print(" }")
}
override fun visitCheckedSafeCallSubject(checkedSafeCallSubject: FirCheckedSafeCallSubject) {
print("\$subj\$")
}
override fun visitValueParameter(valueParameter: FirValueParameter) {
valueParameter.renderDeclarationData()
valueParameter.annotations.renderAnnotations()
if (valueParameter.isCrossinline) {
print("crossinline ")
}
if (valueParameter.isNoinline) {
print("noinline ")
}
if (valueParameter.isVararg) {
print("vararg ")
}
if (valueParameter.name != SpecialNames.NO_NAME_PROVIDED) {
print(valueParameter.name.toString() + ": ")
}
valueParameter.returnTypeRef.accept(this)
valueParameter.defaultValue?.let {
print(" = ")
if (mode.renderDefaultParameterValues) {
it.accept(this)
} else {
print("...")
}
}
}
override fun visitImport(import: FirImport) {
visitElement(import)
}
override fun visitStatement(statement: FirStatement) {
if (statement is FirStubStatement) {
print("[StubStatement]")
} else {
visitElement(statement)
}
}
override fun visitReturnExpression(returnExpression: FirReturnExpression) {
returnExpression.annotations.renderAnnotations()
print("^")
val target = returnExpression.target
val labeledElement = target.labeledElement
if (labeledElement is FirSimpleFunction) {
print("${labeledElement.name}")
} else {
val labelName = target.labelName
if (labelName != null) {
print("@$labelName")
}
}
print(" ")
returnExpression.result.accept(this)
}
override fun visitWhenBranch(whenBranch: FirWhenBranch) {
val condition = whenBranch.condition
if (condition is FirElseIfTrueCondition) {
print("else")
} else {
condition.accept(this)
}
print(" -> ")
whenBranch.result.accept(this)
}
override fun visitWhenExpression(whenExpression: FirWhenExpression) {
whenExpression.annotations.renderAnnotations()
print("when (")
val subjectVariable = whenExpression.subjectVariable
if (subjectVariable != null) {
subjectVariable.accept(this)
} else {
whenExpression.subject?.accept(this)
}
println(") {")
pushIndent()
for (branch in whenExpression.branches) {
branch.accept(this)
}
popIndent()
println("}")
}
override fun visitWhenSubjectExpression(whenSubjectExpression: FirWhenSubjectExpression) {
print("\$subj\$")
}
override fun visitTryExpression(tryExpression: FirTryExpression) {
tryExpression.annotations.renderAnnotations()
print("try")
tryExpression.tryBlock.accept(this)
for (catchClause in tryExpression.catches) {
print("catch (")
catchClause.parameter.accept(this)
print(")")
catchClause.block.accept(this)
}
val finallyBlock = tryExpression.finallyBlock ?: return
print("finally")
finallyBlock.accept(this)
}
override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop) {
val label = doWhileLoop.label
if (label != null) {
print("${label.name}@")
}
print("do")
doWhileLoop.block.accept(this)
print("while(")
doWhileLoop.condition.accept(this)
print(")")
}
override fun visitWhileLoop(whileLoop: FirWhileLoop) {
val label = whileLoop.label
if (label != null) {
print("${label.name}@")
}
print("while(")
whileLoop.condition.accept(this)
print(")")
whileLoop.block.accept(this)
}
private val loopJumpStack = Stack()
override fun visitLoopJump(loopJump: FirLoopJump) {
if (loopJumpStack.contains(loopJump)) {
// For example,
// do {
// ...
// } while(
// when (...) {
// ... -> break
// }
// )
// That `break` condition is `when` expression, and while visiting its branch result, we will see the same `break` again.
return
}
loopJumpStack.push(loopJump)
val target = loopJump.target
val labeledElement = target.labeledElement
print("@@@[")
labeledElement.condition.accept(this)
print("] ")
loopJumpStack.pop()
}
override fun visitBreakExpression(breakExpression: FirBreakExpression) {
breakExpression.annotations.renderAnnotations()
print("break")
visitLoopJump(breakExpression)
}
override fun visitContinueExpression(continueExpression: FirContinueExpression) {
continueExpression.annotations.renderAnnotations()
print("continue")
visitLoopJump(continueExpression)
}
override fun visitExpression(expression: FirExpression) {
if (expression !is FirLazyExpression) {
expression.annotations.renderAnnotations()
}
print(
when (expression) {
is FirExpressionStub -> "STUB"
is FirLazyExpression -> "LAZY_EXPRESSION"
is FirUnitExpression -> "Unit"
is FirElseIfTrueCondition -> "else"
is FirNoReceiverExpression -> ""
else -> "??? ${expression.javaClass}"
}
)
}
override fun visitConstExpression(constExpression: FirConstExpression) {
constExpression.annotations.renderAnnotations()
val kind = constExpression.kind
val value = constExpression.value
print("$kind(")
if (value !is Char) {
print(value.toString())
} else {
if (value.code in 32..127) {
print(value)
} else {
print(value.code)
}
}
print(")")
}
override fun visitWrappedDelegateExpression(wrappedDelegateExpression: FirWrappedDelegateExpression) {
wrappedDelegateExpression.expression.accept(this)
}
override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression) {
print(namedArgumentExpression.name)
print(" = ")
if (namedArgumentExpression.isSpread) {
print("*")
}
namedArgumentExpression.expression.accept(this)
}
override fun visitSpreadArgumentExpression(spreadArgumentExpression: FirSpreadArgumentExpression) {
if (spreadArgumentExpression.isSpread) {
print("*")
}
spreadArgumentExpression.expression.accept(this)
}
override fun visitLambdaArgumentExpression(lambdaArgumentExpression: FirLambdaArgumentExpression) {
print(" = ")
lambdaArgumentExpression.expression.accept(this)
}
override fun visitVarargArgumentsExpression(varargArgumentsExpression: FirVarargArgumentsExpression) {
print("vararg(")
varargArgumentsExpression.arguments.renderSeparated()
print(")")
}
override fun visitCall(call: FirCall) {
print("(")
if (mode.renderCallArguments) {
call.arguments.renderSeparated()
} else {
if (call.arguments.isNotEmpty()) {
print("...")
}
}
print(")")
}
override fun visitStringConcatenationCall(stringConcatenationCall: FirStringConcatenationCall) {
print("")
visitCall(stringConcatenationCall)
}
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall) {
print("(")
typeOperatorCall.argument.accept(this)
print(" ")
print(typeOperatorCall.operation.operator)
print(" ")
typeOperatorCall.conversionTypeRef.accept(this)
print(")")
}
override fun visitAnnotationCall(annotationCall: FirAnnotationCall) {
visitAnnotation(annotationCall)
}
override fun visitAnnotation(annotation: FirAnnotation) {
print("@")
annotation.useSiteTarget?.let {
print(it.name)
print(":")
}
annotation.annotationTypeRef.accept(this)
when (annotation) {
is FirAnnotationCall -> if (annotation.calleeReference.let { it is FirResolvedNamedReference || it is FirErrorNamedReference }) {
annotation.renderArgumentMapping()
} else {
visitCall(annotation)
}
else -> annotation.renderArgumentMapping()
}
if (annotation.useSiteTarget == AnnotationUseSiteTarget.FILE) {
println()
} else {
print(" ")
}
}
private fun FirAnnotation.renderArgumentMapping() {
print("(")
if (mode.renderCallArguments) {
argumentMapping.mapping.renderSeparated()
} else {
if (argumentMapping.mapping.isNotEmpty()) {
print("...")
}
}
print(")")
}
private fun Map.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) {
val dispatchReceiver = delegatedConstructorCall.dispatchReceiver
if (dispatchReceiver !is FirNoReceiverExpression) {
dispatchReceiver.accept(this)
print(".")
}
if (delegatedConstructorCall.isSuper) {
print("super<")
} else if (delegatedConstructorCall.isThis) {
print("this<")
}
delegatedConstructorCall.constructedTypeRef.accept(this)
print(">")
visitCall(delegatedConstructorCall)
}
override fun visitTypeRef(typeRef: FirTypeRef) {
typeRef.annotations.renderAnnotations()
visitElement(typeRef)
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef) {
errorTypeRef.annotations.renderAnnotations()
print("")
}
override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef) {
print("")
}
override fun visitTypeRefWithNullability(typeRefWithNullability: FirTypeRefWithNullability) {
if (typeRefWithNullability.isMarkedNullable) {
print("?")
}
}
override fun visitDynamicTypeRef(dynamicTypeRef: FirDynamicTypeRef) {
dynamicTypeRef.annotations.renderAnnotations()
print("")
visitTypeRefWithNullability(dynamicTypeRef)
}
override fun visitFunctionTypeRef(functionTypeRef: FirFunctionTypeRef) {
if (functionTypeRef.contextReceiverTypeRefs.isNotEmpty()) {
print("context(")
functionTypeRef.contextReceiverTypeRefs.renderSeparated()
print(")")
}
functionTypeRef.annotations.dropExtensionFunctionAnnotation().renderAnnotations()
print("( ")
if (functionTypeRef.isSuspend) {
print("suspend ")
}
functionTypeRef.receiverTypeRef?.let {
it.accept(this)
print(".")
}
functionTypeRef.valueParameters.renderParameters()
print(" -> ")
functionTypeRef.returnTypeRef.accept(this)
print(" )")
visitTypeRefWithNullability(functionTypeRef)
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef) {
val kind = resolvedTypeRef.functionTypeKind
print("R|")
val coneType = resolvedTypeRef.type
print(coneType.renderFunctionType(kind))
print("|")
}
override fun visitUserTypeRef(userTypeRef: FirUserTypeRef) {
userTypeRef.annotations.renderAnnotations()
if (userTypeRef.customRenderer) {
print(userTypeRef.toString())
return
}
for ((index, qualifier) in userTypeRef.qualifier.withIndex()) {
if (index != 0) {
print(".")
}
print(qualifier.name)
if (qualifier.typeArgumentList.typeArguments.isNotEmpty()) {
print("<")
qualifier.typeArgumentList.typeArguments.renderSeparated()
print(">")
}
}
visitTypeRefWithNullability(userTypeRef)
}
override fun visitTypeProjection(typeProjection: FirTypeProjection) {
visitElement(typeProjection)
}
override fun visitTypeProjectionWithVariance(typeProjectionWithVariance: FirTypeProjectionWithVariance) {
typeProjectionWithVariance.variance.renderVariance()
typeProjectionWithVariance.typeRef.accept(this)
}
override fun visitStarProjection(starProjection: FirStarProjection) {
print("*")
}
private fun FirBasedSymbol<*>.render(): String {
return when (this) {
is FirCallableSymbol<*> -> callableId.toString()
is FirClassLikeSymbol<*> -> classId.toString()
else -> "?"
}
}
override fun visitNamedReference(namedReference: FirNamedReference) {
val symbol = namedReference.candidateSymbol
when {
namedReference is FirErrorNamedReference -> print("<${namedReference.diagnostic.reason}>#")
symbol != null -> print("R?C|${symbol.render()}|")
else -> print("${namedReference.name}#")
}
}
override fun visitBackingFieldReference(backingFieldReference: FirBackingFieldReference) {
print("F|")
print(backingFieldReference.resolvedSymbol.fir.propertySymbol.callableId)
print("|")
}
override fun visitDelegateFieldReference(delegateFieldReference: FirDelegateFieldReference) {
print("D|")
print(delegateFieldReference.resolvedSymbol.callableId)
print("|")
}
override fun visitResolvedNamedReference(resolvedNamedReference: FirResolvedNamedReference) {
print("R|")
val symbol = resolvedNamedReference.resolvedSymbol
val isSubstitutionOverride = (symbol.fir as? FirCallableDeclaration)?.isSubstitutionOverride == true
if (isSubstitutionOverride) {
print("SubstitutionOverride<")
}
print(symbol.unwrapIntersectionOverrides().render())
if (resolvedNamedReference is FirResolvedCallableReference) {
if (resolvedNamedReference.inferredTypeArguments.isNotEmpty()) {
print("<")
resolvedNamedReference.inferredTypeArguments.renderTypesSeparated()
print(">")
}
}
if (isSubstitutionOverride) {
when (symbol) {
is FirNamedFunctionSymbol -> {
print(": ")
symbol.fir.returnTypeRef.accept(this)
}
is FirPropertySymbol -> {
print(": ")
symbol.fir.returnTypeRef.accept(this)
}
}
print(">")
}
print("|")
}
private fun FirBasedSymbol<*>.unwrapIntersectionOverrides(): FirBasedSymbol<*> {
(this as? FirCallableSymbol<*>)?.baseForIntersectionOverride?.let { return it.unwrapIntersectionOverrides() }
return this
}
override fun visitResolvedCallableReference(resolvedCallableReference: FirResolvedCallableReference) {
visitResolvedNamedReference(resolvedCallableReference)
}
override fun visitThisReference(thisReference: FirThisReference) {
print("this")
val labelName = thisReference.labelName
val symbol = thisReference.boundSymbol
when {
symbol != null -> print("@R|${symbol.render()}|")
labelName != null -> print("@$labelName#")
else -> print("#")
}
}
override fun visitSuperReference(superReference: FirSuperReference) {
print("super<")
superReference.superTypeRef.accept(this)
print(">")
superReference.labelName?.let {
print("@$it#")
}
}
override fun visitQualifiedAccess(qualifiedAccess: FirQualifiedAccess) {
val explicitReceiver = qualifiedAccess.explicitReceiver
val dispatchReceiver = qualifiedAccess.dispatchReceiver
val extensionReceiver = qualifiedAccess.extensionReceiver
var hasSomeReceiver = true
when {
dispatchReceiver !is FirNoReceiverExpression && extensionReceiver !is FirNoReceiverExpression -> {
print("(")
dispatchReceiver.accept(this)
print(", ")
extensionReceiver.accept(this)
print(")")
}
dispatchReceiver !is FirNoReceiverExpression -> {
dispatchReceiver.accept(this)
}
extensionReceiver !is FirNoReceiverExpression -> {
extensionReceiver.accept(this)
}
explicitReceiver != null -> {
explicitReceiver.accept(this)
}
else -> {
hasSomeReceiver = false
}
}
if (hasSomeReceiver) {
print(".")
}
}
override fun visitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall) {
checkNotNullCall.argument.accept(this)
print("!!")
}
override fun visitElvisExpression(elvisExpression: FirElvisExpression) {
elvisExpression.lhs.accept(this)
print(" ?: ")
elvisExpression.rhs.accept(this)
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
callableReferenceAccess.annotations.renderAnnotations()
callableReferenceAccess.explicitReceiver?.accept(this)
if (callableReferenceAccess.hasQuestionMarkAtLHS && callableReferenceAccess.explicitReceiver !is FirResolvedQualifier) {
print("?")
}
print("::")
callableReferenceAccess.calleeReference.accept(this)
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression) {
qualifiedAccessExpression.annotations.renderAnnotations()
visitQualifiedAccess(qualifiedAccessExpression)
qualifiedAccessExpression.calleeReference.accept(this)
qualifiedAccessExpression.typeArguments.renderTypeArguments()
}
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
visitQualifiedAccessExpression(propertyAccessExpression)
}
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression) {
visitQualifiedAccessExpression(thisReceiverExpression)
}
override fun visitExpressionWithSmartcast(expressionWithSmartcast: FirExpressionWithSmartcast) {
visitQualifiedAccessExpression(expressionWithSmartcast)
}
private fun visitAssignment(operation: FirOperation, rValue: FirExpression) {
print(operation.operator)
print(" ")
rValue.accept(this)
}
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment) {
variableAssignment.annotations.renderAnnotations()
visitQualifiedAccess(variableAssignment)
variableAssignment.lValue.accept(this)
print(" ")
visitAssignment(FirOperation.ASSIGN, variableAssignment.rValue)
}
override fun visitAugmentedArraySetCall(augmentedArraySetCall: FirAugmentedArraySetCall) {
augmentedArraySetCall.annotations.renderAnnotations()
print("ArraySet:[")
augmentedArraySetCall.lhsGetCall.accept(this)
print(" ")
print(augmentedArraySetCall.operation.operator)
print(" ")
augmentedArraySetCall.rhs.accept(this)
print("]")
}
override fun visitFunctionCall(functionCall: FirFunctionCall) {
functionCall.annotations.renderAnnotations()
visitQualifiedAccess(functionCall)
functionCall.calleeReference.accept(this)
functionCall.typeArguments.renderTypeArguments()
visitCall(functionCall)
}
override fun visitIntegerLiteralOperatorCall(integerLiteralOperatorCall: FirIntegerLiteralOperatorCall) {
visitFunctionCall(integerLiteralOperatorCall)
}
override fun visitImplicitInvokeCall(implicitInvokeCall: FirImplicitInvokeCall) {
visitFunctionCall(implicitInvokeCall)
}
override fun visitComparisonExpression(comparisonExpression: FirComparisonExpression) {
print("CMP(${comparisonExpression.operation.operator}, ")
comparisonExpression.compareToCall.accept(this)
print(")")
}
override fun visitAssignmentOperatorStatement(assignmentOperatorStatement: FirAssignmentOperatorStatement) {
assignmentOperatorStatement.annotations.renderAnnotations()
print(assignmentOperatorStatement.operation.operator)
print("(")
assignmentOperatorStatement.leftArgument.accept(this@FirRenderer)
print(", ")
assignmentOperatorStatement.rightArgument.accept(this@FirRenderer)
print(")")
}
override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall) {
equalityOperatorCall.annotations.renderAnnotations()
print(equalityOperatorCall.operation.operator)
visitCall(equalityOperatorCall)
}
override fun visitComponentCall(componentCall: FirComponentCall) {
visitFunctionCall(componentCall)
}
override fun visitGetClassCall(getClassCall: FirGetClassCall) {
getClassCall.annotations.renderAnnotations()
print("")
visitCall(getClassCall)
}
override fun visitClassReferenceExpression(classReferenceExpression: FirClassReferenceExpression) {
classReferenceExpression.annotations.renderAnnotations()
print("")
print("(")
classReferenceExpression.classTypeRef.accept(this)
print(")")
}
override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall) {
arrayOfCall.annotations.renderAnnotations()
print("")
visitCall(arrayOfCall)
}
override fun visitThrowExpression(throwExpression: FirThrowExpression) {
throwExpression.annotations.renderAnnotations()
print("throw ")
throwExpression.exception.accept(this)
}
override fun visitErrorExpression(errorExpression: FirErrorExpression) {
print("ERROR_EXPR(${errorExpression.diagnostic.reason})")
}
override fun visitResolvedQualifier(resolvedQualifier: FirResolvedQualifier) {
renderAnnotations(resolvedQualifier)
print("Q|")
val classId = resolvedQualifier.classId
if (classId != null) {
print(classId.asString())
} else {
print(resolvedQualifier.packageFqName.asString().replace(".", "/"))
}
if (resolvedQualifier.isNullableLHSForCallableReference) {
print("?")
}
print("|")
}
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression) {
binaryLogicExpression.leftOperand.accept(this)
print(" ${binaryLogicExpression.kind.token} ")
binaryLogicExpression.rightOperand.accept(this)
}
override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference) {
visitNamedReference(errorNamedReference)
}
override fun visitLegacyRawContractDescription(legacyRawContractDescription: FirLegacyRawContractDescription) {
newLine()
print("[Contract description]")
renderInBraces("<", ">") {
legacyRawContractDescription.contractCall.accept(this)
newLine()
}
}
override fun visitRawContractDescription(rawContractDescription: FirRawContractDescription) {
newLine()
print("[Contract description]")
renderInBraces("<", ">") {
rawContractDescription.rawEffects.renderSeparatedWithNewlines()
newLine()
}
}
override fun visitEffectDeclaration(effectDeclaration: FirEffectDeclaration) {
newLine()
print("[Effect declaration]")
renderInBraces("<", ">") {
println(buildString { effectDeclaration.effect.accept(ConeContractRenderer(this), null) })
}
}
override fun visitResolvedContractDescription(resolvedContractDescription: FirResolvedContractDescription) {
newLine()
println("[R|Contract description]")
renderInBraces("<", ">") {
resolvedContractDescription.effects
.map { it.effect }
.forEach {
println(buildString { it.accept(ConeContractRenderer(this), null) })
}
}
}
override fun visitContractDescription(contractDescription: FirContractDescription) {
require(contractDescription is FirEmptyContractDescription)
}
override fun visitPackageDirective(packageDirective: FirPackageDirective) {
if (mode.renderPackageDirective) {
if (!packageDirective.packageFqName.isRoot) {
println("package ${packageDirective.packageFqName.asString()}")
println()
}
}
}
}