FIR IDE: introduce diagnostics tests bases on FIR diagnostics tests

This commit is contained in:
Ilya Kirillov
2021-04-03 15:24:12 +02:00
parent 0c77565104
commit 65ce641b22
17 changed files with 36644 additions and 149 deletions
@@ -354,8 +354,8 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
extractor.provideConfigurationKeys()
extractor.configure(keyConfiguration, module.directives)
}
val kind = configuratorForFlags.extractConfigurationKind(module.directives)
val jdkKind = configuratorForFlags.extractJdkKind(module.directives)
val kind = JvmEnvironmentConfigurator.extractConfigurationKind(module.directives)
val jdkKind = JvmEnvironmentConfigurator.extractJdkKind(module.directives)
keyConfiguration.languageVersionSettings = module.languageVersionSettings
@@ -29,16 +29,25 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import java.io.File
abstract class AbstractFirAnalyzerFacade {
abstract val scopeSession: ScopeSession
abstract fun runCheckers(): Map<FirFile, List<FirDiagnostic<*>>>
abstract fun runResolution(): List<FirFile>
abstract fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult
}
class FirAnalyzerFacade(
val session: FirSession,
val languageVersionSettings: LanguageVersionSettings,
val ktFiles: Collection<KtFile> = emptyList(), // may be empty if light tree mode enabled
val originalFiles: Collection<File> = emptyList(), // may be empty if light tree mode disabled
val useLightTree: Boolean = false
) {
) : AbstractFirAnalyzerFacade() {
private var firFiles: List<FirFile>? = null
private var _scopeSession: ScopeSession? = null
val scopeSession: ScopeSession
override val scopeSession: ScopeSession
get() = _scopeSession!!
private var collectedDiagnostics: Map<FirFile, List<FirDiagnostic<*>>>? = null
@@ -63,7 +72,7 @@ class FirAnalyzerFacade(
}
}
fun runResolution(): List<FirFile> {
override fun runResolution(): List<FirFile> {
if (firFiles == null) buildRawFir()
if (_scopeSession != null) return firFiles!!
val resolveProcessor = FirTotalResolveProcessor(session)
@@ -73,7 +82,7 @@ class FirAnalyzerFacade(
}
@OptIn(ExperimentalStdlibApi::class)
fun runCheckers(): Map<FirFile, List<FirDiagnostic<*>>> {
override fun runCheckers(): Map<FirFile, List<FirDiagnostic<*>>> {
if (_scopeSession == null) runResolution()
if (collectedDiagnostics != null) return collectedDiagnostics!!
val collector = FirDiagnosticsCollector.create(session, scopeSession)
@@ -87,7 +96,7 @@ class FirAnalyzerFacade(
return collectedDiagnostics!!
}
fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult {
override fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult {
if (_scopeSession == null) runResolution()
val signaturer = JvmIdSignatureDescriptor(JvmManglerDesc())
@@ -78,7 +78,7 @@ class FirFrontendFacade(
testFile to firFile
}.toMap()
return FirOutputArtifact(session, filesMap, firAnalyzerFacade)
return FirOutputArtifactImpl(session, filesMap, firAnalyzerFacade)
}
private fun createSessionForBuiltins(
@@ -6,19 +6,27 @@
package org.jetbrains.kotlin.test.frontend.fir
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.AbstractFirAnalyzerFacade
import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.ResultingArtifact
import org.jetbrains.kotlin.test.model.TestFile
data class FirOutputArtifact(
val session: FirSession,
val allFirFiles: Map<TestFile, FirFile>,
val firAnalyzerFacade: FirAnalyzerFacade
) : ResultingArtifact.FrontendOutput<FirOutputArtifact>() {
abstract class FirOutputArtifact : ResultingArtifact.FrontendOutput<FirOutputArtifact>() {
abstract val session: FirSession
abstract val firAnalyzerFacade: AbstractFirAnalyzerFacade
abstract val allFirFiles: Map<TestFile, FirFile>
override val kind: FrontendKinds.FIR
get() = FrontendKinds.FIR
val firFiles: Map<TestFile, FirFile> = allFirFiles.filterKeys { !it.isAdditional }
val firFiles: Map<TestFile, FirFile> by lazy { allFirFiles.filterKeys { !it.isAdditional } }
}
data class FirOutputArtifactImpl(
override val session: FirSession,
override val allFirFiles: Map<TestFile, FirFile>,
override val firAnalyzerFacade: FirAnalyzerFacade
) : FirOutputArtifact()
@@ -28,75 +28,7 @@ import org.jetbrains.kotlin.test.services.fir.FirOldFrontendMetaConfigurator
abstract class AbstractFirDiagnosticTest : AbstractKotlinCompilerTest() {
override fun TestConfigurationBuilder.configuration() {
globalDefaults {
frontend = FrontendKinds.FIR
targetPlatform = JvmPlatforms.defaultJvmPlatform
dependencyKind = DependencyKind.Source
}
enableMetaInfoHandler()
useConfigurators(
::CommonEnvironmentConfigurator,
::JvmEnvironmentConfigurator,
)
useAdditionalSourceProviders(
::AdditionalDiagnosticsSourceFilesProvider,
::CoroutineHelpersSourceFilesProvider,
)
useFrontendFacades(::FirFrontendFacade)
useFrontendHandlers(
::FirDiagnosticsHandler,
::FirDumpHandler,
::FirCfgDumpHandler,
::FirCfgConsistencyHandler,
::FirNoImplicitTypesHandler,
)
useMetaInfoProcessors(::PsiLightTreeMetaInfoProcessor)
defaultDirectives {
+COMPARE_WITH_LIGHT_TREE
}
forTestsMatching("compiler/testData/diagnostics/*") {
useAfterAnalysisCheckers(
::FirIdenticalChecker,
::FirFailingTestSuppressor,
)
useMetaTestConfigurators(::FirOldFrontendMetaConfigurator)
}
forTestsMatching("compiler/fir/analysis-tests/testData/*") {
defaultDirectives {
+FIR_DUMP
}
}
forTestsMatching(
"compiler/testData/diagnostics/testsWithStdLib/*" or
"compiler/fir/analysis-tests/testData/resolveWithStdlib/*" or
"compiler/testData/diagnostics/tests/unsignedTypes/*"
) {
defaultDirectives {
+WITH_STDLIB
}
}
forTestsMatching("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/*") {
defaultDirectives {
+WITH_EXTENDED_CHECKERS
}
}
forTestsMatching("compiler/testData/diagnostics/tests/testsWithJava15/*") {
defaultDirectives {
JDK_KIND with TestJdkKind.FULL_JDK_15
+WITH_STDLIB
+WITH_REFLECT
}
}
baseFirDiagnosticTestConfiguration()
}
}
@@ -110,3 +42,76 @@ abstract class AbstractFirDiagnosticsWithLightTreeTest : AbstractFirDiagnosticTe
}
}
}
fun TestConfigurationBuilder.baseFirDiagnosticTestConfiguration() {
globalDefaults {
frontend = FrontendKinds.FIR
targetPlatform = JvmPlatforms.defaultJvmPlatform
dependencyKind = DependencyKind.Source
}
enableMetaInfoHandler()
useConfigurators(
::CommonEnvironmentConfigurator,
::JvmEnvironmentConfigurator,
)
useAdditionalSourceProviders(
::AdditionalDiagnosticsSourceFilesProvider,
::CoroutineHelpersSourceFilesProvider,
)
useFrontendFacades(::FirFrontendFacade)
useFrontendHandlers(
::FirDiagnosticsHandler,
::FirDumpHandler,
::FirCfgDumpHandler,
::FirCfgConsistencyHandler,
::FirNoImplicitTypesHandler,
)
useMetaInfoProcessors(::PsiLightTreeMetaInfoProcessor)
defaultDirectives {
+COMPARE_WITH_LIGHT_TREE
}
forTestsMatching("compiler/testData/diagnostics/*") {
useAfterAnalysisCheckers(
::FirIdenticalChecker,
::FirFailingTestSuppressor,
)
useMetaTestConfigurators(::FirOldFrontendMetaConfigurator)
}
forTestsMatching("compiler/fir/analysis-tests/testData/*") {
defaultDirectives {
+FIR_DUMP
}
}
forTestsMatching(
"compiler/testData/diagnostics/testsWithStdLib/*" or
"compiler/fir/analysis-tests/testData/resolveWithStdlib/*" or
"compiler/testData/diagnostics/tests/unsignedTypes/*"
) {
defaultDirectives {
+WITH_STDLIB
}
}
forTestsMatching("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/*") {
defaultDirectives {
+WITH_EXTENDED_CHECKERS
}
}
forTestsMatching("compiler/testData/diagnostics/tests/testsWithJava15/*") {
defaultDirectives {
JDK_KIND with TestJdkKind.FULL_JDK_15
+WITH_STDLIB
+WITH_REFLECT
}
}
}
@@ -34,23 +34,27 @@ abstract class AbstractKotlinCompilerTest {
val defaultPreprocessors: List<Constructor<SourceFilePreprocessor>> = listOf(
::MetaInfosCleanupPreprocessor
)
private fun configureDebugFlags() {
AbstractTypeChecker.RUN_SLOW_ASSERTIONS = true
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true
}
val defaultConfiguration: TestConfigurationBuilder.() -> Unit = {
useAdditionalService<TemporaryDirectoryManager>(::TemporaryDirectoryManagerImpl)
useAdditionalService<BackendKindExtractor>(::BackendKindExtractorImpl)
useSourcePreprocessor(*defaultPreprocessors.toTypedArray())
useDirectives(*defaultDirectiveContainers.toTypedArray())
configureDebugFlags()
}
}
private val configuration: TestConfigurationBuilder.() -> Unit = {
assertions = JUnit5Assertions
useAdditionalService<TemporaryDirectoryManager>(::TemporaryDirectoryManagerImpl)
useAdditionalService<BackendKindExtractor>(::BackendKindExtractorImpl)
useSourcePreprocessor(*defaultPreprocessors.toTypedArray())
useDirectives(*defaultDirectiveContainers.toTypedArray())
configureDebugFlags()
defaultConfiguration()
configure(this)
}
private fun configureDebugFlags() {
AbstractTypeChecker.RUN_SLOW_ASSERTIONS = true
FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true
}
abstract fun TestConfigurationBuilder.configuration()
private lateinit var testInfo: KotlinTestInfo
@@ -65,6 +65,61 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
private val DEFAULT_JVM_TARGET_FROM_PROPERTY: String? = System.getProperty("kotlin.test.default.jvm.target")
private const val JAVA_BINARIES_JAR_NAME = "java-binaries"
fun extractConfigurationKind(registeredDirectives: RegisteredDirectives): ConfigurationKind {
val withRuntime = JvmEnvironmentConfigurationDirectives.WITH_RUNTIME in registeredDirectives ||
JvmEnvironmentConfigurationDirectives.WITH_STDLIB in registeredDirectives
val withReflect = JvmEnvironmentConfigurationDirectives.WITH_REFLECT in registeredDirectives
val noRuntime = JvmEnvironmentConfigurationDirectives.NO_RUNTIME in registeredDirectives
if (noRuntime && withRuntime) {
error("NO_RUNTIME and WITH_RUNTIME can not be used together")
}
return when {
withRuntime && !withReflect -> ConfigurationKind.NO_KOTLIN_REFLECT
withRuntime || withReflect -> ConfigurationKind.ALL
noRuntime -> ConfigurationKind.JDK_NO_RUNTIME
else -> ConfigurationKind.JDK_ONLY
}
}
fun extractJdkKind(registeredDirectives: RegisteredDirectives): TestJdkKind {
val fullJdkEnabled = JvmEnvironmentConfigurationDirectives.FULL_JDK in registeredDirectives
val jdkKinds = registeredDirectives[JvmEnvironmentConfigurationDirectives.JDK_KIND]
if (fullJdkEnabled) {
if (jdkKinds.isNotEmpty()) {
error("FULL_JDK and JDK_KIND can not be used together")
}
return TestJdkKind.FULL_JDK
}
return when (jdkKinds.size) {
0 -> TestJdkKind.MOCK_JDK
1 -> jdkKinds.single()
else -> error("Too many jdk kinds passed: ${jdkKinds.joinToArrayString()}")
}
}
fun getLibraryFiles(configurationKind: ConfigurationKind, directives: RegisteredDirectives): List<File> {
val files = mutableListOf<File>()
if (configurationKind.withRuntime) {
files.add(ForTestCompileRuntime.runtimeJarForTests())
files.add(ForTestCompileRuntime.scriptRuntimeJarForTests())
files.add(ForTestCompileRuntime.kotlinTestJarForTests())
} else if (configurationKind.withMockRuntime) {
files.add(ForTestCompileRuntime.minimalRuntimeJarForTests())
files.add(ForTestCompileRuntime.scriptRuntimeJarForTests())
}
if (configurationKind.withReflection) {
files.add(ForTestCompileRuntime.reflectJarForTests())
}
files.add(KtTestUtil.getAnnotationsJar())
if (JvmEnvironmentConfigurationDirectives.STDLIB_JDK8 in directives) {
files.add(ForTestCompileRuntime.runtimeJarForTestsWithJdk8())
}
return files
}
}
override val directivesContainers: List<DirectivesContainer>
@@ -130,27 +185,8 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
configuration.put(TEST_CONFIGURATION_KIND_KEY, it)
}
val javaVersionToCompile = registeredDirectives[COMPILE_JAVA_USING].singleOrNull()
val javaBinaryFiles = if (ALL_JAVA_AS_BINARY !in registeredDirectives) {
module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY in it.directives }
} else module.javaFiles
configuration.addJvmClasspathRoots(getLibraryFiles(configurationKind, module.directives))
val useJava9ToCompileIncludedJavaFiles = javaVersionToCompile == TestJavacVersion.JAVAC_9
if (configurationKind.withRuntime) {
configuration.configureStandardLibs(PathUtil.kotlinPathsForDistDirectory, K2JVMCompilerArguments().also { it.noReflect = true })
configuration.addJvmClasspathRoot(ForTestCompileRuntime.kotlinTestJarForTests())
} else if (configurationKind.withMockRuntime) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.minimalRuntimeJarForTests())
configuration.addJvmClasspathRoot(ForTestCompileRuntime.scriptRuntimeJarForTests())
}
if (configurationKind.withReflection) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.reflectJarForTests())
}
if (JvmEnvironmentConfigurationDirectives.STDLIB_JDK8 in module.directives) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.runtimeJarForTestsWithJdk8())
}
configuration.addJvmClasspathRoot(KtTestUtil.getAnnotationsJar())
@@ -309,39 +345,6 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
}
}
fun extractJdkKind(registeredDirectives: RegisteredDirectives): TestJdkKind {
val fullJdkEnabled = JvmEnvironmentConfigurationDirectives.FULL_JDK in registeredDirectives
val jdkKinds = registeredDirectives[JvmEnvironmentConfigurationDirectives.JDK_KIND]
if (fullJdkEnabled) {
if (jdkKinds.isNotEmpty()) {
error("FULL_JDK and JDK_KIND can not be used together")
}
return TestJdkKind.FULL_JDK
}
return when (jdkKinds.size) {
0 -> TestJdkKind.MOCK_JDK
1 -> jdkKinds.single()
else -> error("Too many jdk kinds passed: ${jdkKinds.joinToArrayString()}")
}
}
fun extractConfigurationKind(registeredDirectives: RegisteredDirectives): ConfigurationKind {
val withRuntime = JvmEnvironmentConfigurationDirectives.WITH_RUNTIME in registeredDirectives ||
JvmEnvironmentConfigurationDirectives.WITH_STDLIB in registeredDirectives
val withReflect = JvmEnvironmentConfigurationDirectives.WITH_REFLECT in registeredDirectives
val noRuntime = JvmEnvironmentConfigurationDirectives.NO_RUNTIME in registeredDirectives
if (noRuntime && withRuntime) {
error("NO_RUNTIME and WITH_RUNTIME can not be used together")
}
return when {
withRuntime && !withReflect -> ConfigurationKind.NO_KOTLIN_REFLECT
withRuntime || withReflect -> ConfigurationKind.ALL
noRuntime -> ConfigurationKind.JDK_NO_RUNTIME
else -> ConfigurationKind.JDK_ONLY
}
}
private fun CompilerConfiguration.registerModuleDependencies(module: TestModule) {
val dependencyProvider = testServices.dependencyProvider