org.jetbrains.kotlin.fir.renderer.FirRenderer.kt Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2010-2024 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.builtins.functions.AllowedToUsedOnlyInK1
import org.jetbrains.kotlin.builtins.functions.FunctionTypeKindExtractor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirPackageDirective
import org.jetbrains.kotlin.fir.contracts.FirContractDescription
import org.jetbrains.kotlin.fir.contracts.FirEffectDeclaration
import org.jetbrains.kotlin.fir.contracts.description.ConeContractRenderer
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
import org.jetbrains.kotlin.fir.expressions.impl.FirLazyDelegatedConstructorCall
import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression
import org.jetbrains.kotlin.fir.isCatchParameter
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
import java.util.*
class FirRenderer(
builder: StringBuilder = StringBuilder(),
override val annotationRenderer: FirAnnotationRenderer? = FirAnnotationRenderer(),
override val bodyRenderer: FirBodyRenderer? = FirBodyRenderer(),
override val callArgumentsRenderer: FirCallArgumentsRenderer? = FirCallArgumentsRenderer(),
override val classMemberRenderer: FirClassMemberRenderer? = FirClassMemberRenderer(),
override val contractRenderer: ConeContractRenderer? = ConeContractRenderer(),
override val declarationRenderer: FirDeclarationRenderer? = FirDeclarationRenderer(),
override val idRenderer: ConeIdRenderer = ConeIdRendererForDebugging(),
override val modifierRenderer: FirModifierRenderer? = FirAllModifierRenderer(),
override val packageDirectiveRenderer: FirPackageDirectiveRenderer? = null,
override val propertyAccessorRenderer: FirPropertyAccessorRenderer? = FirPropertyAccessorRenderer(),
override val resolvePhaseRenderer: FirResolvePhaseRenderer? = null,
override val typeRenderer: ConeTypeRenderer = ConeTypeRendererForDebugging(),
override val referencedSymbolRenderer: FirSymbolRenderer = FirSymbolRenderer(),
override val callableSignatureRenderer: FirCallableSignatureRenderer? = FirCallableSignatureRenderer(),
override val errorExpressionRenderer: FirErrorExpressionRenderer? = FirErrorExpressionOnlyErrorRenderer(),
override val resolvedNamedReferenceRenderer: FirResolvedNamedReferenceRenderer = FirResolvedNamedReferenceRendererWithLabel(),
override val resolvedQualifierRenderer: FirResolvedQualifierRenderer = FirResolvedQualifierRendererWithLabel(),
override val getClassCallRenderer: FirGetClassCallRenderer = FirGetClassCallRendererForDebugging(),
override val supertypeRenderer: FirSupertypeRenderer? = FirSupertypeRenderer(),
private val lineBreakAfterContextParameters: Boolean = true,
private val renderFieldAnnotationSeparately: Boolean = true,
private val renderVarargTypes: Boolean = false,
) : FirRendererComponents {
override val visitor: Visitor = Visitor()
override val printer: FirPrinter = FirPrinter(builder)
companion object {
fun noAnnotationBodiesAccessorAndArguments(): FirRenderer = FirRenderer(
annotationRenderer = null,
bodyRenderer = null,
propertyAccessorRenderer = null,
callArgumentsRenderer = FirCallNoArgumentsRenderer(),
)
fun withResolvePhase(): FirRenderer = FirRenderer(
resolvePhaseRenderer = FirResolvePhaseRenderer(),
)
fun withDeclarationAttributes(): FirRenderer = FirRenderer(
declarationRenderer = FirDeclarationRendererWithAttributes(),
)
fun forReadability(): FirRenderer = FirRenderer(
typeRenderer = ConeTypeRenderer(),
idRenderer = ConeIdShortRenderer(),
classMemberRenderer = FirNoClassMemberRenderer(),
bodyRenderer = null,
propertyAccessorRenderer = null,
callArgumentsRenderer = FirCallNoArgumentsRenderer(),
modifierRenderer = FirPartialModifierRenderer(),
callableSignatureRenderer = FirCallableSignatureRendererForReadability(),
declarationRenderer = FirDeclarationRenderer("local "),
)
}
init {
annotationRenderer?.components = this
bodyRenderer?.components = this
callArgumentsRenderer?.components = this
classMemberRenderer?.components = this
contractRenderer?.components = this
declarationRenderer?.components = this
idRenderer.builder = builder
modifierRenderer?.components = this
packageDirectiveRenderer?.components = this
propertyAccessorRenderer?.components = this
resolvePhaseRenderer?.components = this
typeRenderer.builder = builder
typeRenderer.idRenderer = idRenderer
referencedSymbolRenderer.components = this
callableSignatureRenderer?.components = this
errorExpressionRenderer?.components = this
resolvedNamedReferenceRenderer.components = this
resolvedQualifierRenderer.components = this
getClassCallRenderer.components = this
supertypeRenderer?.components = this
}
fun renderElementAsString(element: FirElement, trim: Boolean = false): String {
element.accept(visitor)
return printer.toString().applyIf(trim, String::trim)
}
fun renderElementWithTypeAsString(element: FirElement): String {
print(element)
print(": ")
return renderElementAsString(element)
}
fun renderAsCallableDeclarationString(callableDeclaration: FirCallableDeclaration): String {
visitor.visitCallableDeclaration(callableDeclaration)
return printer.toString()
}
fun renderMemberDeclarationClass(firClass: FirClass) {
visitor.visitMemberDeclaration(firClass)
}
fun renderAnnotations(annotationContainer: FirAnnotationContainer) {
annotationRenderer?.render(annotationContainer)
}
private fun Variance.renderVariance() {
label.let {
print(it)
if (it.isNotEmpty()) {
print(" ")
}
}
}
private fun renderContexts(contextParameters: List) {
if (contextParameters.isEmpty()) return
print("context(")
renderSeparated(contextParameters, visitor)
print(")")
if (lineBreakAfterContextParameters) {
printer.newLine()
} else {
print(" ")
}
}
private fun List.renderTypeParameters() {
if (isNotEmpty()) {
print("<")
renderSeparated(this, visitor)
print(">")
}
}
private fun List.renderTypeArguments() {
if (isNotEmpty()) {
print("<")
renderSeparated(this, visitor)
print(">")
}
}
private fun print(s: Any) {
printer.print(s)
}
private fun renderSeparated(elements: List, visitor: Visitor) {
printer.renderSeparated(elements, visitor)
}
private fun renderType(type: ConeKotlinType?) {
if (type == null) return
print("R|")
typeRenderer.render(type)
print("|")
}
private fun renderPhaseAndAttributes(declaration: FirDeclaration) {
declarationRenderer?.renderPhaseAndAttributes(declaration) ?: resolvePhaseRenderer?.render(declaration)
}
inner class Visitor internal constructor() : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitFile(file: FirFile) {
printer.print("FILE: ")
renderPhaseAndAttributes(file)
printer.println(file.name)
printer.pushIndent()
annotationRenderer?.render(file)
visitPackageDirective(file.packageDirective)
file.imports.forEach { it.accept(this) }
file.declarations.forEach { it.accept(this) }
printer.popIndent()
}
override fun visitScript(script: FirScript) {
annotationRenderer?.render(script)
printer.print("SCRIPT: ")
renderPhaseAndAttributes(script)
printer.println(script.name)
printer.pushIndent()
// following the function convention, although in a compiled script parameters are passed before receivers
script.receivers.forEach {
it.accept(this)
printer.newLine()
}
script.parameters.forEach {
it.accept(this)
printer.newLine()
}
printer.newLine()
script.declarations.forEach {
it.accept(this)
printer.newLine()
}
printer.popIndent()
}
override fun visitScriptReceiverParameter(scriptReceiverParameter: FirScriptReceiverParameter) {
renderPhaseAndAttributes(scriptReceiverParameter)
annotationRenderer?.render(scriptReceiverParameter)
print("