[Test] Merge multiple abstract legacy test runners into a single one
There was only one real inheritor of AbstractFirBaseDiagnosticTest, so there is no need in the whole hierarchy of abstract test runners Also AbstractFirOldFrontendLightClassesTest is not intended to check any diagnostics or CFG dumps, so this logic was removed (they still can be checked using non-legacy AbstractFirDiagnosticTest from the main test infrastructure)
This commit is contained in:
committed by
Space Team
parent
fa4c6d55c1
commit
2d334c4e71
+209
-5
@@ -1,24 +1,159 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 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.fir.java
|
||||
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiElementFinder
|
||||
import com.intellij.psi.impl.compiled.ClsClassImpl
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.fir.AbstractFirOldFrontendDiagnosticsTest
|
||||
import org.jetbrains.kotlin.KtInMemoryTextSourceFile
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.PsiBasedProjectFileSearchScope
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.VfsBasedProjectEnvironment
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.builder.BodyBuildingMode
|
||||
import org.jetbrains.kotlin.fir.builder.PsiRawFirBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.doFirResolveTestBench
|
||||
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.createAllCompilerResolveProcessors
|
||||
import org.jetbrains.kotlin.fir.session.FirSessionFactoryHelper
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.toSourceLinesMapping
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractFirOldFrontendLightClassesTest : AbstractFirOldFrontendDiagnosticsTest() {
|
||||
override fun checkResultingFirFiles(firFiles: List<FirFile>, testDataFile: File) {
|
||||
super.checkResultingFirFiles(firFiles, testDataFile)
|
||||
abstract class AbstractFirOldFrontendLightClassesTest : BaseDiagnosticsTest() {
|
||||
override fun analyzeAndCheck(testDataFile: File, files: List<TestFile>) {
|
||||
if (files.any { "FIR_IGNORE" in it.directives }) return
|
||||
try {
|
||||
analyzeAndCheckUnhandled(testDataFile, files, useLightTree)
|
||||
} catch (t: AssertionError) {
|
||||
throw t
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
}
|
||||
|
||||
private val useLightTree: Boolean
|
||||
get() = false
|
||||
|
||||
private val useLazyBodiesModeForRawFir: Boolean
|
||||
get() = false
|
||||
|
||||
override fun setupEnvironment(environment: KotlinCoreEnvironment) {
|
||||
PsiElementFinder.EP.getPoint(environment.project).unregisterExtension(JavaElementFinder::class.java)
|
||||
}
|
||||
|
||||
private fun analyzeAndCheckUnhandled(testDataFile: File, files: List<TestFile>, useLightTree: Boolean = false) {
|
||||
val groupedByModule = files.groupBy(TestFile::module)
|
||||
|
||||
val modules = createModules(groupedByModule)
|
||||
|
||||
val sessionProvider = FirProjectSessionProvider()
|
||||
|
||||
//For BuiltIns, registered in sessionProvider automatically
|
||||
val allProjectScope = GlobalSearchScope.allScope(project)
|
||||
|
||||
val configToSession = modules.mapValues { (config, info) ->
|
||||
val moduleFiles = groupedByModule.getValue(config)
|
||||
val scope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(
|
||||
project,
|
||||
moduleFiles.mapNotNull { it.ktFile }
|
||||
)
|
||||
val projectEnvironment = VfsBasedProjectEnvironment(
|
||||
project,
|
||||
VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
) { environment.createPackagePartProvider(it) }
|
||||
|
||||
FirSessionFactoryHelper.createSessionWithDependencies(
|
||||
Name.identifier(info.name.asString().removeSurrounding("<", ">")),
|
||||
info.platform,
|
||||
info.analyzerServices,
|
||||
externalSessionProvider = sessionProvider,
|
||||
projectEnvironment,
|
||||
config?.languageVersionSettings ?: LanguageVersionSettingsImpl.DEFAULT,
|
||||
javaSourcesScope = PsiBasedProjectFileSearchScope(scope),
|
||||
librariesScope = PsiBasedProjectFileSearchScope(allProjectScope),
|
||||
lookupTracker = null,
|
||||
enumWhenTracker = null,
|
||||
importTracker = null,
|
||||
incrementalCompilationContext = null,
|
||||
extensionRegistrars = emptyList(),
|
||||
needRegisterJavaElementFinder = true
|
||||
) {}
|
||||
}
|
||||
|
||||
val firFilesPerSession = mutableMapOf<FirSession, List<FirFile>>()
|
||||
|
||||
// TODO: make module/session/transformer handling like in AbstractFirMultiModuleTest (IDE)
|
||||
for ((testModule, testFilesInModule) in groupedByModule) {
|
||||
val ktFiles = getKtFiles(testFilesInModule, true)
|
||||
|
||||
val session = configToSession.getValue(testModule)
|
||||
|
||||
val firFiles = mutableListOf<FirFile>()
|
||||
mapKtFilesToFirFiles(session, ktFiles, firFiles, useLightTree)
|
||||
firFilesPerSession[session] = firFiles
|
||||
}
|
||||
|
||||
runAnalysis(testDataFile, firFilesPerSession)
|
||||
}
|
||||
|
||||
private fun mapKtFilesToFirFiles(session: FirSession, ktFiles: List<KtFile>, firFiles: MutableList<FirFile>, useLightTree: Boolean) {
|
||||
val firProvider = (session.firProvider as FirProviderImpl)
|
||||
if (useLightTree) {
|
||||
val lightTreeBuilder = LightTree2Fir(session, firProvider.kotlinScopeProvider)
|
||||
ktFiles.mapTo(firFiles) {
|
||||
val firFile =
|
||||
lightTreeBuilder.buildFirFile(
|
||||
it.text,
|
||||
KtInMemoryTextSourceFile(it.name, it.virtualFilePath, it.text),
|
||||
it.text.toSourceLinesMapping()
|
||||
)
|
||||
(session.firProvider as FirProviderImpl).recordFile(firFile)
|
||||
firFile
|
||||
}
|
||||
} else {
|
||||
val firBuilder = PsiRawFirBuilder(
|
||||
session,
|
||||
firProvider.kotlinScopeProvider,
|
||||
bodyBuildingMode = BodyBuildingMode.lazyBodies(useLazyBodiesModeForRawFir)
|
||||
)
|
||||
ktFiles.mapTo(firFiles) {
|
||||
val firFile = firBuilder.buildFirFile(it)
|
||||
firProvider.recordFile(firFile)
|
||||
firFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAnalysis(testDataFile: File, firFilesPerSession: Map<FirSession, List<FirFile>>) {
|
||||
for ((session, firFiles) in firFilesPerSession) {
|
||||
doFirResolveTestBench(firFiles, createAllCompilerResolveProcessors(session), gc = false)
|
||||
}
|
||||
checkResultingFirFiles(testDataFile)
|
||||
}
|
||||
|
||||
private fun checkResultingFirFiles(testDataFile: File) {
|
||||
val ourFinders = PsiElementFinder.EP.getPoint(project).extensions.filterIsInstance<FirJavaElementFinder>()
|
||||
|
||||
assertNotEmpty(ourFinders)
|
||||
@@ -52,4 +187,73 @@ abstract class AbstractFirOldFrontendLightClassesTest : AbstractFirOldFrontendDi
|
||||
override fun createTestFileFromPath(filePath: String): File {
|
||||
return File(filePath)
|
||||
}
|
||||
|
||||
private fun createModules(groupedByModule: Map<TestModule?, List<TestFile>>): MutableMap<TestModule?, ModuleInfo> {
|
||||
val modules =
|
||||
HashMap<TestModule?, ModuleInfo>()
|
||||
|
||||
for (testModule in groupedByModule.keys) {
|
||||
val module = if (testModule == null)
|
||||
createSealedModule()
|
||||
else
|
||||
createModule(testModule.name)
|
||||
|
||||
modules[testModule] = module
|
||||
}
|
||||
|
||||
for (testModule in groupedByModule.keys) {
|
||||
if (testModule == null) continue
|
||||
|
||||
val module = modules[testModule]!!
|
||||
val dependencies = ArrayList<ModuleInfo>()
|
||||
dependencies.add(module)
|
||||
for (dependency in testModule.dependencies) {
|
||||
dependencies.add(modules[dependency as TestModule?]!!)
|
||||
}
|
||||
|
||||
|
||||
dependencies.add(builtInsModuleInfo)
|
||||
(module as TestModuleInfo).dependencies.addAll(dependencies)
|
||||
}
|
||||
|
||||
return modules
|
||||
}
|
||||
|
||||
private val builtInsModuleInfo = BuiltInModuleInfo(Name.special("<built-ins>"))
|
||||
|
||||
private fun createModule(moduleName: String): TestModuleInfo {
|
||||
parseModulePlatformByName(moduleName)
|
||||
return TestModuleInfo(Name.special("<$moduleName>"))
|
||||
}
|
||||
|
||||
private class BuiltInModuleInfo(override val name: Name) : ModuleInfo {
|
||||
override val platform: TargetPlatform
|
||||
get() = JvmPlatforms.unspecifiedJvmPlatform
|
||||
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices
|
||||
get() = JvmPlatformAnalyzerServices
|
||||
|
||||
override fun dependencies(): List<ModuleInfo> {
|
||||
return listOf(this)
|
||||
}
|
||||
}
|
||||
|
||||
private class TestModuleInfo(override val name: Name) : ModuleInfo {
|
||||
override val platform: TargetPlatform
|
||||
get() = JvmPlatforms.unspecifiedJvmPlatform
|
||||
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices
|
||||
get() = JvmPlatformAnalyzerServices
|
||||
|
||||
val dependencies = mutableListOf<ModuleInfo>(this)
|
||||
override fun dependencies(): List<ModuleInfo> {
|
||||
return dependencies
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSealedModule(): TestModuleInfo {
|
||||
return createModule("test-module-jvm").apply {
|
||||
dependencies += builtInsModuleInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-355
@@ -1,355 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.fir
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementFinder
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.KtInMemoryTextSourceFile
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
import org.jetbrains.kotlin.checkers.BaseDiagnosticsTest
|
||||
import org.jetbrains.kotlin.checkers.DiagnosticDiffCallbacks
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.ActualDiagnostic
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.PositionalTextDiagnostic
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.SyntaxErrorDiagnostic
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.TextDiagnostic
|
||||
import org.jetbrains.kotlin.checkers.utils.CheckerTestUtil
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.PsiBasedProjectFileSearchScope
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.VfsBasedProjectEnvironment
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
|
||||
import org.jetbrains.kotlin.fir.builder.BodyBuildingMode
|
||||
import org.jetbrains.kotlin.fir.builder.PsiRawFirBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.session.FirSessionFactoryHelper
|
||||
import org.jetbrains.kotlin.fir.session.FirSessionConfigurator
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils
|
||||
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
|
||||
import org.jetbrains.kotlin.toSourceLinesMapping
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractFirBaseDiagnosticsTest : BaseDiagnosticsTest() {
|
||||
override fun analyzeAndCheck(testDataFile: File, files: List<TestFile>) {
|
||||
try {
|
||||
analyzeAndCheckUnhandled(testDataFile, files, useLightTree)
|
||||
} catch (t: AssertionError) {
|
||||
throw t
|
||||
} catch (t: Throwable) {
|
||||
throw t
|
||||
}
|
||||
}
|
||||
|
||||
protected open val useLightTree: Boolean
|
||||
get() = false
|
||||
|
||||
protected open val useLazyBodiesModeForRawFir: Boolean
|
||||
get() = false
|
||||
|
||||
override fun setupEnvironment(environment: KotlinCoreEnvironment) {
|
||||
PsiElementFinder.EP.getPoint(environment.project).unregisterExtension(JavaElementFinder::class.java)
|
||||
}
|
||||
|
||||
open fun analyzeAndCheckUnhandled(testDataFile: File, files: List<TestFile>, useLightTree: Boolean = false) {
|
||||
val groupedByModule = files.groupBy(TestFile::module)
|
||||
|
||||
val modules = createModules(groupedByModule)
|
||||
|
||||
val sessionProvider = FirProjectSessionProvider()
|
||||
|
||||
//For BuiltIns, registered in sessionProvider automatically
|
||||
val allProjectScope = GlobalSearchScope.allScope(project)
|
||||
|
||||
val configToSession = modules.mapValues { (config, info) ->
|
||||
val moduleFiles = groupedByModule.getValue(config)
|
||||
val scope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(
|
||||
project,
|
||||
moduleFiles.mapNotNull { it.ktFile })
|
||||
FirSessionFactoryHelper.createSessionWithDependencies(
|
||||
Name.identifier(info.name.asString().removeSurrounding("<", ">")),
|
||||
info.platform,
|
||||
info.analyzerServices,
|
||||
externalSessionProvider = sessionProvider,
|
||||
VfsBasedProjectEnvironment(
|
||||
project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL),
|
||||
{ environment.createPackagePartProvider(it) }
|
||||
),
|
||||
config?.languageVersionSettings ?: LanguageVersionSettingsImpl.DEFAULT,
|
||||
javaSourcesScope = PsiBasedProjectFileSearchScope(scope),
|
||||
librariesScope = PsiBasedProjectFileSearchScope(allProjectScope),
|
||||
lookupTracker = null,
|
||||
enumWhenTracker = null,
|
||||
importTracker = null,
|
||||
incrementalCompilationContext = null,
|
||||
extensionRegistrars = emptyList(),
|
||||
needRegisterJavaElementFinder = true
|
||||
) {
|
||||
configureSession()
|
||||
}
|
||||
}
|
||||
|
||||
val firFilesPerSession = mutableMapOf<FirSession, List<FirFile>>()
|
||||
|
||||
// TODO: make module/session/transformer handling like in AbstractFirMultiModuleTest (IDE)
|
||||
for ((testModule, testFilesInModule) in groupedByModule) {
|
||||
val ktFiles = getKtFiles(testFilesInModule, true)
|
||||
|
||||
val session = configToSession.getValue(testModule)
|
||||
|
||||
val firFiles = mutableListOf<FirFile>()
|
||||
mapKtFilesToFirFiles(session, ktFiles, firFiles, useLightTree)
|
||||
firFilesPerSession[session] = firFiles
|
||||
}
|
||||
|
||||
runAnalysis(testDataFile, files, firFilesPerSession)
|
||||
}
|
||||
|
||||
private fun mapKtFilesToFirFiles(session: FirSession, ktFiles: List<KtFile>, firFiles: MutableList<FirFile>, useLightTree: Boolean) {
|
||||
val firProvider = (session.firProvider as FirProviderImpl)
|
||||
if (useLightTree) {
|
||||
val lightTreeBuilder = LightTree2Fir(session, firProvider.kotlinScopeProvider)
|
||||
ktFiles.mapTo(firFiles) {
|
||||
val firFile =
|
||||
lightTreeBuilder.buildFirFile(
|
||||
it.text,
|
||||
KtInMemoryTextSourceFile(it.name, it.virtualFilePath, it.text),
|
||||
it.text.toSourceLinesMapping()
|
||||
)
|
||||
(session.firProvider as FirProviderImpl).recordFile(firFile)
|
||||
firFile
|
||||
}
|
||||
} else {
|
||||
val firBuilder = PsiRawFirBuilder(
|
||||
session,
|
||||
firProvider.kotlinScopeProvider,
|
||||
bodyBuildingMode = BodyBuildingMode.lazyBodies(useLazyBodiesModeForRawFir)
|
||||
)
|
||||
ktFiles.mapTo(firFiles) {
|
||||
val firFile = firBuilder.buildFirFile(it)
|
||||
firProvider.recordFile(firFile)
|
||||
firFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun runAnalysis(testDataFile: File, testFiles: List<TestFile>, firFilesPerSession: Map<FirSession, List<FirFile>>)
|
||||
|
||||
private fun createModules(
|
||||
groupedByModule: Map<TestModule?, List<TestFile>>
|
||||
): MutableMap<TestModule?, ModuleInfo> {
|
||||
val modules =
|
||||
HashMap<TestModule?, ModuleInfo>()
|
||||
|
||||
for (testModule in groupedByModule.keys) {
|
||||
val module = if (testModule == null)
|
||||
createSealedModule()
|
||||
else
|
||||
createModule(testModule.name)
|
||||
|
||||
modules[testModule] = module
|
||||
}
|
||||
|
||||
for (testModule in groupedByModule.keys) {
|
||||
if (testModule == null) continue
|
||||
|
||||
val module = modules[testModule]!!
|
||||
val dependencies = ArrayList<ModuleInfo>()
|
||||
dependencies.add(module)
|
||||
for (dependency in testModule.dependencies) {
|
||||
dependencies.add(modules[dependency as TestModule?]!!)
|
||||
}
|
||||
|
||||
|
||||
dependencies.add(builtInsModuleInfo)
|
||||
//dependencies.addAll(getAdditionalDependencies(module))
|
||||
(module as TestModuleInfo).dependencies.addAll(dependencies)
|
||||
}
|
||||
|
||||
return modules
|
||||
}
|
||||
|
||||
private val builtInsModuleInfo = BuiltInModuleInfo(Name.special("<built-ins>"))
|
||||
|
||||
protected open fun createModule(moduleName: String): TestModuleInfo {
|
||||
parseModulePlatformByName(moduleName)
|
||||
return TestModuleInfo(Name.special("<$moduleName>"))
|
||||
}
|
||||
|
||||
class BuiltInModuleInfo(override val name: Name) :
|
||||
ModuleInfo {
|
||||
override val platform: TargetPlatform
|
||||
get() = JvmPlatforms.unspecifiedJvmPlatform
|
||||
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices
|
||||
get() = JvmPlatformAnalyzerServices
|
||||
|
||||
override fun dependencies(): List<ModuleInfo> {
|
||||
return listOf(this)
|
||||
}
|
||||
}
|
||||
|
||||
protected class TestModuleInfo(override val name: Name) :
|
||||
ModuleInfo {
|
||||
override val platform: TargetPlatform
|
||||
get() = JvmPlatforms.unspecifiedJvmPlatform
|
||||
|
||||
override val analyzerServices: PlatformDependentAnalyzerServices
|
||||
get() = JvmPlatformAnalyzerServices
|
||||
|
||||
val dependencies = mutableListOf<ModuleInfo>(this)
|
||||
override fun dependencies(): List<ModuleInfo> {
|
||||
return dependencies
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun createSealedModule(): TestModuleInfo =
|
||||
createModule("test-module-jvm").apply {
|
||||
dependencies += builtInsModuleInfo
|
||||
}
|
||||
|
||||
protected fun TestFile.getActualText(
|
||||
ktDiagnostics: Iterable<KtDiagnostic>,
|
||||
actualText: StringBuilder
|
||||
): Boolean {
|
||||
val ktFile = this.ktFile
|
||||
if (ktFile == null) {
|
||||
// TODO: check java files too
|
||||
actualText.append(this.clearText)
|
||||
return true
|
||||
}
|
||||
|
||||
if (ktFile.name.endsWith("CoroutineUtil.kt") && ktFile.packageFqName == FqName("helpers")) return true
|
||||
|
||||
// TODO: report JVM signature diagnostics also for implementing modules
|
||||
|
||||
val ok = booleanArrayOf(true)
|
||||
val diagnostics = ktDiagnostics.toActualDiagnostic(ktFile)
|
||||
val filteredDiagnostics = diagnostics // TODO
|
||||
|
||||
actualDiagnostics.addAll(filteredDiagnostics)
|
||||
|
||||
val uncheckedDiagnostics = mutableListOf<PositionalTextDiagnostic>()
|
||||
|
||||
val diagnosticToExpectedDiagnostic =
|
||||
CheckerTestUtil.diagnosticsDiff(
|
||||
diagnosedRanges,
|
||||
filteredDiagnostics,
|
||||
object : DiagnosticDiffCallbacks {
|
||||
override fun missingDiagnostic(
|
||||
diagnostic: TextDiagnostic,
|
||||
expectedStart: Int,
|
||||
expectedEnd: Int
|
||||
) {
|
||||
val message =
|
||||
"Missing " + diagnostic.description + PsiDiagnosticUtils.atLocation(
|
||||
ktFile,
|
||||
TextRange(
|
||||
expectedStart,
|
||||
expectedEnd
|
||||
)
|
||||
)
|
||||
System.err.println(message)
|
||||
ok[0] = false
|
||||
}
|
||||
|
||||
override fun wrongParametersDiagnostic(
|
||||
expectedDiagnostic: TextDiagnostic,
|
||||
actualDiagnostic: TextDiagnostic,
|
||||
start: Int,
|
||||
end: Int
|
||||
) {
|
||||
val message = "Parameters of diagnostic not equal at position " +
|
||||
PsiDiagnosticUtils.atLocation(
|
||||
ktFile,
|
||||
TextRange(
|
||||
start,
|
||||
end
|
||||
)
|
||||
) +
|
||||
". Expected: ${expectedDiagnostic.asString()}, actual: $actualDiagnostic"
|
||||
System.err.println(message)
|
||||
ok[0] = false
|
||||
}
|
||||
|
||||
override fun unexpectedDiagnostic(
|
||||
diagnostic: TextDiagnostic,
|
||||
actualStart: Int,
|
||||
actualEnd: Int
|
||||
) {
|
||||
val message =
|
||||
"Unexpected ${diagnostic.description}${PsiDiagnosticUtils.atLocation(
|
||||
ktFile,
|
||||
TextRange(
|
||||
actualStart,
|
||||
actualEnd
|
||||
)
|
||||
)}"
|
||||
System.err.println(message)
|
||||
ok[0] = false
|
||||
}
|
||||
|
||||
fun updateUncheckedDiagnostics(
|
||||
diagnostic: TextDiagnostic,
|
||||
start: Int,
|
||||
end: Int
|
||||
) {
|
||||
uncheckedDiagnostics.add(
|
||||
PositionalTextDiagnostic(
|
||||
diagnostic,
|
||||
start,
|
||||
end
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
actualText.append(
|
||||
CheckerTestUtil.addDiagnosticMarkersToText(
|
||||
ktFile,
|
||||
filteredDiagnostics,
|
||||
diagnosticToExpectedDiagnostic,
|
||||
{ file -> file.text },
|
||||
uncheckedDiagnostics,
|
||||
false,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
stripExtras(actualText)
|
||||
|
||||
return ok[0]
|
||||
}
|
||||
|
||||
private fun Iterable<KtDiagnostic>.toActualDiagnostic(root: PsiElement): List<ActualDiagnostic> {
|
||||
val result = mutableListOf<ActualDiagnostic>()
|
||||
filterIsInstance<Diagnostic>().mapTo(result) {
|
||||
ActualDiagnostic(it, null, true)
|
||||
}
|
||||
for (errorElement in AnalyzingUtils.getSyntaxErrorRanges(root)) {
|
||||
result.add(ActualDiagnostic(SyntaxErrorDiagnostic(errorElement), null, true))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
protected open fun FirSessionConfigurator.configureSession() {}
|
||||
}
|
||||
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.fir
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1
|
||||
import org.jetbrains.kotlin.checkers.utils.TypeOfCall
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.FirDiagnosticsCollector
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.renderer.FirRenderer
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.FirControlFlowGraphRenderVisitor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.createAllCompilerResolveProcessors
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeOrNull
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.util.JUnit4Assertions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.File
|
||||
|
||||
/*
|
||||
* For comfort viewing dumps of control flow graph you can setup external tool in IDEA that opens .dot files
|
||||
*
|
||||
* Example of config for `xdot` viewer:
|
||||
*
|
||||
* File -> Settings -> External tools -> Add
|
||||
*
|
||||
* Name: XDot
|
||||
* Program: xdot
|
||||
* Arguments: $FileNameWithoutExtension$.dot
|
||||
* Working directory: $FileDir$
|
||||
* Disable "Open console for tool output"
|
||||
*
|
||||
* After that you can run action `XDot` in editor with source of test (or with cfg dump)
|
||||
* and it will opens xdot with dump for that test
|
||||
*/
|
||||
@OptIn(SymbolInternals::class)
|
||||
abstract class AbstractKtDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
|
||||
companion object {
|
||||
const val DUMP_CFG_DIRECTIVE = "DUMP_CFG"
|
||||
|
||||
private val allowedKindsForDebugInfo = setOf(
|
||||
KtRealSourceElementKind,
|
||||
KtFakeSourceElementKind.DesugaredCompoundAssignment,
|
||||
)
|
||||
|
||||
val TestFile.withDumpCfgDirective: Boolean
|
||||
get() = DUMP_CFG_DIRECTIVE in directives
|
||||
|
||||
val File.cfgDumpFile: File
|
||||
get() = File(absolutePath.replace(".kt", ".dot"))
|
||||
}
|
||||
|
||||
override fun runAnalysis(testDataFile: File, testFiles: List<TestFile>, firFilesPerSession: Map<FirSession, List<FirFile>>) {
|
||||
for ((session, firFiles) in firFilesPerSession) {
|
||||
doFirResolveTestBench(
|
||||
firFiles,
|
||||
createAllCompilerResolveProcessors(session),
|
||||
gc = false
|
||||
)
|
||||
}
|
||||
val allFirFiles = firFilesPerSession.values.flatten()
|
||||
checkDiagnostics(testDataFile, testFiles, allFirFiles)
|
||||
checkFir(testDataFile, allFirFiles)
|
||||
checkCfg(allFirFiles, testFiles, testDataFile)
|
||||
}
|
||||
|
||||
protected fun checkCfg(
|
||||
allFirFiles: List<FirFile>,
|
||||
testFiles: List<TestFile>,
|
||||
testDataFile: File
|
||||
) {
|
||||
checkCfgEdgeConsistency(allFirFiles)
|
||||
if (testFiles.any { it.withDumpCfgDirective }) {
|
||||
checkCfgDump(testDataFile, allFirFiles)
|
||||
} else {
|
||||
checkCfgDumpNotExists(testDataFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkFir(testDataFile: File, firFiles: List<FirFile>) {
|
||||
val renderer = FirRenderer()
|
||||
firFiles.forEach { renderer.renderElementAsString(it) }
|
||||
val firFileDump = renderer.toString()
|
||||
val expectedPath = testDataFile.absolutePath.replace(".kt", ".txt")
|
||||
KotlinTestUtils.assertEqualsToFile(
|
||||
File(expectedPath),
|
||||
firFileDump
|
||||
)
|
||||
}
|
||||
|
||||
protected open fun checkDiagnostics(file: File, testFiles: List<TestFile>, firFiles: List<FirFile>) {
|
||||
val diagnostics = collectDiagnostics(firFiles)
|
||||
val actualTextBuilder = StringBuilder()
|
||||
for (testFile in testFiles) {
|
||||
val firFile = firFiles.firstOrNull { it.psi == testFile.ktFile }
|
||||
if (firFile != null) {
|
||||
val debugInfoDiagnostics: List<KtDiagnostic> =
|
||||
collectDebugInfoDiagnostics(firFile, testFile.diagnosedRangesToDiagnosticNames)
|
||||
testFile.getActualText(
|
||||
diagnostics.getValue(firFile) + debugInfoDiagnostics,
|
||||
actualTextBuilder,
|
||||
)
|
||||
} else {
|
||||
actualTextBuilder.append(testFile.expectedText)
|
||||
}
|
||||
}
|
||||
val actualText = actualTextBuilder.toString()
|
||||
KotlinTestUtils.assertEqualsToFile(file, actualText)
|
||||
}
|
||||
|
||||
private fun collectDebugInfoDiagnostics(
|
||||
firFile: FirFile,
|
||||
diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>
|
||||
): List<KtDiagnostic> {
|
||||
val result = mutableListOf<KtDiagnostic>()
|
||||
|
||||
|
||||
object : FirDefaultVisitorVoid() {
|
||||
override fun visitElement(element: FirElement) {
|
||||
if (element is FirExpression) {
|
||||
result.addIfNotNull(
|
||||
createExpressionTypeDiagnosticIfExpected(
|
||||
element, diagnosedRangesToDiagnosticNames
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
|
||||
override fun visitFunctionCall(functionCall: FirFunctionCall) {
|
||||
val reference = functionCall.calleeReference
|
||||
result.addIfNotNull(createCallDiagnosticIfExpected(functionCall, reference, diagnosedRangesToDiagnosticNames))
|
||||
result.addIfNotNull(createDerivedClassDiagnosticIfExpected(functionCall, reference, diagnosedRangesToDiagnosticNames))
|
||||
|
||||
super.visitFunctionCall(functionCall)
|
||||
}
|
||||
|
||||
override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall) {
|
||||
val reference = delegatedConstructorCall.calleeReference as FirNamedReference
|
||||
result.addIfNotNull(
|
||||
createDerivedClassDiagnosticIfExpected(delegatedConstructorCall, reference, diagnosedRangesToDiagnosticNames))
|
||||
|
||||
super.visitDelegatedConstructorCall(delegatedConstructorCall)
|
||||
}
|
||||
|
||||
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression) {
|
||||
val reference = propertyAccessExpression.calleeReference as FirNamedReference
|
||||
result.addIfNotNull(
|
||||
createDerivedClassDiagnosticIfExpected(propertyAccessExpression, reference, diagnosedRangesToDiagnosticNames))
|
||||
}
|
||||
}.let(firFile::accept)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun createExpressionTypeDiagnosticIfExpected(
|
||||
element: FirExpression,
|
||||
diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>
|
||||
): KtDiagnosticWithParameters1<String>? =
|
||||
DebugInfoDiagnosticFactory1.EXPRESSION_TYPE.createDebugInfoDiagnostic(element, diagnosedRangesToDiagnosticNames) {
|
||||
element.coneTypeOrNull.renderAsString((element as? FirSmartCastExpression)?.originalExpression?.coneTypeOrNull)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType?.renderAsString(originalType: ConeKotlinType?): String {
|
||||
val type = this ?: return "Type is unknown"
|
||||
val rendered = type.renderForDebugInfo()
|
||||
val originalTypeRendered = originalType?.renderForDebugInfo() ?: return rendered
|
||||
|
||||
return "$rendered & $originalTypeRendered"
|
||||
}
|
||||
|
||||
private fun createCallDiagnosticIfExpected(
|
||||
element: FirElement,
|
||||
reference: FirNamedReference,
|
||||
diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>
|
||||
): KtDiagnostic? {
|
||||
return DebugInfoDiagnosticFactory1.CALL.createDebugInfoDiagnostic(element, diagnosedRangesToDiagnosticNames) {
|
||||
val resolvedSymbol = (reference as? FirResolvedNamedReference)?.resolvedSymbol
|
||||
val fqName = resolvedSymbol?.fqNameUnsafe()
|
||||
Renderers.renderCallInfo(fqName, getTypeOfCall(reference, resolvedSymbol))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDerivedClassDiagnosticIfExpected(
|
||||
element: FirElement,
|
||||
reference: FirNamedReference,
|
||||
diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>
|
||||
): KtDiagnostic? {
|
||||
return DebugInfoDiagnosticFactory1.CALLABLE_OWNER.createDebugInfoDiagnostic(element, diagnosedRangesToDiagnosticNames) {
|
||||
val resolvedSymbol = (reference as? FirResolvedNamedReference)?.resolvedSymbol
|
||||
val callable = resolvedSymbol?.fir as? FirCallableDeclaration ?: return@createDebugInfoDiagnostic ""
|
||||
DebugInfoDiagnosticFactory1.renderCallableOwner(
|
||||
callable.symbol.callableId,
|
||||
callable.containingClassLookupTag()?.classId,
|
||||
callable.containingClassForStaticMemberAttr == null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DebugInfoDiagnosticFactory1.createDebugInfoDiagnostic(
|
||||
element: FirElement,
|
||||
diagnosedRangesToDiagnosticNames: MutableMap<IntRange, MutableSet<String>>,
|
||||
argument: () -> String,
|
||||
): KtDiagnosticWithParameters1<String>? {
|
||||
val sourceElement = element.source ?: return null
|
||||
val sourceKind = sourceElement.kind
|
||||
if (sourceKind !in allowedKindsForDebugInfo) {
|
||||
if (sourceKind !is KtFakeSourceElementKind.ImplicitReturn || sourceElement.elementType != KtNodeTypes.RETURN) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
// Lambda argument is always (?) duplicated by function literal
|
||||
// Block expression is always (?) duplicated by single block expression
|
||||
if (sourceElement.elementType == KtNodeTypes.LAMBDA_ARGUMENT || sourceElement.elementType == KtNodeTypes.BLOCK) return null
|
||||
val name = name
|
||||
if (diagnosedRangesToDiagnosticNames[sourceElement.startOffset..sourceElement.endOffset]?.contains(name) != true) return null
|
||||
|
||||
val argumentText = argument()
|
||||
return when (sourceElement) {
|
||||
is KtPsiSourceElement -> KtPsiDiagnosticWithParameters1(
|
||||
sourceElement,
|
||||
argumentText,
|
||||
severity,
|
||||
KtDiagnosticFactory1(name, severity, AbstractSourceElementPositioningStrategy.DEFAULT, PsiElement::class),
|
||||
AbstractSourceElementPositioningStrategy.DEFAULT
|
||||
)
|
||||
is KtLightSourceElement -> KtLightDiagnosticWithParameters1(
|
||||
sourceElement,
|
||||
argumentText,
|
||||
severity,
|
||||
KtDiagnosticFactory1(name, severity, AbstractSourceElementPositioningStrategy.DEFAULT, PsiElement::class),
|
||||
AbstractSourceElementPositioningStrategy.DEFAULT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirBasedSymbol<*>.fqNameUnsafe(): FqNameUnsafe? = when (this) {
|
||||
is FirClassLikeSymbol<*> -> classId.asSingleFqName().toUnsafe()
|
||||
is FirCallableSymbol<*> -> callableId.asFqNameForDebugInfo().toUnsafe()
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun getTypeOfCall(
|
||||
reference: FirNamedReference,
|
||||
resolvedSymbol: FirBasedSymbol<*>?
|
||||
): String {
|
||||
if (resolvedSymbol == null) return TypeOfCall.UNRESOLVED.nameToRender
|
||||
|
||||
if ((resolvedSymbol as? FirFunctionSymbol)?.callableId?.callableName == OperatorNameConventions.INVOKE
|
||||
&& reference.name != OperatorNameConventions.INVOKE
|
||||
) {
|
||||
return TypeOfCall.VARIABLE_THROUGH_INVOKE.nameToRender
|
||||
}
|
||||
|
||||
return when (val fir = resolvedSymbol.fir) {
|
||||
is FirProperty -> {
|
||||
TypeOfCall.PROPERTY_GETTER.nameToRender
|
||||
}
|
||||
is FirFunction -> buildString {
|
||||
if (fir.status.isInline) append("inline ")
|
||||
if (fir.status.isInfix) append("infix ")
|
||||
if (fir.status.isOperator) append("operator ")
|
||||
if (fir.receiverParameter != null) append("extension ")
|
||||
append(TypeOfCall.FUNCTION.nameToRender)
|
||||
}
|
||||
else -> TypeOfCall.OTHER.nameToRender
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected fun collectDiagnostics(firFiles: List<FirFile>): Map<FirFile, List<KtDiagnostic>> {
|
||||
val collectors = mutableMapOf<FirSession, AbstractDiagnosticCollector>()
|
||||
val result = mutableMapOf<FirFile, List<KtDiagnostic>>()
|
||||
for (firFile in firFiles) {
|
||||
val session = firFile.moduleData.session
|
||||
val collector = collectors.computeIfAbsent(session) { createCollector(session) }
|
||||
val reporter = DiagnosticReporterFactory.createPendingReporter()
|
||||
collector.collectDiagnostics(firFile, reporter)
|
||||
result[firFile] = reporter.diagnostics
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun createCollector(session: FirSession): AbstractDiagnosticCollector {
|
||||
return FirDiagnosticsCollector.create(
|
||||
session,
|
||||
ScopeSession()
|
||||
) // seems this class is obsolete, so do not care about correctness of the scope session here
|
||||
}
|
||||
|
||||
private fun checkCfgDump(testDataFile: File, firFiles: List<FirFile>) {
|
||||
val builder = StringBuilder()
|
||||
|
||||
firFiles.first().accept(FirControlFlowGraphRenderVisitor(builder), null)
|
||||
|
||||
val dotCfgDump = builder.toString()
|
||||
KotlinTestUtils.assertEqualsToFile(testDataFile.cfgDumpFile, dotCfgDump)
|
||||
}
|
||||
|
||||
private fun checkCfgEdgeConsistency(firFiles: List<FirFile>) {
|
||||
firFiles.forEach { it.accept(FirCfgConsistencyChecker(JUnit4Assertions)) }
|
||||
}
|
||||
|
||||
private fun checkCfgDumpNotExists(testDataFile: File) {
|
||||
val cfgDumpFile = testDataFile.cfgDumpFile
|
||||
if (cfgDumpFile.exists()) {
|
||||
val message = """
|
||||
Directive `!$DUMP_CFG_DIRECTIVE` is missing, but file with cfg dump is present.
|
||||
Please remove ${cfgDumpFile.path} or add `!$DUMP_CFG_DIRECTIVE` to test
|
||||
""".trimIndent()
|
||||
kotlin.test.fail(message)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.createAllCompilerResolveProcessors
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractFirOldFrontendDiagnosticsTest : AbstractKtDiagnosticsTest() {
|
||||
override fun createTestFileFromPath(filePath: String): File {
|
||||
val newPath = if (File(filePath).readText().contains("// FIR_IDENTICAL")) filePath else filePath.replace(".kt", ".fir.kt")
|
||||
return File(newPath).also {
|
||||
prepareTestDataFile(filePath, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareTestDataFile(originalFilePath: String, firTestDataFile: File) {
|
||||
if (!firTestDataFile.exists()) {
|
||||
KotlinTestUtils.assertEqualsToFile(firTestDataFile, loadTestDataWithDiagnostics(File(originalFilePath)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun analyzeAndCheck(testDataFile: File, files: List<TestFile>) {
|
||||
if (files.any { "FIR_IGNORE" in it.directives }) return
|
||||
super.analyzeAndCheck(testDataFile, files)
|
||||
}
|
||||
|
||||
override fun runAnalysis(testDataFile: File, testFiles: List<TestFile>, firFilesPerSession: Map<FirSession, List<FirFile>>) {
|
||||
val failure: FirRuntimeException? = try {
|
||||
for ((session, firFiles) in firFilesPerSession) {
|
||||
doFirResolveTestBench(firFiles, createAllCompilerResolveProcessors(session), gc = false)
|
||||
}
|
||||
null
|
||||
} catch (e: FirRuntimeException) {
|
||||
e
|
||||
}
|
||||
val failureFile = File(testDataFile.path.replace(".kt", ".fail"))
|
||||
if (failure == null) {
|
||||
val allFirFiles = firFilesPerSession.values.flatten()
|
||||
checkResultingFirFiles(allFirFiles, testDataFile)
|
||||
assertFalse("Test is good but there is expected exception", failureFile.exists())
|
||||
checkDiagnostics(testDataFile, testFiles, allFirFiles)
|
||||
if (testDataFile.absolutePath.endsWith(".fir.kt")) {
|
||||
val oldFrontendTestDataFile = File(testDataFile.absolutePath.replace(".fir.kt", ".kt"))
|
||||
compareAndMergeFirFileAndOldFrontendFile(oldFrontendTestDataFile, testDataFile)
|
||||
}
|
||||
|
||||
val needDump = testFiles.any { "FIR_DUMP" in it.directives }
|
||||
if (needDump) {
|
||||
checkFir(testDataFile, allFirFiles)
|
||||
}
|
||||
checkCfg(allFirFiles, testFiles, testDataFile)
|
||||
} else {
|
||||
if (!failureFile.exists()) {
|
||||
throw failure
|
||||
}
|
||||
checkFailureFile(failure, failureFile)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFailureFile(failure: FirRuntimeException, failureFile: File) {
|
||||
val failureMessage = buildString {
|
||||
appendLine(failure.message)
|
||||
append("Cause: ")
|
||||
appendLine(failure.cause)
|
||||
}
|
||||
KotlinTestUtils.assertEqualsToFile(failureFile, failureMessage)
|
||||
}
|
||||
|
||||
protected open fun checkResultingFirFiles(firFiles: List<FirFile>, testDataFile: File) {}
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,10 +15,10 @@ import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.defaultConstructor.AbstractDefaultArgumentsReflectionTest
|
||||
import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest
|
||||
import org.jetbrains.kotlin.codegen.ir.*
|
||||
import org.jetbrains.kotlin.fir.java.AbstractFirOldFrontendLightClassesTest
|
||||
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderLazyBodiesTestCase
|
||||
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderSourceElementMappingTestCase
|
||||
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
||||
import org.jetbrains.kotlin.fir.java.AbstractFirOldFrontendLightClassesTest
|
||||
import org.jetbrains.kotlin.fir.java.AbstractFirTypeEnhancementTest
|
||||
import org.jetbrains.kotlin.fir.java.AbstractOwnFirTypeEnhancementTest
|
||||
import org.jetbrains.kotlin.fir.lightTree.AbstractLightTree2FirConverterTestCase
|
||||
|
||||
Reference in New Issue
Block a user