Modularized tests. Support parsing of original compiler arguments
Now testData contains info about original compiler arguments, which can be reused to support plugins and various other arguments Support original arguments in modularized tests - Properly support JDK9 modules - Opt-ins from original arguments - jdkHome from module data or arguments, as well as noJdk option - Fix friendPaths not configured - jvmDefault now handled properly ^KT-56075 ^KT-55879
This commit is contained in:
committed by
Space Team
parent
36c3d62ba1
commit
59e69481a3
+73
-11
@@ -5,34 +5,96 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractFrontendModularizedTest : AbstractModularizedTest() {
|
||||
fun createDefaultConfiguration(moduleData: ModuleData): CompilerConfiguration {
|
||||
|
||||
fun configureLanguageVersionSettings(
|
||||
configuration: CompilerConfiguration,
|
||||
moduleData: ModuleData,
|
||||
languageVersion: LanguageVersion,
|
||||
configureFlags: MutableMap<AnalysisFlag<*>, Any?>.() -> Unit = {},
|
||||
configureFeatures: MutableMap<LanguageFeature, LanguageFeature.State>.() -> Unit = {}
|
||||
) {
|
||||
val originalArguments = moduleData.arguments as? K2JVMCompilerArguments
|
||||
|
||||
configuration.languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
languageVersion,
|
||||
originalArguments?.apiVersion?.let { ApiVersion.parse(it) } ?: ApiVersion.LATEST_STABLE,
|
||||
analysisFlags = buildMap {
|
||||
put(AnalysisFlags.optIn, moduleData.optInAnnotations + originalArguments?.optIn.orEmpty())
|
||||
if (originalArguments != null) {
|
||||
put(AnalysisFlags.skipPrereleaseCheck, originalArguments.skipPrereleaseCheck)
|
||||
put(JvmAnalysisFlags.jvmDefaultMode, JvmDefaultMode.fromStringOrNull(originalArguments.jvmDefault))
|
||||
}
|
||||
|
||||
configureFlags()
|
||||
},
|
||||
specificFeatures = buildMap {
|
||||
configureFeatures()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun createDefaultConfiguration(
|
||||
moduleData: ModuleData
|
||||
): CompilerConfiguration {
|
||||
val configuration = KotlinTestUtils.newConfiguration()
|
||||
val originalArguments = moduleData.arguments as? K2JVMCompilerArguments
|
||||
|
||||
moduleData.javaSourceRoots.forEach {
|
||||
configuration.addJavaSourceRoot(it.path, it.packagePrefix)
|
||||
}
|
||||
configuration.addJvmClasspathRoots(moduleData.classpath)
|
||||
configuration.languageVersionSettings = LanguageVersionSettingsImpl(
|
||||
LanguageVersion.LATEST_STABLE,
|
||||
ApiVersion.LATEST_STABLE,
|
||||
analysisFlags = mutableMapOf(AnalysisFlags.optIn to moduleData.optInAnnotations)
|
||||
)
|
||||
configuration.configureJdkClasspathRoots()
|
||||
|
||||
// in case of modular jdk only
|
||||
configuration.putIfNotNull(JVMConfigurationKeys.JDK_HOME, moduleData.modularJdkRoot)
|
||||
val isJava9Module = moduleData.javaSourceRoots.any { (file, packagePrefix) ->
|
||||
packagePrefix == null &&
|
||||
(file.name == PsiJavaModule.MODULE_INFO_FILE ||
|
||||
(file.isDirectory && file.listFiles()!!.any { it.name == PsiJavaModule.MODULE_INFO_FILE }))
|
||||
}
|
||||
|
||||
for (rootPath in moduleData.classpath) {
|
||||
if (isJava9Module) {
|
||||
configuration.add(CLIConfigurationKeys.CONTENT_ROOTS, JvmModulePathRoot(rootPath))
|
||||
}
|
||||
configuration.add(CLIConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(rootPath))
|
||||
}
|
||||
|
||||
val jdkHome =
|
||||
moduleData.modularJdkRoot
|
||||
?: moduleData.jdkHome?.absoluteFile
|
||||
?: originalArguments?.jdkHome?.fixPath()?.absoluteFile
|
||||
|
||||
if (originalArguments != null) {
|
||||
configuration.put(JVMConfigurationKeys.NO_JDK, originalArguments.noJdk)
|
||||
|
||||
for (modularRoot in originalArguments.javaModulePath?.split(File.pathSeparatorChar).orEmpty()) {
|
||||
configuration.add(CLIConfigurationKeys.CONTENT_ROOTS, JvmModulePathRoot(modularRoot.fixPath()))
|
||||
}
|
||||
|
||||
configuration.put(
|
||||
JVMConfigurationKeys.JVM_TARGET,
|
||||
originalArguments.jvmTargetIfSupported() ?: JvmTarget.DEFAULT
|
||||
)
|
||||
}
|
||||
configuration.putIfNotNull(JVMConfigurationKeys.JDK_HOME, jdkHome)
|
||||
configuration.configureJdkClasspathRoots()
|
||||
|
||||
configuration.addAll(
|
||||
CLIConfigurationKeys.CONTENT_ROOTS,
|
||||
moduleData.sources.filter { it.extension == "kt" || it.isDirectory }.map { KotlinSourceRoot(it.absolutePath, false) })
|
||||
|
||||
configuration.addAll(JVMConfigurationKeys.FRIEND_PATHS, moduleData.friendDirs.map { it.absolutePath })
|
||||
|
||||
return configuration
|
||||
}
|
||||
}
|
||||
+20
-3
@@ -128,10 +128,27 @@ abstract class AbstractFullPipelineModularizedTest : AbstractModularizedTest() {
|
||||
}
|
||||
|
||||
private fun configureBaseArguments(args: K2JVMCompilerArguments, moduleData: ModuleData, tmp: Path) {
|
||||
val originalArguments = moduleData.arguments as? K2JVMCompilerArguments
|
||||
if (originalArguments != null) {
|
||||
args.apiVersion = originalArguments.apiVersion
|
||||
args.noJdk = originalArguments.noJdk
|
||||
args.noStdlib = originalArguments.noStdlib
|
||||
args.noReflect = originalArguments.noReflect
|
||||
args.jvmTarget = originalArguments.jvmTargetIfSupported()?.description
|
||||
args.jsr305 = originalArguments.jsr305
|
||||
args.nullabilityAnnotations = originalArguments.nullabilityAnnotations
|
||||
args.jspecifyAnnotations = originalArguments.jspecifyAnnotations
|
||||
args.jvmDefault = originalArguments.jvmDefault
|
||||
args.jdkRelease = originalArguments.jdkRelease
|
||||
args.progressiveMode = originalArguments.progressiveMode
|
||||
args.optIn = (moduleData.optInAnnotations + (originalArguments.optIn ?: emptyArray())).toTypedArray()
|
||||
args.allowKotlinPackage = originalArguments.allowKotlinPackage
|
||||
} else {
|
||||
args.jvmTarget = JVM_TARGET
|
||||
args.allowKotlinPackage = true
|
||||
}
|
||||
args.reportPerf = true
|
||||
args.jvmTarget = JVM_TARGET
|
||||
args.allowKotlinPackage = true
|
||||
args.jdkHome = moduleData.jdkHome?.absolutePath
|
||||
args.jdkHome = moduleData.jdkHome?.absolutePath ?: originalArguments?.jdkHome?.fixPath()?.absolutePath
|
||||
args.renderInternalDiagnosticNames = true
|
||||
configureArgsUsingBuildFile(args, moduleData, tmp)
|
||||
}
|
||||
|
||||
+27
-2
@@ -6,7 +6,11 @@
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.util.xmlb.XmlSerializer
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
@@ -37,11 +41,16 @@ data class ModuleData(
|
||||
val friendDirs = rawFriendDirs.map { it.fixPath() }
|
||||
val jdkHome = rawJdkHome?.fixPath()
|
||||
val modularJdkRoot = rawModularJdkRoot?.fixPath()
|
||||
|
||||
/**
|
||||
* Raw compiler arguments, as it was passed to original module build
|
||||
*/
|
||||
var arguments: CommonCompilerArguments? = null
|
||||
}
|
||||
|
||||
data class JavaSourceRootData<Path : Any>(val path: Path, val packagePrefix: String?)
|
||||
|
||||
private fun String.fixPath(): File = File(ROOT_PATH_PREFIX, this.removePrefix("/"))
|
||||
internal fun String.fixPath(): File = File(ROOT_PATH_PREFIX, this.removePrefix("/"))
|
||||
|
||||
private val ROOT_PATH_PREFIX:String = System.getProperty("fir.bench.prefix", "/")
|
||||
private val OUTPUT_DIR_REGEX_FILTER:String = System.getProperty("fir.bench.filter", ".*")
|
||||
@@ -136,7 +145,16 @@ abstract class AbstractModularizedTest : KtUsefulTestCase() {
|
||||
private fun loadModuleDumpFile(file: File): List<ModuleData> {
|
||||
val rootElement = JDOMUtil.load(file)
|
||||
val modules = rootElement.getChildren("module")
|
||||
return modules.map { node -> loadModule(node) }
|
||||
val arguments = rootElement.getChild("compilerArguments")?.let { loadCompilerArguments(it) }
|
||||
return modules.map { node -> loadModule(node).also { it.arguments = arguments } }
|
||||
}
|
||||
|
||||
private fun loadCompilerArguments(argumentsRoot: Element): CommonCompilerArguments? {
|
||||
val element = argumentsRoot.children.singleOrNull() ?: return null
|
||||
return when (element.name) {
|
||||
"K2JVMCompilerArguments" -> K2JVMCompilerArguments().also { XmlSerializer.deserializeInto(it, element) }
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun beforePass(pass: Int)
|
||||
@@ -172,3 +190,10 @@ abstract class AbstractModularizedTest : KtUsefulTestCase() {
|
||||
afterPass(pass)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun K2JVMCompilerArguments.jvmTargetIfSupported(): JvmTarget? {
|
||||
val specified = jvmTarget?.let { JvmTarget.fromString(it) } ?: return null
|
||||
if (specified != JvmTarget.JVM_1_6) return specified
|
||||
return null
|
||||
}
|
||||
+20
-11
@@ -7,21 +7,30 @@ package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
|
||||
/**
|
||||
* Language version to be used for K1 FP tests
|
||||
*/
|
||||
internal val LANGUAGE_VERSION_K1: String = System.getProperty("fir.bench.language.version.k1", "1.8")
|
||||
|
||||
class FE1FullPipelineModularizedTest : AbstractFullPipelineModularizedTest() {
|
||||
override fun configureArguments(args: K2JVMCompilerArguments, moduleData: ModuleData) {
|
||||
args.useK2 = false
|
||||
args.useIR = true
|
||||
args.jvmDefault = "compatibility"
|
||||
args.apiVersion = API_VERSION
|
||||
args.optIn = arrayOf(
|
||||
"kotlin.RequiresOptIn",
|
||||
"kotlin.contracts.ExperimentalContracts",
|
||||
"kotlin.io.path.ExperimentalPathApi",
|
||||
"org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI"
|
||||
)
|
||||
args.multiPlatform = true
|
||||
args.noStdlib = true
|
||||
args.noReflect = true
|
||||
args.languageVersion = LANGUAGE_VERSION_K1
|
||||
// TODO: Remove when support for old modularized tests is removed
|
||||
if (moduleData.arguments == null) {
|
||||
args.jvmDefault = "compatibility"
|
||||
args.apiVersion = API_VERSION
|
||||
args.optIn = arrayOf(
|
||||
"kotlin.RequiresOptIn",
|
||||
"kotlin.contracts.ExperimentalContracts",
|
||||
"kotlin.io.path.ExperimentalPathApi",
|
||||
"org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI"
|
||||
)
|
||||
args.multiPlatform = true
|
||||
args.noStdlib = true
|
||||
args.noReflect = true
|
||||
}
|
||||
}
|
||||
|
||||
fun testTotalKotlin() {
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.*
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.collectSources
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
||||
@@ -213,6 +214,7 @@ class FirResolveModularizedTotalKotlinTest : AbstractFrontendModularizedTest() {
|
||||
override fun processModule(moduleData: ModuleData): ProcessorAction {
|
||||
val disposable = Disposer.newDisposable()
|
||||
val configuration = createDefaultConfiguration(moduleData)
|
||||
configureLanguageVersionSettings(configuration, moduleData, LanguageVersion.fromVersionString(LANGUAGE_VERSION_K2)!!)
|
||||
val environment = KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
|
||||
PsiElementFinder.EP.getPoint(environment.project)
|
||||
|
||||
+16
-13
@@ -8,11 +8,11 @@ package org.jetbrains.kotlin.fir
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
|
||||
// This is used for API version configuration for both frontends
|
||||
// TODO: rename system property
|
||||
// TODO: Deprecated and only used in old FP tests
|
||||
internal val API_VERSION: String = System.getProperty("fir.bench.language.version", "1.4")
|
||||
|
||||
// This is used for language version configuration for K2 only. K1 always uses default version
|
||||
private val LANGUAGE_VERSION_K2: String = System.getProperty("fir.bench.language.version.k2", "2.0")
|
||||
// This is used for language version configuration for K2 only. K1 uses LANGUAGE_VERSION_K1
|
||||
internal val LANGUAGE_VERSION_K2: String = System.getProperty("fir.bench.language.version.k2", "2.0")
|
||||
|
||||
class FullPipelineModularizedTest : AbstractFullPipelineModularizedTest() {
|
||||
|
||||
@@ -20,16 +20,19 @@ class FullPipelineModularizedTest : AbstractFullPipelineModularizedTest() {
|
||||
args.useK2 = true
|
||||
args.useIR = true
|
||||
args.languageVersion = LANGUAGE_VERSION_K2
|
||||
args.apiVersion = API_VERSION
|
||||
args.jvmDefault = "compatibility"
|
||||
args.optIn = moduleData.optInAnnotations.toTypedArray() + arrayOf(
|
||||
"kotlin.RequiresOptIn",
|
||||
"kotlin.contracts.ExperimentalContracts",
|
||||
"kotlin.io.path.ExperimentalPathApi",
|
||||
"org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI"
|
||||
)
|
||||
args.noStdlib = true
|
||||
args.noReflect = true
|
||||
// TODO: Remove when support for old modularized tests is removed
|
||||
if (moduleData.arguments == null) {
|
||||
args.apiVersion = API_VERSION
|
||||
args.jvmDefault = "compatibility"
|
||||
args.optIn = moduleData.optInAnnotations.toTypedArray() + arrayOf(
|
||||
"kotlin.RequiresOptIn",
|
||||
"kotlin.contracts.ExperimentalContracts",
|
||||
"kotlin.io.path.ExperimentalPathApi",
|
||||
"org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI"
|
||||
)
|
||||
args.noStdlib = true
|
||||
args.noReflect = true
|
||||
}
|
||||
}
|
||||
|
||||
fun testTotalKotlin() {
|
||||
|
||||
+35
-19
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY
|
||||
@@ -16,6 +17,9 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.FlexibleTypeImpl
|
||||
import java.io.FileOutputStream
|
||||
import java.io.PrintStream
|
||||
import kotlin.system.measureNanoTime
|
||||
@@ -67,28 +71,28 @@ class NonFirResolveModularizedTotalKotlinTest : AbstractFrontendModularizedTest(
|
||||
writeMessageToLog("$message: ${time * 1e-6} ms")
|
||||
}
|
||||
|
||||
override fun processModule(moduleData: ModuleData): ProcessorAction {
|
||||
val disposable = Disposer.newDisposable()
|
||||
|
||||
private fun configureAndSetupEnvironment(moduleData: ModuleData, disposable: Disposable): KotlinCoreEnvironment {
|
||||
|
||||
val configuration = createDefaultConfiguration(moduleData)
|
||||
|
||||
|
||||
configuration.languageVersionSettings =
|
||||
LanguageVersionSettingsImpl(
|
||||
configuration.languageVersionSettings.languageVersion,
|
||||
configuration.languageVersionSettings.apiVersion,
|
||||
specificFeatures = mapOf(
|
||||
LanguageFeature.NewInference to if (USE_NI) LanguageFeature.State.ENABLED else LanguageFeature.State.DISABLED
|
||||
),
|
||||
analysisFlags = mapOf(
|
||||
AnalysisFlags.skipPrereleaseCheck to true,
|
||||
AnalysisFlags.optIn to moduleData.optInAnnotations
|
||||
)
|
||||
)
|
||||
|
||||
System.getProperty("fir.bench.oldfe.jvm_target")?.let {
|
||||
configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.fromString(it) ?: error("Unknown JvmTarget"))
|
||||
configureLanguageVersionSettings(
|
||||
configuration, moduleData,
|
||||
LanguageVersion.fromVersionString(LANGUAGE_VERSION_K1)!!,
|
||||
configureFeatures = {
|
||||
put(LanguageFeature.NewInference, if (USE_NI) LanguageFeature.State.ENABLED else LanguageFeature.State.DISABLED)
|
||||
},
|
||||
configureFlags = {
|
||||
// TODO: Remove when old tests are no longer supported
|
||||
if (moduleData.arguments == null) {
|
||||
put(AnalysisFlags.skipPrereleaseCheck, true)
|
||||
}
|
||||
}
|
||||
)
|
||||
// TODO: Remove when old tests are no longer supported
|
||||
if (moduleData.arguments == null) {
|
||||
System.getProperty("fir.bench.oldfe.jvm_target")?.let {
|
||||
configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.fromString(it) ?: error("Unknown JvmTarget"))
|
||||
}
|
||||
}
|
||||
configuration.put(MESSAGE_COLLECTOR_KEY, object : MessageCollector {
|
||||
override fun clear() {
|
||||
@@ -111,6 +115,18 @@ class NonFirResolveModularizedTotalKotlinTest : AbstractFrontendModularizedTest(
|
||||
})
|
||||
val environment = KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
|
||||
val visibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.project)
|
||||
for (friendDir in configuration.getList(JVMConfigurationKeys.FRIEND_PATHS)) {
|
||||
visibilityManager.addFriendPath(friendDir)
|
||||
}
|
||||
|
||||
return environment
|
||||
}
|
||||
|
||||
override fun processModule(moduleData: ModuleData): ProcessorAction {
|
||||
val disposable = Disposer.newDisposable()
|
||||
val environment = configureAndSetupEnvironment(moduleData, disposable)
|
||||
|
||||
runAnalysis(environment)
|
||||
|
||||
Disposer.dispose(disposable)
|
||||
|
||||
Reference in New Issue
Block a user