diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt index 770f6dd398b..a2ab4d798db 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/symbols/AbstractSymbolTest.kt @@ -7,21 +7,26 @@ package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.DO_NOT_CHECK_SYMBOL_RESTORE +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.DO_NOT_CHECK_SYMBOL_RESTORE_K1 +import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.symbols.SymbolTestDirectives.DO_NOT_CHECK_SYMBOL_RESTORE_K2 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.pointers.KtSymbolPointer import org.jetbrains.kotlin.analysis.test.framework.base.AbstractAnalysisApiSingleFileTest +import org.jetbrains.kotlin.analysis.test.framework.test.configurators.FrontendKind import org.jetbrains.kotlin.analysis.test.framework.utils.executeOnPooledThreadInReadAction 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 +import org.jetbrains.kotlin.test.directives.model.Directive import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.assertions +import kotlin.test.fail abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() { private val renderingOptions = KtDeclarationRendererOptions.DEFAULT @@ -38,27 +43,35 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() { 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 directives = module.directives + val directiveToIgnore = DO_NOT_CHECK_SYMBOL_RESTORE.takeIf { it in directives } + ?: DO_NOT_CHECK_SYMBOL_RESTORE_K1.takeIf { configurator.frontendKind == FrontendKind.Fe10 && it in directives } + ?: DO_NOT_CHECK_SYMBOL_RESTORE_K2.takeIf { configurator.frontendKind == FrontendKind.Fir && it in directives } val prettyRenderOptions = when (prettyRenderMode) { PrettyRenderingMode.RENDER_SYMBOLS_LINE_BY_LINE -> renderingOptions PrettyRenderingMode.RENDER_SYMBOLS_NESTED -> renderingOptions.copy(renderClassMembers = true) } + fun KtSymbol.safePointer(): KtSymbolPointer? { + val result = kotlin.runCatching { createPointer() } + return if (directiveToIgnore == null) result.getOrThrow() else result.getOrNull() + } + val pointersWithRendered = executeOnPooledThreadInReadAction { analyseForTest(ktFile) { val (symbols, symbolForPrettyRendering) = collectSymbols(ktFile, testServices) val pointerWithRenderedSymbol = symbols.map { symbol -> PointerWithRenderedSymbol( - if (createPointers) symbol.createPointer() else null, + symbol.safePointer(), renderSymbolForComparison(symbol), ) } val pointerWithPrettyRenderedSymbol = symbolForPrettyRendering.map { symbol -> PointerWithRenderedSymbol( - if (createPointers) symbol.createPointer() else null, + symbol.safePointer(), when (symbol) { is KtDeclarationSymbol -> symbol.render(prettyRenderOptions) is KtFileSymbol -> prettyPrint { @@ -80,9 +93,7 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() { configurator.doOutOfBlockModification(ktFile) - if (createPointers) { - restoreSymbolsInOtherReadActionAndCompareResults(ktFile, pointersWithRendered.pointers, testServices) - } + restoreSymbolsInOtherReadActionAndCompareResults(directiveToIgnore, ktFile, pointersWithRendered.pointers, testServices) } private fun compareResults( @@ -104,20 +115,35 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() { else joinToString(separator = "\n\n") private fun restoreSymbolsInOtherReadActionAndCompareResults( + directiveToIgnore: Directive?, ktFile: KtFile, pointersWithRendered: List, testServices: TestServices, ) { - val restored = analyseForTest(ktFile) { - pointersWithRendered.map { (pointer, expectedRender) -> - val restored = pointer!!.restoreSymbol() - ?: error("Symbol $expectedRender was not restored") + var failed = false + try { + val restored = analyseForTest(ktFile) { + pointersWithRendered.map { (pointer, expectedRender) -> + val restored = pointer!!.restoreSymbol() ?: error("Symbol $expectedRender was not restored") - renderSymbolForComparison(restored) + renderSymbolForComparison(restored) + } } + val actual = restored.renderAsDeclarations() + testServices.assertions.assertEqualsToTestDataFileSibling(actual) + } catch (e: Throwable) { + if (directiveToIgnore == null) throw e + failed = true } - val actual = restored.renderAsDeclarations() - testServices.assertions.assertEqualsToTestDataFileSibling(actual) + + if (failed || directiveToIgnore == null) return + + testServices.assertions.assertEqualsToTestDataFileSibling( + actual = ktFile.text.lines().filterNot { it == "// ${directiveToIgnore.name}" }.joinToString(separator = "\n"), + extension = "kt", + ) + + fail("Redundant // ${directiveToIgnore.name} directive") } protected open fun KtAnalysisSession.renderSymbolForComparison(symbol: KtSymbol): String { @@ -128,7 +154,14 @@ abstract class AbstractSymbolTest : AbstractAnalysisApiSingleFileTest() { object SymbolTestDirectives : SimpleDirectivesContainer() { val DO_NOT_CHECK_SYMBOL_RESTORE by directive( description = "Symbol restoring for some symbols in current test is not supported yet", - applicability = DirectiveApplicability.Global + ) + + val DO_NOT_CHECK_SYMBOL_RESTORE_K1 by directive( + description = "Symbol restoring for some symbols in current test is not supported yet in K1", + ) + + val DO_NOT_CHECK_SYMBOL_RESTORE_K2 by directive( + description = "Symbol restoring for some symbols in current test is not supported yet in K2", ) } diff --git a/analysis/analysis-api/testData/symbols/symbolByPsi/classInitializer.kt b/analysis/analysis-api/testData/symbols/symbolByPsi/classInitializer.kt index 8df6cd9bbd6..f937a0215d7 100644 --- a/analysis/analysis-api/testData/symbols/symbolByPsi/classInitializer.kt +++ b/analysis/analysis-api/testData/symbols/symbolByPsi/classInitializer.kt @@ -1,5 +1,3 @@ -// DO_NOT_CHECK_SYMBOL_RESTORE - class A { val i: Int init { diff --git a/analysis/analysis-api/testData/symbols/symbolByReference/constructorViaTypeAlias.kt b/analysis/analysis-api/testData/symbols/symbolByReference/constructorViaTypeAlias.kt index c02c88dd4ac..b5ae39c4e73 100644 --- a/analysis/analysis-api/testData/symbols/symbolByReference/constructorViaTypeAlias.kt +++ b/analysis/analysis-api/testData/symbols/symbolByReference/constructorViaTypeAlias.kt @@ -1,5 +1,4 @@ // WITH_STDLIB -// DO_NOT_CHECK_SYMBOL_RESTORE fun x() { val a = ArrayList(listOf(1)) diff --git a/analysis/analysis-api/testData/symbols/symbolByReference/explicitLambdaParameter.kt b/analysis/analysis-api/testData/symbols/symbolByReference/explicitLambdaParameter.kt index adbf2be31a9..d129bb0e5a2 100644 --- a/analysis/analysis-api/testData/symbols/symbolByReference/explicitLambdaParameter.kt +++ b/analysis/analysis-api/testData/symbols/symbolByReference/explicitLambdaParameter.kt @@ -1,5 +1,3 @@ -// DO_NOT_CHECK_SYMBOL_RESTORE - inline fun T.use(block: (T) -> R): R { return block(this) } diff --git a/analysis/analysis-api/testData/symbols/symbolByReference/genericFromFunctionInLocalClass.kt b/analysis/analysis-api/testData/symbols/symbolByReference/genericFromFunctionInLocalClass.kt index 3aeeb613330..e148d7afb89 100644 --- a/analysis/analysis-api/testData/symbols/symbolByReference/genericFromFunctionInLocalClass.kt +++ b/analysis/analysis-api/testData/symbols/symbolByReference/genericFromFunctionInLocalClass.kt @@ -1,4 +1,3 @@ -// DO_NOT_CHECK_SYMBOL_RESTORE package test class SomeClass diff --git a/analysis/analysis-api/testData/symbols/symbolByReference/genericFromOuterClassInInnerClass.kt b/analysis/analysis-api/testData/symbols/symbolByReference/genericFromOuterClassInInnerClass.kt index c72010b87a4..c9769c93e72 100644 --- a/analysis/analysis-api/testData/symbols/symbolByReference/genericFromOuterClassInInnerClass.kt +++ b/analysis/analysis-api/testData/symbols/symbolByReference/genericFromOuterClassInInnerClass.kt @@ -1,4 +1,3 @@ -// DO_NOT_CHECK_SYMBOL_RESTORE package test class SomeClass