FIR IDE: make all HL tests covering depended mode

Also changed tests to do the analysis on the KtElement of
interest instead of the KtFile where possible because currently depended
mode does not support analysing the entire file. Maybe we should support
analysing the whole file at some point.
This commit is contained in:
Tianyu Geng
2021-10-04 13:33:19 -07:00
committed by Roman Golyshev
parent 0f016c89aa
commit a08ab45e22
14 changed files with 76 additions and 67 deletions
@@ -7,17 +7,18 @@ package org.jetbrains.kotlin.analysis.api.fir
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
import org.jetbrains.kotlin.analysis.api.components.RendererModifier import org.jetbrains.kotlin.analysis.api.components.RendererModifier
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest
import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
import org.jetbrains.kotlin.idea.references.KtReference import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
@@ -45,11 +46,12 @@ abstract class AbstractReferenceResolveTest : AbstractHLApiSingleModuleTest() {
testServices.assertions.fail { "No references at caret found" } testServices.assertions.fail { "No references at caret found" }
} }
val resolvedTo = analyse(mainKtFile) { val resolvedTo =
val symbols = ktReferences.flatMap { it.resolveToSymbols() } analyseForTest(PsiTreeUtil.findElementOfClassAtOffset(mainKtFile, caretPosition, KtDeclaration::class.java, false) ?: mainKtFile) {
checkReferenceResultForValidity(module, testServices, symbols) val symbols = ktReferences.flatMap { it.resolveToSymbols() }
renderResolvedTo(symbols) checkReferenceResultForValidity(module, testServices, symbols)
} renderResolvedTo(symbols)
}
if (Directives.UNRESOLVED_REFERENCE in module.directives) { if (Directives.UNRESOLVED_REFERENCE in module.directives) {
return return
@@ -5,11 +5,9 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.symbols.markers.* import org.jetbrains.kotlin.analysis.api.symbols.markers.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtValueArgument import org.jetbrains.kotlin.psi.KtValueArgument
@@ -26,11 +24,11 @@ abstract class AbstractCompileTimeConstantEvaluatorTest : AbstractHLApiSingleFil
else -> null else -> null
} ?: testServices.assertions.fail { "Unsupported expression: $element" } } ?: testServices.assertions.fail { "Unsupported expression: $element" }
val constantValue = executeOnPooledThreadInReadAction { val constantValue = executeOnPooledThreadInReadAction {
analyse(expression) { expression.evaluate() } analyseForTest(expression) { expression.evaluate() }
} }
val actual = buildString { val actual = buildString {
appendLine("expression: ${expression.text}") appendLine("expression: ${expression.text}")
appendLine("constant_value: ${analyse(ktFile) { constantValue?.stringRepresentation() }}") appendLine("constant_value: ${analyseForTest(expression) { constantValue?.stringRepresentation() }}")
appendLine("constant: ${(constantValue as? KtLiteralConstantValue<*>)?.toConst()}") appendLine("constant: ${(constantValue as? KtLiteralConstantValue<*>)?.toConst()}")
} }
testServices.assertions.assertEqualsToFile(testDataFileSibling(".txt"), actual) testServices.assertions.assertEqualsToFile(testDataFileSibling(".txt"), actual)
@@ -5,10 +5,8 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
@@ -20,7 +18,7 @@ abstract class AbstractExpectedExpressionTypeTest : AbstractHLApiSingleFileTest(
val expressionAtCaret = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) as KtExpression val expressionAtCaret = testServices.expressionMarkerProvider.getElementOfTypAtCaret(ktFile) as KtExpression
val actualExpectedTypeText: String? = executeOnPooledThreadInReadAction { val actualExpectedTypeText: String? = executeOnPooledThreadInReadAction {
analyse(ktFile) { analyseForTest(expressionAtCaret) {
expressionAtCaret.getExpectedType()?.asStringForDebugging() expressionAtCaret.getExpectedType()?.asStringForDebugging()
} }
} }
@@ -5,15 +5,11 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions import org.jetbrains.kotlin.test.services.assertions
@@ -21,7 +17,7 @@ abstract class AbstractHLExpressionTypeTest : AbstractHLApiSingleFileTest() {
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile) as KtExpression val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile) as KtExpression
val type = executeOnPooledThreadInReadAction { val type = executeOnPooledThreadInReadAction {
analyse(expression) { expression.getKtType()?.render() } analyseForTest(expression) { expression.getKtType()?.render() }
} }
val actual = buildString { val actual = buildString {
appendLine("expression: ${expression.text}") appendLine("expression: ${expression.text}")
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
@@ -15,7 +14,7 @@ import org.jetbrains.kotlin.test.services.assertions
abstract class AbstractHLImportOptimizerTest : AbstractHLApiSingleModuleTest() { abstract class AbstractHLImportOptimizerTest : AbstractHLApiSingleModuleTest() {
override fun doTestByFileStructure(ktFiles: List<KtFile>, module: TestModule, testServices: TestServices) { override fun doTestByFileStructure(ktFiles: List<KtFile>, module: TestModule, testServices: TestServices) {
val mainKtFile = ktFiles.singleOrNull() ?: ktFiles.first { it.name == "main.kt" } val mainKtFile = ktFiles.singleOrNull() ?: ktFiles.first { it.name == "main.kt" }
val unusedImports = analyse(mainKtFile) { analyseImports(mainKtFile).unusedImports } val unusedImports = analyseForTest(mainKtFile) { analyseImports(mainKtFile).unusedImports }
val unusedImportPaths = unusedImports val unusedImportPaths = unusedImports
.map { it.importPath ?: error("Import $it should have an import path, instead was ${it.text}") } .map { it.importPath ?: error("Import $it should have an import path, instead was ${it.text}") }
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.analysis.api.fir.components
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -27,7 +26,7 @@ abstract class AbstractHasCommonSubtypeTest : AbstractHLApiSingleFileTest() {
val errors = mutableListOf<String>() val errors = mutableListOf<String>()
val originalText = ktFile.text val originalText = ktFile.text
val actualTextBuilder = StringBuilder() val actualTextBuilder = StringBuilder()
analyse(ktFile) { analyseForTest(ktFile) {
val visitor = object : KtTreeVisitorVoid() { val visitor = object : KtTreeVisitorVoid() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
if (element.firstChild == null) { if (element.firstChild == null) {
@@ -5,12 +5,10 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.parentsOfType import org.jetbrains.kotlin.analysis.low.level.api.fir.util.parentsOfType
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
@@ -26,7 +24,7 @@ abstract class AbstractOverriddenDeclarationProviderTest : AbstractHLApiSingleMo
val declaration = testServices.expressionMarkerProvider.getElementOfTypAtCaret<KtDeclaration>(ktFiles.first()) val declaration = testServices.expressionMarkerProvider.getElementOfTypAtCaret<KtDeclaration>(ktFiles.first())
val actual = executeOnPooledThreadInReadAction { val actual = executeOnPooledThreadInReadAction {
analyse(ktFiles.first()) { analyseForTest(declaration) {
val symbol = declaration.getSymbol() as KtCallableSymbol val symbol = declaration.getSymbol() as KtCallableSymbol
val allOverriddenSymbols = symbol.getAllOverriddenSymbols().map { renderSignature(it) } val allOverriddenSymbols = symbol.getAllOverriddenSymbols().map { renderSignature(it) }
val directlyOverriddenSymbols = symbol.getDirectlyOverriddenSymbols().map { renderSignature(it) } val directlyOverriddenSymbols = symbol.getDirectlyOverriddenSymbols().map { renderSignature(it) }
@@ -5,15 +5,11 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.assertions import org.jetbrains.kotlin.test.services.assertions
@@ -28,7 +24,7 @@ abstract class AbstractRendererTest : AbstractHLApiSingleFileTest() {
val actual = executeOnPooledThreadInReadAction { val actual = executeOnPooledThreadInReadAction {
buildString { buildString {
ktFile.declarations.forEach { ktFile.declarations.forEach {
analyse(it) { analyseForTest(it) {
append(it.getSymbol().render(options)) append(it.getSymbol().render(options))
appendLine() appendLine()
} }
@@ -7,12 +7,10 @@ package org.jetbrains.kotlin.analysis.api.fir.components
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.calls.KtCall import org.jetbrains.kotlin.analysis.api.calls.KtCall
import org.jetbrains.kotlin.analysis.api.calls.KtDelegatedConstructorCallKind import org.jetbrains.kotlin.analysis.api.calls.KtDelegatedConstructorCallKind
import org.jetbrains.kotlin.analysis.api.calls.KtErrorCallTarget import org.jetbrains.kotlin.analysis.api.calls.KtErrorCallTarget
import org.jetbrains.kotlin.analysis.api.calls.KtSuccessCallTarget import org.jetbrains.kotlin.analysis.api.calls.KtSuccessCallTarget
import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleModuleTest
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirSubstitutor import org.jetbrains.kotlin.analysis.api.fir.types.KtFirSubstitutor
import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.*
@@ -36,7 +34,7 @@ abstract class AbstractResolveCallTest : AbstractHLApiSingleModuleTest() {
val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile) val expression = testServices.expressionMarkerProvider.getSelectedElement(ktFile)
val actual = executeOnPooledThreadInReadAction { val actual = executeOnPooledThreadInReadAction {
analyse(ktFile) { analyseForTest(expression) {
resolveCall(expression)?.stringRepresentation() resolveCall(expression)?.stringRepresentation()
} }
} ?: "null" } ?: "null"
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.analysis.api.fir.scopes package org.jetbrains.kotlin.analysis.api.fir.scopes
import org.jetbrains.kotlin.analysis.api.fir.executeOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
@@ -17,7 +15,7 @@ import org.jetbrains.kotlin.test.services.assertions
abstract class AbstractFileScopeTest : AbstractHLApiSingleFileTest() { abstract class AbstractFileScopeTest : AbstractHLApiSingleFileTest() {
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) { override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
val actual = executeOnPooledThreadInReadAction { val actual = executeOnPooledThreadInReadAction {
analyse(ktFile) { analyseForTest(ktFile) {
val symbol = ktFile.getFileSymbol() val symbol = ktFile.getFileSymbol()
val scope = symbol.getFileScope() val scope = symbol.getFileScope()
with(DebugSymbolRenderer) { with(DebugSymbolRenderer) {
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.analysis.api.fir.symbols
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory
import org.jetbrains.kotlin.analysis.api.fir.analyseOnPooledThreadInReadAction
import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest import org.jetbrains.kotlin.analysis.api.fir.test.framework.AbstractHLApiSingleFileTest
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer import org.jetbrains.kotlin.analysis.api.symbols.DebugSymbolRenderer
@@ -5,28 +5,8 @@
package org.jetbrains.kotlin.analysis.api.fir package org.jetbrains.kotlin.analysis.api.fir
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.DuplicatedFirSourceElementsException import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.DuplicatedFirSourceElementsException
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
import java.io.File
inline fun <T> runReadAction(crossinline runnable: () -> T): T {
return ApplicationManager.getApplication().runReadAction(Computable { runnable() })
}
fun <R> executeOnPooledThreadInReadAction(action: () -> R): R =
ApplicationManager.getApplication().executeOnPooledThread<R> { runReadAction(action) }.get()
inline fun <R> analyseOnPooledThreadInReadAction(context: KtElement, crossinline action: KtAnalysisSession.() -> R): R =
executeOnPooledThreadInReadAction {
analyse(context) { action() }
}
/** /**
* Temporary * Temporary
@@ -23,7 +23,7 @@ class TestKtModuleProvider(
internal fun getModuleInfoByKtFile(ktFile: KtFile): TestKtSourceModule = internal fun getModuleInfoByKtFile(ktFile: KtFile): TestKtSourceModule =
cache.values.first { moduleSourceInfo -> cache.values.first { moduleSourceInfo ->
ktFile in moduleSourceInfo.ktFiles (if (ktFile.isPhysical) ktFile else ktFile.originalFile) in moduleSourceInfo.ktFiles
} }
internal fun getModule(moduleName: String): TestKtSourceModule = internal fun getModule(moduleName: String): TestKtSourceModule =
@@ -8,13 +8,19 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.test.base
import com.intellij.mock.MockApplication import com.intellij.mock.MockApplication
import com.intellij.mock.MockProject import com.intellij.mock.MockProject
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Computable
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import com.intellij.testFramework.TestDataFile import com.intellij.testFramework.TestDataFile
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyse
import org.jetbrains.kotlin.analysis.api.analyseInDependedAnalysisSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.ModuleRegistrarPreAnalysisHandler import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.ModuleRegistrarPreAnalysisHandler
import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.TestKtModuleProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.TestKtModuleProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.projectModuleProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based.projectModuleProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.TestInfrastructureInternals import org.jetbrains.kotlin.test.TestInfrastructureInternals
import org.jetbrains.kotlin.test.bind import org.jetbrains.kotlin.test.bind
@@ -33,10 +39,12 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInfo import org.junit.jupiter.api.TestInfo
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.util.concurrent.ExecutionException
import kotlin.io.path.nameWithoutExtension import kotlin.io.path.nameWithoutExtension
abstract class AbstractLowLevelApiTest : TestWithDisposable() { abstract class AbstractLowLevelApiTest : TestWithDisposable() {
private lateinit var testInfo: KotlinTestInfo private lateinit var testInfo: KotlinTestInfo
private var useDependedAnalysisSession: Boolean = false
@OptIn(TestInfrastructureInternals::class) @OptIn(TestInfrastructureInternals::class)
private val configure: TestConfigurationBuilder.() -> Unit = { private val configure: TestConfigurationBuilder.() -> Unit = {
@@ -102,11 +110,24 @@ abstract class AbstractLowLevelApiTest : TestWithDisposable() {
registerApplicationServices() registerApplicationServices()
doTestByFileStructure( val ktFiles = moduleInfo.testFilesToKtFiles.filterKeys { testFile -> !testFile.isAdditional }.values.toList()
moduleInfo.testFilesToKtFiles.filter { (testFile, _) -> !testFile.isAdditional }.values.toList(),
moduleStructure, doTestByFileStructure(ktFiles, moduleStructure, testServices)
testServices useDependedAnalysisSession = true
) try {
doTestByFileStructure(ktFiles.map {
val fakeFile = it.copy() as KtFile
fakeFile.originalKtFile = it
fakeFile
}, moduleStructure, testServices)
} catch (e: SkipDependedModeException) {
// Skip the test if needed
} catch (e: ExecutionException) {
if (e.cause !is SkipDependedModeException)
throw Exception("Test succeeded in normal analysis mode but failed in depended analysis mode.", e)
} catch (e: Exception) {
throw Exception("Test succeeded in normal analysis mode but failed in depended analysis mode.", e)
}
} }
private fun registerApplicationServices() { private fun registerApplicationServices() {
@@ -130,5 +151,32 @@ abstract class AbstractLowLevelApiTest : TestWithDisposable() {
tags = testInfo.tags tags = testInfo.tags
) )
} }
protected inline fun <R> analyseOnPooledThreadInReadAction(context: KtElement, crossinline action: KtAnalysisSession.() -> R): R =
executeOnPooledThreadInReadAction {
analyseForTest(context) { action() }
}
protected inline fun <T> runReadAction(crossinline runnable: () -> T): T {
return ApplicationManager.getApplication().runReadAction(Computable { runnable() })
}
protected inline fun <R> executeOnPooledThreadInReadAction(crossinline action: () -> R): R =
ApplicationManager.getApplication().executeOnPooledThread<R> { runReadAction(action) }.get()
protected fun <R> analyseForTest(contextElement: KtElement, action: KtAnalysisSession.() -> R): R {
return if (useDependedAnalysisSession) {
// Depended mode does not support analysing a KtFile. See org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir#getResolveStateForDependentCopy
if (contextElement is KtFile) throw SkipDependedModeException()
require(!contextElement.isPhysical)
analyseInDependedAnalysisSession(contextElement.containingKtFile.originalKtFile!!, contextElement, action)
} else {
analyse(contextElement, action)
}
}
private class SkipDependedModeException : Exception()
} }