Simplify creation of FirRenderer

This commit is contained in:
Mikhail Glukhikh
2022-07-08 16:19:14 +02:00
committed by Space
parent f9fdb5d3bc
commit 801426d0e6
15 changed files with 47 additions and 95 deletions
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirFieldImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.renderer.FirRenderer import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.renderer.FirResolvePhaseRenderer
import org.jetbrains.kotlin.fir.resolve.getContainingClass import org.jetbrains.kotlin.fir.resolve.getContainingClass
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
@@ -584,9 +583,7 @@ internal class KtSymbolByFirBuilder constructor(
returns() implies requirement returns() implies requirement
} }
require(requirement) { require(requirement) {
val renderedSymbol = FirRenderer().with( val renderedSymbol = FirRenderer.withResolvePhase().renderElementWithTypeAsString(firSymbol.fir)
resolvePhaseRenderer = FirResolvePhaseRenderer()
).renderElementWithTypeAsString(firSymbol.fir)
"Cannot build ${S::class.simpleName} for $renderedSymbol}" "Cannot build ${S::class.simpleName} for $renderedSymbol}"
} }
} }
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.renderer.FirCallNoArgumentsRenderer
import org.jetbrains.kotlin.fir.renderer.FirRenderer import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -160,10 +159,7 @@ internal class KtFirTypeProvider(
?: this.typeArguments.mapNotNull { it.type }) ?: this.typeArguments.mapNotNull { it.type })
require(typeParameterSymbols.size == argumentTypes.size) { require(typeParameterSymbols.size == argumentTypes.size) {
val renderedSymbol = FirRenderer().with( val renderedSymbol = FirRenderer.noAnnotationBodiesAccessorAndArguments().renderElementAsString(symbol.fir)
annotationRenderer = null, bodyRenderer = null, propertyAccessorRenderer = null,
callArgumentsRenderer = FirCallNoArgumentsRenderer()
).renderElementAsString(symbol.fir)
"'$renderedSymbol' expects '${typeParameterSymbols.size}' type arguments " + "'$renderedSymbol' expects '${typeParameterSymbols.size}' type arguments " +
"but type '${this.renderForDebugging()}' has ${argumentTypes.size} type arguments." "but type '${this.renderForDebugging()}' has ${argumentTypes.size} type arguments."
} }
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.renderer.FirRenderer import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.renderer.FirResolvePhaseRenderer
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.ensureResolved import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
@@ -32,9 +31,7 @@ import org.jetbrains.kotlin.psi.KtDeclaration
internal fun FirCallableSymbol<*>.invalidModalityError(): Nothing { internal fun FirCallableSymbol<*>.invalidModalityError(): Nothing {
val rendered = FirRenderer().with( val rendered = FirRenderer.withResolvePhase().renderElementWithTypeAsString(fir)
resolvePhaseRenderer = FirResolvePhaseRenderer()
).renderElementWithTypeAsString(fir)
error( error(
"""|Symbol modality should not be null, looks like the FIR symbol was not properly resolved """|Symbol modality should not be null, looks like the FIR symbol was not properly resolved
| |
@@ -53,7 +53,8 @@ abstract class AbstractFirLazyDeclarationResolveTest : AbstractLowLevelApiSingle
override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) { override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) {
val resultBuilder = StringBuilder() val resultBuilder = StringBuilder()
val renderer = FirRenderer(resultBuilder).with( val renderer = FirRenderer(
builder = resultBuilder,
declarationRenderer = FirDeclarationRendererWithAttributes(), declarationRenderer = FirDeclarationRendererWithAttributes(),
resolvePhaseRenderer = FirResolvePhaseRenderer() resolvePhaseRenderer = FirResolvePhaseRenderer()
) )
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeF
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirSourceResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirSourceResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest
import org.jetbrains.kotlin.fir.renderer.FirRenderer import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.renderer.FirResolvePhaseRenderer
import org.jetbrains.kotlin.psi.KtAnnotated import org.jetbrains.kotlin.psi.KtAnnotated
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -35,9 +34,7 @@ abstract class AbstractFirOnAirResolveTest : AbstractLowLevelApiSingleFileTest()
resolveWithClearCaches(ktFile) { firResolveSession -> resolveWithClearCaches(ktFile) { firResolveSession ->
check(firResolveSession is LLFirSourceResolveSession) check(firResolveSession is LLFirSourceResolveSession)
val firElement = LowLevelFirApiFacadeForResolveOnAir.onAirResolveElement(firResolveSession, place, onAir) val firElement = LowLevelFirApiFacadeForResolveOnAir.onAirResolveElement(firResolveSession, place, onAir)
val rendered = FirRenderer().with( val rendered = FirRenderer.withResolvePhase().renderElementAsString(firElement)
resolvePhaseRenderer = FirResolvePhaseRenderer()
).renderElementAsString(firElement)
testServices.assertions.assertEqualsToTestDataFileSibling(rendered) testServices.assertions.assertEqualsToTestDataFileSibling(rendered)
} }
} }
@@ -60,7 +60,7 @@ abstract class AbstractGetOrBuildFirTest : AbstractLowLevelApiSingleFileTest() {
private fun render(firElement: FirElement?): String = when (firElement) { private fun render(firElement: FirElement?): String = when (firElement) {
null -> "null" null -> "null"
is FirImport -> "import ${firElement.importedFqName}" is FirImport -> "import ${firElement.importedFqName}"
else -> FirRenderer().with(packageDirectiveRenderer = FirPackageDirectiveRenderer()).renderElementAsString(firElement) else -> FirRenderer(packageDirectiveRenderer = FirPackageDirectiveRenderer()).renderElementAsString(firElement)
} }
private object Directives : SimpleDirectivesContainer() { private object Directives : SimpleDirectivesContainer() {
@@ -127,7 +127,7 @@ abstract class AbstractPartialRawFirBuilderTestCase : AbstractLowLevelApiSingleF
null null
) )
val firDump = FirRenderer().with(idRenderer = ConeIdFullRenderer()).renderElementAsString(firElement) val firDump = FirRenderer(idRenderer = ConeIdFullRenderer()).renderElementAsString(firElement)
JUnit5Assertions.assertEqualsToTestDataFileSibling(firDump) JUnit5Assertions.assertEqualsToTestDataFileSibling(firDump)
} }
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.resolveWithClearCaches
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.renderer.FirRenderer import org.jetbrains.kotlin.fir.renderer.FirRenderer
import org.jetbrains.kotlin.fir.renderer.FirResolvePhaseRenderer
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.services.TestModuleStructure import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
@@ -20,9 +19,7 @@ abstract class AbstractInnerDeclarationsResolvePhaseTest : AbstractLowLevelApiSi
override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) { override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) {
resolveWithClearCaches(ktFile) { firResolveSession -> resolveWithClearCaches(ktFile) { firResolveSession ->
val firFile = ktFile.getOrBuildFirOfType<FirFile>(firResolveSession) val firFile = ktFile.getOrBuildFirOfType<FirFile>(firResolveSession)
val actual = FirRenderer().with( val actual = FirRenderer.withResolvePhase().renderElementAsString(firFile)
resolvePhaseRenderer = FirResolvePhaseRenderer()
).renderElementAsString(firFile)
testServices.assertions.assertEqualsToTestDataFileSibling(actual, extension = ".fir.txt") testServices.assertions.assertEqualsToTestDataFileSibling(actual, extension = ".fir.txt")
} }
} }
@@ -27,7 +27,7 @@ object FirDiagnosticRenderers {
val SYMBOL = Renderer { symbol: FirBasedSymbol<*> -> val SYMBOL = Renderer { symbol: FirBasedSymbol<*> ->
when (symbol) { when (symbol) {
is FirClassLikeSymbol<*>, is FirClassLikeSymbol<*>,
is FirCallableSymbol<*> -> FirRenderer().with( is FirCallableSymbol<*> -> FirRenderer(
typeRenderer = ConeTypeRenderer(), typeRenderer = ConeTypeRenderer(),
idRenderer = ConeIdShortRenderer(), idRenderer = ConeIdShortRenderer(),
classMemberRenderer = FirNoClassMemberRenderer(), classMemberRenderer = FirNoClassMemberRenderer(),
@@ -103,7 +103,7 @@ object FirDiagnosticRenderers {
val FQ_NAMES_IN_TYPES = Renderer { symbol: FirBasedSymbol<*> -> val FQ_NAMES_IN_TYPES = Renderer { symbol: FirBasedSymbol<*> ->
@OptIn(SymbolInternals::class) @OptIn(SymbolInternals::class)
FirRenderer().with( FirRenderer(
annotationRenderer = null, bodyRenderer = null, idRenderer = ConeIdFullRenderer() annotationRenderer = null, bodyRenderer = null, idRenderer = ConeIdFullRenderer()
).renderElementAsString(symbol.fir) ).renderElementAsString(symbol.fir)
} }
@@ -24,7 +24,7 @@ abstract class AbstractLightTree2FirConverterTestCase : AbstractRawFirBuilderTes
scopeProvider = StubFirScopeProvider, scopeProvider = StubFirScopeProvider,
diagnosticsReporter = null diagnosticsReporter = null
).buildFirFile(Paths.get(filePath)) ).buildFirFile(Paths.get(filePath))
val firDump = FirRenderer().with(declarationRenderer = FirDeclarationRendererWithAttributes()).renderElementAsString(firFile) val firDump = FirRenderer.withDeclarationAttributes().renderElementAsString(firFile)
val expectedFile = File(filePath.replace(".kt", ".txt")) val expectedFile = File(filePath.replace(".kt", ".txt"))
KotlinTestUtils.assertEqualsToFile(expectedFile, firDump) KotlinTestUtils.assertEqualsToFile(expectedFile, firDump)
@@ -66,7 +66,7 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase(
protected open fun doRawFirTest(filePath: String) { protected open fun doRawFirTest(filePath: String) {
val file = createKtFile(filePath) val file = createKtFile(filePath)
val firFile = file.toFirFile(BodyBuildingMode.NORMAL) val firFile = file.toFirFile(BodyBuildingMode.NORMAL)
val firFileDump = FirRenderer().with(declarationRenderer = FirDeclarationRendererWithAttributes()).renderElementAsString(firFile) val firFileDump = FirRenderer.withDeclarationAttributes().renderElementAsString(firFile)
val expectedPath = filePath.replace(".kt", ".txt") val expectedPath = filePath.replace(".kt", ".txt")
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump) KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
} }
@@ -134,7 +134,7 @@ fun CFGNode<*>.render(): String =
// NB: renderer has a state, so we have to create it each time // NB: renderer has a state, so we have to create it each time
private val CfgRenderer private val CfgRenderer
get() = FirRenderer().with(annotationRenderer = null, callArgumentsRenderer = FirCallNoArgumentsRenderer()) get() = FirRenderer(annotationRenderer = null, callArgumentsRenderer = FirCallNoArgumentsRenderer())
private fun FirFunction.name(): String = when (this) { private fun FirFunction.name(): String = when (this) {
is FirSimpleFunction -> name.asString() is FirSimpleFunction -> name.asString()
@@ -28,27 +28,41 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.* import java.util.*
class FirRenderer private constructor( class FirRenderer(
private val builder: StringBuilder, builder: StringBuilder = StringBuilder(),
components: FirComponentsImpl, private val annotationRenderer: FirAnnotationRenderer? = FirAnnotationRenderer(),
private val annotationRenderer: FirAnnotationRenderer?, private val bodyRenderer: FirBodyRenderer? = FirBodyRenderer(),
private val bodyRenderer: FirBodyRenderer?, private val callArgumentsRenderer: FirCallArgumentsRenderer = FirCallArgumentsRenderer(),
private val callArgumentsRenderer: FirCallArgumentsRenderer, private val classMemberRenderer: FirClassMemberRenderer = FirClassMemberRenderer(),
private val classMemberRenderer: FirClassMemberRenderer, private val contractRenderer: ConeContractRenderer? = ConeContractRenderer(),
private val contractRenderer: ConeContractRenderer?, private val declarationRenderer: FirDeclarationRenderer = FirDeclarationRenderer(),
private val declarationRenderer: FirDeclarationRenderer, private val idRenderer: ConeIdRenderer = ConeIdRendererForDebugging(),
private val idRenderer: ConeIdRenderer, private val modifierRenderer: FirModifierRenderer = FirAllModifierRenderer(),
private val modifierRenderer: FirModifierRenderer, private val packageDirectiveRenderer: FirPackageDirectiveRenderer? = null,
private val packageDirectiveRenderer: FirPackageDirectiveRenderer?, private val propertyAccessorRenderer: FirPropertyAccessorRenderer? = FirPropertyAccessorRenderer(),
private val propertyAccessorRenderer: FirPropertyAccessorRenderer?, resolvePhaseRenderer: FirResolvePhaseRenderer? = null,
private val resolvePhaseRenderer: FirResolvePhaseRenderer?, private val typeRenderer: ConeTypeRenderer = ConeTypeRendererForDebugging(),
private val typeRenderer: ConeTypeRenderer, private val valueParameterRenderer: FirValueParameterRenderer = FirValueParameterRenderer(),
private val valueParameterRenderer: FirValueParameterRenderer,
) : FirPrinter(builder) { ) : FirPrinter(builder) {
private val visitor = Visitor() private val visitor = Visitor()
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())
}
init { init {
val components = FirComponentsImpl()
components.visitor = visitor components.visitor = visitor
components.annotationRenderer = annotationRenderer components.annotationRenderer = annotationRenderer
components.bodyRenderer = bodyRenderer components.bodyRenderer = bodyRenderer
@@ -80,51 +94,6 @@ class FirRenderer private constructor(
valueParameterRenderer.components = components valueParameterRenderer.components = components
} }
private constructor(
builder: StringBuilder,
components: FirComponentsImpl,
) : this(
builder,
components,
FirAnnotationRenderer(),
FirBodyRenderer(),
FirCallArgumentsRenderer(),
FirClassMemberRenderer(),
ConeContractRenderer(),
FirDeclarationRenderer(),
ConeIdRendererForDebugging(),
FirAllModifierRenderer(),
packageDirectiveRenderer = null,
FirPropertyAccessorRenderer(),
resolvePhaseRenderer = null,
ConeTypeRendererForDebugging(),
FirValueParameterRenderer(),
)
constructor(builder: StringBuilder = StringBuilder()) : this(builder, FirComponentsImpl())
fun with(
annotationRenderer: FirAnnotationRenderer? = this.annotationRenderer,
bodyRenderer: FirBodyRenderer? = this.bodyRenderer,
callArgumentsRenderer: FirCallArgumentsRenderer = this.callArgumentsRenderer,
classMemberRenderer: FirClassMemberRenderer = this.classMemberRenderer,
contractRenderer: ConeContractRenderer? = this.contractRenderer,
declarationRenderer: FirDeclarationRenderer = this.declarationRenderer,
idRenderer: ConeIdRenderer = this.idRenderer,
modifierRenderer: FirModifierRenderer = this.modifierRenderer,
packageDirectiveRenderer: FirPackageDirectiveRenderer? = this.packageDirectiveRenderer,
propertyAccessorRenderer: FirPropertyAccessorRenderer? = this.propertyAccessorRenderer,
resolvePhaseRenderer: FirResolvePhaseRenderer? = this.resolvePhaseRenderer,
typeRenderer: ConeTypeRenderer = this.typeRenderer,
valueParameterRenderer: FirValueParameterRenderer = this.valueParameterRenderer,
): FirRenderer = FirRenderer(
builder, FirComponentsImpl(),
annotationRenderer, bodyRenderer, callArgumentsRenderer, classMemberRenderer,
contractRenderer, declarationRenderer, idRenderer, modifierRenderer,
packageDirectiveRenderer, propertyAccessorRenderer,
resolvePhaseRenderer, typeRenderer, valueParameterRenderer
)
fun renderElementAsString(element: FirElement): String { fun renderElementAsString(element: FirElement): String {
element.accept(visitor) element.accept(visitor)
return toString() return toString()
@@ -39,7 +39,8 @@ class FirDumpHandler(
addAll(info.session.createFilesWithGeneratedDeclarations()) addAll(info.session.createFilesWithGeneratedDeclarations())
} }
val renderer = FirRenderer(builderForModule).with( val renderer = FirRenderer(
builder = builderForModule,
packageDirectiveRenderer = FirPackageDirectiveRenderer(), packageDirectiveRenderer = FirPackageDirectiveRenderer(),
classMemberRenderer = FirClassMemberRendererWithGeneratedDeclarations(info.session) classMemberRenderer = FirClassMemberRendererWithGeneratedDeclarations(info.session)
) )
@@ -137,10 +137,7 @@ class FirScopeDumpHandler(testServices: TestServices) : FirAnalysisHandler(testS
private fun SmartPrinter.printInfo(declaration: FirCallableDeclaration, scope: FirTypeScope, counter: SymbolCounter) { private fun SmartPrinter.printInfo(declaration: FirCallableDeclaration, scope: FirTypeScope, counter: SymbolCounter) {
print("[${declaration.origin}]: ") print("[${declaration.origin}]: ")
val renderedDeclaration = FirRenderer().with( val renderedDeclaration = FirRenderer.noAnnotationBodiesAccessorAndArguments().renderElementAsString(declaration).trim()
annotationRenderer = null, bodyRenderer = null, propertyAccessorRenderer = null,
callArgumentsRenderer = FirCallNoArgumentsRenderer()
).renderElementAsString(declaration).trim()
print(renderedDeclaration) print(renderedDeclaration)
print(" from $scope") print(" from $scope")
println(" [id: ${counter.getIndex(declaration.symbol)}]") println(" [id: ${counter.getIndex(declaration.symbol)}]")