Analysis API: pretty print declarations additionaly to debug rendering in some tests

This commit is contained in:
Ilya Kirillov
2021-11-30 13:16:46 +01:00
parent bad91915a6
commit 6e4c87f138
81 changed files with 918 additions and 23 deletions
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.SymbolByFqName
import org.jetbrains.kotlin.analysis.api.impl.base.test.symbols.AbstractSymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.symbols.SymbolsData
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.*
@@ -18,11 +19,11 @@ abstract class AbstractDelegateMemberScopeTest(
configurator: FrontendApiTestConfiguratorService
) : AbstractSymbolByFqNameTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val symbolData = SymbolByFqName.getSymbolDataFromFile(testDataPath)
val symbols = with(symbolData) { toSymbols() }
val classSymbol = symbols.singleOrNull() as? KtClassOrObjectSymbol
?: error("Should be a single class symbol, but $symbols found")
return classSymbol.getDelegatedMemberScope().getCallableSymbols().toList()
return SymbolsData(classSymbol.getDelegatedMemberScope().getCallableSymbols().toList())
}
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.SymbolByFqName
import org.jetbrains.kotlin.analysis.api.impl.base.test.symbols.AbstractSymbolByFqNameTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.symbols.SymbolsData
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.psi.KtFile
@@ -18,11 +19,11 @@ abstract class AbstractMemberScopeByFqNameTest(
configurator: FrontendApiTestConfiguratorService
) : AbstractSymbolByFqNameTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val symbolData = SymbolByFqName.getSymbolDataFromFile(testDataPath)
val symbols = with(symbolData) { toSymbols() }
val classSymbol = symbols.singleOrNull() as? KtClassOrObjectSymbol
?: error("Should be a single class symbol, but $symbols found")
return classSymbol.getMemberScope().getAllSymbols().toList()
return SymbolsData(classSymbol.getMemberScope().getAllSymbols().toList())
}
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.api.impl.base.test.symbols.AbstractSymbolTest
import org.jetbrains.kotlin.analysis.api.impl.base.test.symbols.SymbolsData
import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
@@ -23,13 +24,13 @@ abstract class AbstractSubstitutionOverridesUnwrappingTest(
configurator: FrontendApiTestConfiguratorService
) : AbstractSymbolTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val declarationUnderCaret = testServices.expressionMarkerProvider.getElementOfTypAtCaret<KtClassLikeDeclaration>(ktFile)
val classSymbolUnderCaret = declarationUnderCaret.getSymbol() as KtClassLikeSymbol
require(classSymbolUnderCaret is KtSymbolWithMembers)
return classSymbolUnderCaret.getMemberScope().getAllSymbols().toList()
return SymbolsData(classSymbolUnderCaret.getMemberScope().getAllSymbols().toList())
}
override fun KtAnalysisSession.renderSymbolForComparison(symbol: KtSymbol): String {
@@ -15,9 +15,9 @@ import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractSymbolByFqNameTest(configurator: FrontendApiTestConfiguratorService) : AbstractSymbolTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val symbolData = SymbolByFqName.getSymbolDataFromFile(testDataPath)
return with(symbolData) { toSymbols() }
return SymbolsData(with(symbolData) { toSymbols() })
}
override fun configureTest(builder: TestConfigurationBuilder) {
@@ -15,10 +15,16 @@ import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractSymbolByPsiTest(configurator: FrontendApiTestConfiguratorService) : AbstractSymbolTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
return ktFile.collectDescendantsOfType<KtDeclaration> { it.isValidForSymbolCreation }.map { declaration ->
override val prettyRenderMode: PrettyRenderingMode get() = PrettyRenderingMode.RENDER_SYMBOLS_NESTED
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val allDeclarationSymbols = ktFile.collectDescendantsOfType<KtDeclaration> { it.isValidForSymbolCreation }.map { declaration ->
declaration.getSymbol()
}
return SymbolsData(
allDeclarationSymbols,
listOf(ktFile.getFileSymbol()),
)
}
private val KtDeclaration.isValidForSymbolCreation
@@ -15,8 +15,10 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractSymbolByReferenceTest(configurator: FrontendApiTestConfiguratorService) : AbstractSymbolTest(configurator) {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol> {
override fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData {
val referenceExpression = testServices.expressionMarkerProvider.getElementOfTypAtCaret<KtNameReferenceExpression>(ktFile)
return listOfNotNull(referenceExpression.mainReference.resolveToSymbol())
return SymbolsData(
listOfNotNull(referenceExpression.mainReference.resolveToSymbol())
)
}
}
@@ -6,11 +6,16 @@
package org.jetbrains.kotlin.analysis.api.impl.base.test.symbols
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer
import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
@@ -20,6 +25,10 @@ import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions
abstract class AbstractSymbolTest(configurator: FrontendApiTestConfiguratorService) : AbstractHLApiSingleFileTest(configurator) {
private val renderingOptions = KtDeclarationRendererOptions.DEFAULT
open val prettyRenderMode: PrettyRenderingMode = PrettyRenderingMode.RENDER_SYMBOLS_LINE_BY_LINE
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
with(builder) {
@@ -27,17 +36,42 @@ abstract class AbstractSymbolTest(configurator: FrontendApiTestConfiguratorServi
}
}
abstract fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): List<KtSymbol>
abstract fun KtAnalysisSession.collectSymbols(ktFile: KtFile, testServices: TestServices): SymbolsData
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
val createPointers = SymbolTestDirectives.DO_NOT_CHECK_SYMBOL_RESTORE !in module.directives
val prettyRenderOptions = when (prettyRenderMode) {
PrettyRenderingMode.RENDER_SYMBOLS_LINE_BY_LINE -> renderingOptions
PrettyRenderingMode.RENDER_SYMBOLS_NESTED -> renderingOptions.copy(renderClassMembers = true)
}
val pointersWithRendered = analyseOnPooledThreadInReadAction(ktFile) {
collectSymbols(ktFile, testServices).map { symbol ->
val (symbols, symbolForPrettyRendering) = collectSymbols(ktFile, testServices)
val pointerWithRenderedSymbol = symbols.map { symbol ->
PointerWithRenderedSymbol(
if (createPointers) symbol.createPointer() else null,
renderSymbolForComparison(symbol)
renderSymbolForComparison(symbol),
)
}
val pointerWithPrettyRenderedSymbol = symbolForPrettyRendering.map { symbol ->
PointerWithRenderedSymbol(
if (createPointers) symbol.createPointer() else null,
when (symbol) {
is KtDeclarationSymbol -> symbol.render(prettyRenderOptions)
is KtFileSymbol -> prettyPrint {
printCollection(symbol.getFileScope().getAllSymbols().asIterable(), separator = "\n\n") {
append((it as KtDeclarationSymbol).render(prettyRenderOptions))
}
}
else -> error(symbol::class.toString())
}
)
}
SymbolPointersData(pointerWithRenderedSymbol, pointerWithPrettyRenderedSymbol)
}
compareResults(pointersWithRendered, testServices)
@@ -45,16 +79,19 @@ abstract class AbstractSymbolTest(configurator: FrontendApiTestConfiguratorServi
configurator.doOutOfBlockModification(ktFile)
if (createPointers) {
restoreSymbolsInOtherReadActionAndCompareResults(ktFile, pointersWithRendered, testServices)
restoreSymbolsInOtherReadActionAndCompareResults(ktFile, pointersWithRendered.pointers, testServices)
}
}
private fun compareResults(
pointersWithRendered: List<PointerWithRenderedSymbol>,
data: SymbolPointersData,
testServices: TestServices,
) {
val actual = pointersWithRendered.joinToString(separator = "\n\n") { it.rendered }
val actual = data.pointers.joinToString(separator = "\n\n") { it.rendered }
testServices.assertions.assertEqualsToTestDataFileSibling(actual)
val actualPretty = data.pointersForPrettyRendering.joinToString(separator = "\n\n") { it.rendered }
testServices.assertions.assertEqualsToTestDataFileSibling(actualPretty, extension = ".pretty.txt")
}
private fun restoreSymbolsInOtherReadActionAndCompareResults(
@@ -86,4 +123,22 @@ private object SymbolTestDirectives : SimpleDirectivesContainer() {
)
}
private data class PointerWithRenderedSymbol(val pointer: KtSymbolPointer<*>?, val rendered: String)
enum class PrettyRenderingMode {
RENDER_SYMBOLS_LINE_BY_LINE,
RENDER_SYMBOLS_NESTED,
}
data class SymbolsData(
val symbols: List<KtSymbol>,
val symbolsForPrettyRendering: List<KtSymbol> = symbols,
)
private data class SymbolPointersData(
val pointers: List<PointerWithRenderedSymbol>,
val pointersForPrettyRendering: List<PointerWithRenderedSymbol>,
)
private data class PointerWithRenderedSymbol(
val pointer: KtSymbolPointer<*>?,
val rendered: String,
)