[Test] Implement handler which dumps overrides tree of specified classes
This commit is contained in:
committed by
TeamCityServer
parent
4299794de2
commit
523d37b0f5
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis
|
package org.jetbrains.kotlin.fir.analysis
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
|
|
||||||
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
@@ -37,7 +36,10 @@ class FirAnalyzerFacade(
|
|||||||
val useLightTree: Boolean = false
|
val useLightTree: Boolean = false
|
||||||
) {
|
) {
|
||||||
private var firFiles: List<FirFile>? = null
|
private var firFiles: List<FirFile>? = null
|
||||||
private var scopeSession: ScopeSession? = null
|
private var _scopeSession: ScopeSession? = null
|
||||||
|
val scopeSession: ScopeSession
|
||||||
|
get() = _scopeSession!!
|
||||||
|
|
||||||
private var collectedDiagnostics: Map<FirFile, List<FirDiagnostic<*>>>? = null
|
private var collectedDiagnostics: Map<FirFile, List<FirDiagnostic<*>>>? = null
|
||||||
|
|
||||||
private fun buildRawFir() {
|
private fun buildRawFir() {
|
||||||
@@ -62,16 +64,16 @@ class FirAnalyzerFacade(
|
|||||||
|
|
||||||
fun runResolution(): List<FirFile> {
|
fun runResolution(): List<FirFile> {
|
||||||
if (firFiles == null) buildRawFir()
|
if (firFiles == null) buildRawFir()
|
||||||
if (scopeSession != null) return firFiles!!
|
if (_scopeSession != null) return firFiles!!
|
||||||
val resolveProcessor = FirTotalResolveProcessor(session)
|
val resolveProcessor = FirTotalResolveProcessor(session)
|
||||||
resolveProcessor.process(firFiles!!)
|
resolveProcessor.process(firFiles!!)
|
||||||
scopeSession = resolveProcessor.scopeSession
|
_scopeSession = resolveProcessor.scopeSession
|
||||||
return firFiles!!
|
return firFiles!!
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
fun runCheckers(): Map<FirFile, List<FirDiagnostic<*>>> {
|
fun runCheckers(): Map<FirFile, List<FirDiagnostic<*>>> {
|
||||||
if (scopeSession == null) runResolution()
|
if (_scopeSession == null) runResolution()
|
||||||
if (collectedDiagnostics != null) return collectedDiagnostics!!
|
if (collectedDiagnostics != null) return collectedDiagnostics!!
|
||||||
val collector = FirDiagnosticsCollector.create(session)
|
val collector = FirDiagnosticsCollector.create(session)
|
||||||
collectedDiagnostics = buildMap {
|
collectedDiagnostics = buildMap {
|
||||||
@@ -83,11 +85,11 @@ class FirAnalyzerFacade(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult {
|
fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult {
|
||||||
if (scopeSession == null) runResolution()
|
if (_scopeSession == null) runResolution()
|
||||||
val signaturer = JvmIdSignatureDescriptor(JvmManglerDesc())
|
val signaturer = JvmIdSignatureDescriptor(JvmManglerDesc())
|
||||||
|
|
||||||
return Fir2IrConverter.createModuleFragment(
|
return Fir2IrConverter.createModuleFragment(
|
||||||
session, scopeSession!!, firFiles!!,
|
session, _scopeSession!!, firFiles!!,
|
||||||
languageVersionSettings, signaturer,
|
languageVersionSettings, signaturer,
|
||||||
extensions, FirJvmKotlinMangler(session), IrFactoryImpl,
|
extensions, FirJvmKotlinMangler(session), IrFactoryImpl,
|
||||||
FirJvmVisibilityConverter,
|
FirJvmVisibilityConverter,
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
|
|||||||
val renderCallableFqNames: Boolean,
|
val renderCallableFqNames: Boolean,
|
||||||
val renderDeclarationResolvePhase: Boolean,
|
val renderDeclarationResolvePhase: Boolean,
|
||||||
val renderAnnotation: Boolean,
|
val renderAnnotation: Boolean,
|
||||||
|
val renderBodies: Boolean = true,
|
||||||
|
val renderPropertyAccessors: Boolean = true,
|
||||||
) {
|
) {
|
||||||
object Normal : RenderMode(
|
object Normal : RenderMode(
|
||||||
renderLambdaBodies = true,
|
renderLambdaBodies = true,
|
||||||
@@ -86,6 +88,16 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
|
|||||||
renderDeclarationResolvePhase = true,
|
renderDeclarationResolvePhase = true,
|
||||||
renderAnnotation = true,
|
renderAnnotation = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
object NoBodies : RenderMode(
|
||||||
|
renderLambdaBodies = false,
|
||||||
|
renderCallArguments = false,
|
||||||
|
renderCallableFqNames = false,
|
||||||
|
renderDeclarationResolvePhase = false,
|
||||||
|
renderAnnotation = false,
|
||||||
|
renderBodies = false,
|
||||||
|
renderPropertyAccessors = false,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val printer = Printer(builder)
|
private val printer = Printer(builder)
|
||||||
@@ -442,6 +454,7 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
|
|||||||
override fun visitProperty(property: FirProperty) {
|
override fun visitProperty(property: FirProperty) {
|
||||||
visitVariable(property)
|
visitVariable(property)
|
||||||
if (property.isLocal) return
|
if (property.isLocal) return
|
||||||
|
if (!mode.renderPropertyAccessors) return
|
||||||
println()
|
println()
|
||||||
pushIndent()
|
pushIndent()
|
||||||
property.getter?.accept(this)
|
property.getter?.accept(this)
|
||||||
@@ -543,14 +556,17 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
|
|||||||
anonymousInitializer.body?.renderBody()
|
anonymousInitializer.body?.renderBody()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirBlock.renderBody(additionalStatements: List<FirStatement> = emptyList()) = when (this) {
|
private fun FirBlock.renderBody(additionalStatements: List<FirStatement> = emptyList()) {
|
||||||
is FirLazyBlock -> {
|
if (!mode.renderBodies) return
|
||||||
println(" { LAZY_BLOCK }")
|
when (this) {
|
||||||
}
|
is FirLazyBlock -> {
|
||||||
else -> renderInBraces {
|
println(" { LAZY_BLOCK }")
|
||||||
for (statement in additionalStatements + statements) {
|
}
|
||||||
statement.accept(this@FirRenderer)
|
else -> renderInBraces {
|
||||||
println()
|
for (statement in additionalStatements + statements) {
|
||||||
|
statement.accept(this@FirRenderer)
|
||||||
|
println()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.declarations
|
package org.jetbrains.kotlin.fir.declarations
|
||||||
|
|
||||||
sealed class FirDeclarationOrigin(val fromSupertypes: Boolean = false) {
|
sealed class FirDeclarationOrigin(private val displayName: String? = null, val fromSupertypes: Boolean = false) {
|
||||||
object Source : FirDeclarationOrigin()
|
object Source : FirDeclarationOrigin()
|
||||||
object Library : FirDeclarationOrigin()
|
object Library : FirDeclarationOrigin()
|
||||||
object BuiltIns : FirDeclarationOrigin()
|
object BuiltIns : FirDeclarationOrigin()
|
||||||
@@ -18,7 +18,11 @@ sealed class FirDeclarationOrigin(val fromSupertypes: Boolean = false) {
|
|||||||
object IntersectionOverride : FirDeclarationOrigin(fromSupertypes = true)
|
object IntersectionOverride : FirDeclarationOrigin(fromSupertypes = true)
|
||||||
object Delegated : FirDeclarationOrigin()
|
object Delegated : FirDeclarationOrigin()
|
||||||
|
|
||||||
class Plugin(val key: FirPluginKey) : FirDeclarationOrigin()
|
class Plugin(val key: FirPluginKey) : FirDeclarationOrigin(displayName = "Plugin[$key]")
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return displayName ?: this::class.simpleName!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class FirPluginKey
|
abstract class FirPluginKey
|
||||||
|
|||||||
+8
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.directives
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability.Global
|
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability.Global
|
||||||
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
|
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
|
||||||
|
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirScopeDumpHandler
|
||||||
|
|
||||||
object FirDiagnosticsDirectives : SimpleDirectivesContainer() {
|
object FirDiagnosticsDirectives : SimpleDirectivesContainer() {
|
||||||
val DUMP_CFG by directive(
|
val DUMP_CFG by directive(
|
||||||
@@ -49,4 +50,11 @@ object FirDiagnosticsDirectives : SimpleDirectivesContainer() {
|
|||||||
val WITH_EXTENDED_CHECKERS by directive(
|
val WITH_EXTENDED_CHECKERS by directive(
|
||||||
description = "Enable extended checkers"
|
description = "Enable extended checkers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val SCOPE_DUMP by stringDirective(
|
||||||
|
description = """
|
||||||
|
Dump hierarchies of overrides of classes listed in arguments
|
||||||
|
Enables ${FirScopeDumpHandler::class}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.test.frontend.fir.handlers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirRenderer
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.render
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.render
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
|
||||||
|
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
|
||||||
|
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
|
||||||
|
import org.jetbrains.kotlin.test.model.TestModule
|
||||||
|
import org.jetbrains.kotlin.test.services.TestServices
|
||||||
|
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||||
|
import org.jetbrains.kotlin.test.utils.MultiModuleInfoDumperImpl
|
||||||
|
import org.jetbrains.kotlin.test.utils.withExtension
|
||||||
|
import org.jetbrains.kotlin.util.SmartPrinter
|
||||||
|
import org.jetbrains.kotlin.util.withIndent
|
||||||
|
|
||||||
|
class FirScopeDumpHandler(testServices: TestServices) : FirAnalysisHandler(testServices) {
|
||||||
|
private val dumper = MultiModuleInfoDumperImpl()
|
||||||
|
|
||||||
|
override val directivesContainers: List<DirectivesContainer>
|
||||||
|
get() = listOf(FirDiagnosticsDirectives)
|
||||||
|
|
||||||
|
override fun processModule(module: TestModule, info: FirOutputArtifact) {
|
||||||
|
val fqNames = module.directives[FirDiagnosticsDirectives.SCOPE_DUMP]
|
||||||
|
if (fqNames.isEmpty()) return
|
||||||
|
val printer = SmartPrinter(dumper.builderForModule(module), indent = " ")
|
||||||
|
for (fqName in fqNames) {
|
||||||
|
printer.processClass(fqName, info.session, info.firAnalyzerFacade.scopeSession, module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SmartPrinter.processClass(fqName: String, session: FirSession, scopeSession: ScopeSession, module: TestModule) {
|
||||||
|
val classId = ClassId.topLevel(FqName.fromSegments(fqName.split(".")))
|
||||||
|
val symbol = session.symbolProvider.getClassLikeSymbolByFqName(classId) ?: assertions.fail {
|
||||||
|
"Class $fqName not found in module ${module.name}"
|
||||||
|
}
|
||||||
|
val firClass = symbol.fir as? FirRegularClass ?: assertions.fail { "$fqName is not a class but ${symbol.fir.render()}" }
|
||||||
|
println("$fqName: ")
|
||||||
|
|
||||||
|
val scope = firClass.unsubstitutedScope(session, scopeSession, withForcedTypeCalculator = true)
|
||||||
|
val names = scope.getCallableNames()
|
||||||
|
withIndent {
|
||||||
|
for (name in names) {
|
||||||
|
processFunctions(name, scope)
|
||||||
|
processProperties(name, scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SymbolCounter {
|
||||||
|
private val map = mutableMapOf<AbstractFirBasedSymbol<*>, Int>()
|
||||||
|
private var counter = 0
|
||||||
|
|
||||||
|
fun getIndex(symbol: AbstractFirBasedSymbol<*>): Int {
|
||||||
|
return map.computeIfAbsent(symbol) { counter++ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SmartPrinter.processFunctions(name: Name, scope: FirTypeScope) {
|
||||||
|
val functions = scope.getFunctions(name)
|
||||||
|
for (function in functions) {
|
||||||
|
processFunction(function, scope, SymbolCounter())
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SmartPrinter.processFunction(symbol: FirNamedFunctionSymbol, scope: FirTypeScope, counter: SymbolCounter) {
|
||||||
|
printInfo(symbol.fir, counter)
|
||||||
|
scope.processDirectOverriddenFunctionsWithBaseScope(symbol) { overriden, baseScope ->
|
||||||
|
withIndent {
|
||||||
|
processFunction(overriden, baseScope, counter)
|
||||||
|
}
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SmartPrinter.processProperties(name: Name, scope: FirTypeScope) {
|
||||||
|
val properties = scope.getProperties(name)
|
||||||
|
for (property in properties) {
|
||||||
|
if (property !is FirPropertySymbol) continue
|
||||||
|
processProperty(property, scope, SymbolCounter())
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SmartPrinter.processProperty(symbol: FirPropertySymbol, scope: FirTypeScope, counter: SymbolCounter) {
|
||||||
|
printInfo(symbol.fir, counter)
|
||||||
|
withIndent {
|
||||||
|
scope.processDirectOverriddenPropertiesWithBaseScope(symbol) { overriden, baseScope ->
|
||||||
|
processProperty(overriden, baseScope, counter)
|
||||||
|
ProcessorAction.NEXT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SmartPrinter.printInfo(declaration: FirCallableMemberDeclaration<*>, counter: SymbolCounter) {
|
||||||
|
print("[${declaration.origin}]: ")
|
||||||
|
print(declaration.render(FirRenderer.RenderMode.NoBodies).trim())
|
||||||
|
print(" from ${declaration.dispatchReceiverType?.render()}")
|
||||||
|
println(" [id: ${counter.getIndex(declaration.symbol)}]")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||||
|
if (dumper.isEmpty()) return
|
||||||
|
val expectedFile = testServices.moduleStructure.originalTestDataFiles.first().withExtension(".overrides.txt")
|
||||||
|
val actualDump = dumper.generateResultingDump()
|
||||||
|
assertions.assertEqualsToFile(expectedFile, actualDump)
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.runners.codegen
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.test.Constructor
|
import org.jetbrains.kotlin.test.Constructor
|
||||||
import org.jetbrains.kotlin.test.TargetBackend
|
import org.jetbrains.kotlin.test.TargetBackend
|
||||||
|
import org.jetbrains.kotlin.test.backend.handlers.BytecodeListingHandler
|
||||||
import org.jetbrains.kotlin.test.backend.handlers.IrTextDumpHandler
|
import org.jetbrains.kotlin.test.backend.handlers.IrTextDumpHandler
|
||||||
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
|
import org.jetbrains.kotlin.test.backend.ir.JvmIrBackendFacade
|
||||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||||
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.test.frontend.fir.FirFrontendFacade
|
|||||||
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
|
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
|
||||||
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirCfgDumpHandler
|
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirCfgDumpHandler
|
||||||
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDumpHandler
|
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDumpHandler
|
||||||
|
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirScopeDumpHandler
|
||||||
import org.jetbrains.kotlin.test.model.*
|
import org.jetbrains.kotlin.test.model.*
|
||||||
|
|
||||||
open class AbstractFirBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase<FirOutputArtifact>(
|
open class AbstractFirBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase<FirOutputArtifact>(
|
||||||
@@ -38,9 +40,10 @@ open class AbstractFirBlackBoxCodegenTest : AbstractJvmBlackBoxCodegenTestBase<F
|
|||||||
// See KT-44152
|
// See KT-44152
|
||||||
-USE_PSI_CLASS_FILES_READING
|
-USE_PSI_CLASS_FILES_READING
|
||||||
}
|
}
|
||||||
useFrontendHandlers(::FirDumpHandler)
|
useFrontendHandlers(::FirDumpHandler, ::FirScopeDumpHandler)
|
||||||
useFrontendHandlers(::FirCfgDumpHandler)
|
useFrontendHandlers(::FirCfgDumpHandler)
|
||||||
useBackendHandlers(::IrTextDumpHandler)
|
useBackendHandlers(::IrTextDumpHandler)
|
||||||
|
useArtifactsHandlers(::BytecodeListingHandler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ package org.jetbrains.kotlin.util
|
|||||||
|
|
||||||
import java.lang.Appendable
|
import java.lang.Appendable
|
||||||
|
|
||||||
class SmartPrinter(appendable: Appendable) {
|
class SmartPrinter(appendable: Appendable, indent: String = DEFAULT_INDENT) {
|
||||||
private val printer = org.jetbrains.kotlin.utils.Printer(appendable)
|
companion object {
|
||||||
|
private const val DEFAULT_INDENT = " "
|
||||||
|
}
|
||||||
|
|
||||||
|
private val printer = org.jetbrains.kotlin.utils.Printer(appendable, indent)
|
||||||
|
|
||||||
private var notFirstPrint: Boolean = false
|
private var notFirstPrint: Boolean = false
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user