Support java 9 modules in the diagnostic tests both in sources and binaries

This commit is contained in:
Victor Petukhov
2021-04-06 16:25:16 +03:00
parent 1f0616439c
commit 71755b7a5e
9 changed files with 259 additions and 101 deletions
@@ -49,6 +49,9 @@ fun CompilerConfiguration.addJvmSdkRoots(files: List<File>) {
val CompilerConfiguration.jvmClasspathRoots: List<File> val CompilerConfiguration.jvmClasspathRoots: List<File>
get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance<JvmClasspathRoot>().map(JvmContentRoot::file) get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance<JvmClasspathRoot>().map(JvmContentRoot::file)
val CompilerConfiguration.jvmModularRoots: List<File>
get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance<JvmModulePathRoot>().map(JvmContentRoot::file)
@JvmOverloads @JvmOverloads
fun CompilerConfiguration.addJavaSourceRoot(file: File, packagePrefix: String? = null) { fun CompilerConfiguration.addJavaSourceRoot(file: File, packagePrefix: String? = null) {
add(CLIConfigurationKeys.CONTENT_ROOTS, JavaSourceRoot(file, packagePrefix)) add(CLIConfigurationKeys.CONTENT_ROOTS, JavaSourceRoot(file, packagePrefix))
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2021 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.test
enum class TestJavacVersion {
JAVAC_1_8, JAVAC_9
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.test.directives package org.jetbrains.kotlin.test.directives
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.test.TestJavacVersion
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
@@ -33,6 +34,8 @@ object JvmEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
val WITH_FOREIGN_ANNOTATIONS by directive("Add foreign nullability annotations to classpath") val WITH_FOREIGN_ANNOTATIONS by directive("Add foreign nullability annotations to classpath")
val ALLOW_KOTLIN_PACKAGE by directive("Don't require stdlib as a java 9 module")
val WITH_JSR305_TEST_ANNOTATIONS by directive( val WITH_JSR305_TEST_ANNOTATIONS by directive(
description = """ description = """
Add test nullability annotations based on JSR-305 annotations Add test nullability annotations based on JSR-305 annotations
@@ -47,6 +50,14 @@ object JvmEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
"Compile this java file into jar and add it to classpath instead of compiling Kotlin with Java sources", "Compile this java file into jar and add it to classpath instead of compiling Kotlin with Java sources",
applicability = DirectiveApplicability.File applicability = DirectiveApplicability.File
) )
val ALL_JAVA_AS_BINARY by directive(
"Compile all java files into jar and add it to classpath instead of compiling Kotlin with Java sources",
applicability = DirectiveApplicability.Global
)
val COMPILE_JAVA_USING by enumDirective<TestJavacVersion>(
"Compile all including java files using javac of specific version",
applicability = DirectiveApplicability.Global
)
val JSPECIFY_MUTE by directive( val JSPECIFY_MUTE by directive(
"Skip jspecify checks for compliance Kotlin diagnostics to jspecify marks", "Skip jspecify checks for compliance Kotlin diagnostics to jspecify marks",
@@ -5,22 +5,20 @@
package org.jetbrains.kotlin.test.runners package org.jetbrains.kotlin.test.runners
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.Constructor import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TestJavacVersion
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.REPORT_JVM_DIAGNOSTICS_ON_FRONTEND import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.REPORT_JVM_DIAGNOSTICS_ON_FRONTEND
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.SKIP_TXT import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives.SKIP_TXT
import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives.ANNOTATIONS_PATH import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives.ANNOTATIONS_PATH
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.COMPILE_JAVA_USING
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JDK_KIND import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JDK_KIND
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JVM_TARGET
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.STDLIB_JDK8
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.USE_PSI_CLASS_FILES_READING import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.USE_PSI_CLASS_FILES_READING
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_FOREIGN_ANNOTATIONS import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_FOREIGN_ANNOTATIONS
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_JSR305_TEST_ANNOTATIONS import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_JSR305_TEST_ANNOTATIONS
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_STDLIB
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendFacade
import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler import org.jetbrains.kotlin.test.frontend.classic.handlers.ClassicDiagnosticsHandler
import org.jetbrains.kotlin.test.frontend.classic.handlers.DeclarationsDumpHandler import org.jetbrains.kotlin.test.frontend.classic.handlers.DeclarationsDumpHandler
@@ -34,7 +32,7 @@ import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsS
import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider import org.jetbrains.kotlin.test.services.sourceProviders.CoroutineHelpersSourceFilesProvider
abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest() { abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest() {
protected abstract val foreignAnnotationsConfigurator: Constructor<JvmForeignAnnotationsConfigurator> protected open val foreignAnnotationsConfigurator: Constructor<JvmForeignAnnotationsConfigurator>? = null
override fun TestConfigurationBuilder.configuration() { override fun TestConfigurationBuilder.configuration() {
globalDefaults { globalDefaults {
@@ -46,17 +44,17 @@ abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest()
defaultDirectives { defaultDirectives {
+REPORT_JVM_DIAGNOSTICS_ON_FRONTEND +REPORT_JVM_DIAGNOSTICS_ON_FRONTEND
+WITH_FOREIGN_ANNOTATIONS +WITH_FOREIGN_ANNOTATIONS
+WITH_JSR305_TEST_ANNOTATIONS
} }
enableMetaInfoHandler() enableMetaInfoHandler()
useConfigurators( useConfigurators(
::CommonEnvironmentConfigurator, ::CommonEnvironmentConfigurator,
::JvmEnvironmentConfigurator, ::JvmEnvironmentConfigurator
foreignAnnotationsConfigurator
) )
foreignAnnotationsConfigurator.takeIf { it != null }?.also { useConfigurators(it) }
useMetaInfoProcessors(::OldNewInferenceMetaInfoProcessor) useMetaInfoProcessors(::OldNewInferenceMetaInfoProcessor)
useAdditionalSourceProviders( useAdditionalSourceProviders(
::AdditionalDiagnosticsSourceFilesProvider, ::AdditionalDiagnosticsSourceFilesProvider,
@@ -72,6 +70,7 @@ abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest()
forTestsMatching("compiler/testData/diagnostics/foreignAnnotationsTests/tests/*") { forTestsMatching("compiler/testData/diagnostics/foreignAnnotationsTests/tests/*") {
defaultDirectives { defaultDirectives {
ANNOTATIONS_PATH with JavaForeignAnnotationType.Annotations ANNOTATIONS_PATH with JavaForeignAnnotationType.Annotations
+WITH_JSR305_TEST_ANNOTATIONS
} }
} }
@@ -81,6 +80,14 @@ abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest()
} }
} }
forTestsMatching("compiler/testData/diagnostics/foreignAnnotationsTests/java9Tests/*") {
defaultDirectives {
ANNOTATIONS_PATH with JavaForeignAnnotationType.Java9Annotations
JDK_KIND with TestJdkKind.FULL_JDK_9
COMPILE_JAVA_USING with TestJavacVersion.JAVAC_9
}
}
forTestsMatching("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/*") { forTestsMatching("compiler/testData/diagnostics/foreignAnnotationsTests/java8Tests/jspecify/*") {
useSourcePreprocessor(::JspecifyTestsPreprocessor, needToPrepend = true) useSourcePreprocessor(::JspecifyTestsPreprocessor, needToPrepend = true)
} }
@@ -93,9 +100,6 @@ abstract class AbstractForeignAnnotationsTest : AbstractForeignAnnotationsTestBa
} }
abstract class AbstractForeignAnnotationsNoAnnotationInClasspathTest : AbstractForeignAnnotationsTestBase() { abstract class AbstractForeignAnnotationsNoAnnotationInClasspathTest : AbstractForeignAnnotationsTestBase() {
override val foreignAnnotationsConfigurator: Constructor<JvmForeignAnnotationsConfigurator>
get() = ::JvmForeignAnnotationsAgainstCompiledJavaConfigurator
override fun configure(builder: TestConfigurationBuilder) { override fun configure(builder: TestConfigurationBuilder) {
super.configure(builder) super.configure(builder)
with(builder) { with(builder) {
@@ -6,19 +6,24 @@
package org.jetbrains.kotlin.test.services.configuration package org.jetbrains.kotlin.test.services.configuration
import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.SystemInfo
import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot import com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.addModularRootIfNotNull
import org.jetbrains.kotlin.cli.jvm.config.*
import org.jetbrains.kotlin.cli.jvm.configureStandardLibs
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.MockLibraryUtil
import org.jetbrains.kotlin.test.MockLibraryUtil.compileJavaFilesLibraryToJar import org.jetbrains.kotlin.test.MockLibraryUtil.compileJavaFilesLibraryToJar
import org.jetbrains.kotlin.test.TestJavacVersion
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.ASSERTIONS_MODE import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.ASSERTIONS_MODE
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.COMPILE_JAVA_USING
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.CONSTRUCTOR_CALL_NORMALIZATION_MODE import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.CONSTRUCTOR_CALL_NORMALIZATION_MODE
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.INCLUDE_JAVA_AS_BINARY import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.INCLUDE_JAVA_AS_BINARY
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JVM_TARGET import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JVM_TARGET
@@ -37,15 +42,16 @@ import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.model.DependencyDescription import org.jetbrains.kotlin.test.model.DependencyDescription
import org.jetbrains.kotlin.test.model.DependencyKind import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.FOREIGN_ANNOTATIONS_SOURCES_PATH import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.FOREIGN_JDK8_ANNOTATIONS_SOURCES_PATH import org.jetbrains.kotlin.test.services.configuration.JvmForeignAnnotationsConfigurator.Companion.JSR_305_TEST_ANNOTATIONS_PATH
import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.JSR_305_TEST_ANNOTATIONS_PATH
import org.jetbrains.kotlin.test.services.jvm.CompiledClassesManager import org.jetbrains.kotlin.test.services.jvm.CompiledClassesManager
import org.jetbrains.kotlin.test.services.jvm.compiledClassesManager import org.jetbrains.kotlin.test.services.jvm.compiledClassesManager
import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.test.util.KtTestUtil
import org.jetbrains.kotlin.test.util.joinToArrayString import org.jetbrains.kotlin.test.util.joinToArrayString
import org.jetbrains.kotlin.utils.PathUtil
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.File import java.io.File
import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.ExperimentalPathApi
@@ -56,6 +62,8 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
val TEST_CONFIGURATION_KIND_KEY = CompilerConfigurationKey.create<ConfigurationKind>("ConfigurationKind") val TEST_CONFIGURATION_KIND_KEY = CompilerConfigurationKey.create<ConfigurationKind>("ConfigurationKind")
private val DEFAULT_JVM_TARGET_FROM_PROPERTY: String? = System.getProperty("kotlin.test.default.jvm.target") private val DEFAULT_JVM_TARGET_FROM_PROPERTY: String? = System.getProperty("kotlin.test.default.jvm.target")
private const val JAVA_BINARIES_JAR_NAME = "java-binaries"
} }
override val directivesContainers: List<DirectivesContainer> override val directivesContainers: List<DirectivesContainer>
@@ -81,6 +89,7 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
register(JVM_TARGET, JVMConfigurationKeys.JVM_TARGET) register(JVM_TARGET, JVMConfigurationKeys.JVM_TARGET)
} }
@OptIn(ExperimentalPathApi::class, ExperimentalStdlibApi::class)
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) { override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
if (module.targetPlatform !in JvmPlatforms.allJvmPlatforms) return if (module.targetPlatform !in JvmPlatforms.allJvmPlatforms) return
configureDefaultJvmTarget(configuration) configureDefaultJvmTarget(configuration)
@@ -120,9 +129,20 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
configuration.put(TEST_CONFIGURATION_KIND_KEY, it) configuration.put(TEST_CONFIGURATION_KIND_KEY, it)
} }
val javaVersionToCompile = registeredDirectives[COMPILE_JAVA_USING].singleOrNull()
val javaBinaryFiles = module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY in it.directives }
val withForeignAnnotations = JvmEnvironmentConfigurationDirectives.WITH_FOREIGN_ANNOTATIONS in registeredDirectives
assertTrue(javaVersionToCompile == null || javaBinaryFiles.isNotEmpty() || withForeignAnnotations) {
"'COMPILE_JAVA_USING' can't be use if there aren't any java files to compile " +
"(mark java files by 'INCLUDE_JAVA_AS_BINARY' or include foreign annotations using 'WITH_FOREIGN_ANNOTATIONS' " +
"which will be compiled by specified version of javac)"
}
val useJava9ToCompileIncludedJavaFiles = javaVersionToCompile == TestJavacVersion.JAVAC_9
if (configurationKind.withRuntime) { if (configurationKind.withRuntime) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.runtimeJarForTests()) configuration.configureStandardLibs(PathUtil.kotlinPathsForDistDirectory, K2JVMCompilerArguments().also { it.noReflect = true })
configuration.addJvmClasspathRoot(ForTestCompileRuntime.scriptRuntimeJarForTests())
configuration.addJvmClasspathRoot(ForTestCompileRuntime.kotlinTestJarForTests()) configuration.addJvmClasspathRoot(ForTestCompileRuntime.kotlinTestJarForTests())
} else if (configurationKind.withMockRuntime) { } else if (configurationKind.withMockRuntime) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.minimalRuntimeJarForTests()) configuration.addJvmClasspathRoot(ForTestCompileRuntime.minimalRuntimeJarForTests())
@@ -131,63 +151,87 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
if (configurationKind.withReflection) { if (configurationKind.withReflection) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.reflectJarForTests()) configuration.addJvmClasspathRoot(ForTestCompileRuntime.reflectJarForTests())
} }
configuration.addJvmClasspathRoot(KtTestUtil.getAnnotationsJar())
if (JvmEnvironmentConfigurationDirectives.STDLIB_JDK8 in module.directives) { if (JvmEnvironmentConfigurationDirectives.STDLIB_JDK8 in module.directives) {
configuration.addJvmClasspathRoot(ForTestCompileRuntime.runtimeJarForTestsWithJdk8()) configuration.addJvmClasspathRoot(ForTestCompileRuntime.runtimeJarForTestsWithJdk8())
} }
if (JvmEnvironmentConfigurationDirectives.WITH_FOREIGN_ANNOTATIONS in registeredDirectives) { if (withForeignAnnotations) {
val annotationPath = registeredDirectives[ForeignAnnotationsDirectives.ANNOTATIONS_PATH].singleOrNull() val annotationPath = registeredDirectives[ForeignAnnotationsDirectives.ANNOTATIONS_PATH].singleOrNull()
?: JdkForeignAnnotationType.Jdk8Annotations ?: JavaForeignAnnotationType.Java8Annotations
val javaFilesDir = createTempDirectory().toFile().also { val javaFilesDir = createTempDirectory().toFile().also {
File(annotationPath.path).copyRecursively(it) File(annotationPath.path).copyRecursively(it)
} }
val jar = compileJavaFilesLibraryToJar( val foreignAnnotationsJar = compileJavaFilesLibraryToJar(
javaFilesDir.path, javaFilesDir.path,
"foreign-annotations", "foreign-annotations",
assertions = JUnit5Assertions, assertions = JUnit5Assertions,
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath } extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath },
useJava9 = useJava9ToCompileIncludedJavaFiles
) )
configuration.addJvmClasspathRoot(jar) configuration.addModularRootIfNotNull(useJava9ToCompileIncludedJavaFiles, "java9_annotations", foreignAnnotationsJar)
configuration.addJvmClasspathRoot(ForTestCompileRuntime.jvmAnnotationsForTests()) configuration.addJvmClasspathRoot(ForTestCompileRuntime.jvmAnnotationsForTests())
} else {
// Add jetbrains annotations of an old version, without supporting type use target
configuration.addJvmClasspathRoot(KtTestUtil.getAnnotationsJar())
} }
if (JvmEnvironmentConfigurationDirectives.WITH_JSR305_TEST_ANNOTATIONS in registeredDirectives) { if (JvmEnvironmentConfigurationDirectives.WITH_JSR305_TEST_ANNOTATIONS in registeredDirectives) {
val javaFilesDir = createTempDirectory().toFile().also { val javaFilesDir = createTempDirectory().toFile().also {
File(JSR_305_TEST_ANNOTATIONS_PATH).copyRecursively(it) File(JSR_305_TEST_ANNOTATIONS_PATH).copyRecursively(it)
} }
val jar = compileJavaFilesLibraryToJar( configuration.addJvmClasspathRoot(
javaFilesDir.path, compileJavaFilesLibraryToJar(
"jsr-305-test-annotations", javaFilesDir.path,
assertions = JUnit5Assertions, "jsr-305-test-annotations",
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath } assertions = JUnit5Assertions,
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath }
)
) )
configuration.addJvmClasspathRoot(jar) configuration.addJvmClasspathRoot(KtTestUtil.getAnnotationsJar())
} }
val isIr = module.targetBackend?.isIR == true val isIr = module.targetBackend?.isIR == true
configuration.put(JVMConfigurationKeys.IR, isIr) configuration.put(JVMConfigurationKeys.IR, isIr)
if (JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES !in module.directives) { val javaSourceFiles = module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY !in it.directives }
val javaSourceFiles = module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY !in it.directives }
javaSourceFiles.takeIf { it.isNotEmpty() }?.let { javaFiles -> if (javaSourceFiles.isNotEmpty() && JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES !in module.directives && ALL_JAVA_AS_BINARY !in registeredDirectives) {
javaFiles.forEach { testServices.sourceFileProvider.getRealFileForSourceFile(it) } javaSourceFiles.forEach { testServices.sourceFileProvider.getRealFileForSourceFile(it) }
// TODO: temporary hack to provide java 9 modules in the source mode properly (see comment on ClasspathRootsResolved::addModularRoots)
addJavaCompiledModulesFromDependentKotlinModules(configuration, configurationKind, module, bySources = true)
val moduleInfoFiles = javaSourceFiles.filter { it.name == MODULE_INFO_FILE }
if (moduleInfoFiles.isNotEmpty()) {
addJavaSourceRootsByJavaModules(configuration, moduleInfoFiles)
} else {
configuration.addJavaSourceRoot(testServices.sourceFileProvider.javaSourceDirectory) configuration.addJavaSourceRoot(testServices.sourceFileProvider.javaSourceDirectory)
} }
} }
val javaBinaryFiles = module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY in it.directives } if (javaBinaryFiles.isNotEmpty()) {
javaBinaryFiles.forEach { testServices.sourceFileProvider.getRealFileForBinaryFile(it) }
javaBinaryFiles.takeIf { it.isNotEmpty() }?.let { javaFiles -> addJavaCompiledModulesFromDependentKotlinModules(configuration, configurationKind, module, bySources = false)
javaFiles.forEach { testServices.sourceFileProvider.getRealFileForBinaryFile(it) }
val jar = compileJavaFilesLibraryToJar( val moduleInfoFiles = javaBinaryFiles.filter { it.name == MODULE_INFO_FILE }
testServices.sourceFileProvider.javaBinaryDirectory.path,
"java-binaries", // TODO: Use module graph to build proper modulepath for each module according cross-module dependencies
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath }, if (moduleInfoFiles.isNotEmpty()) {
assertions = JUnit5Assertions addJavaBinaryRootsByJavaModules(configuration, configurationKind, moduleInfoFiles)
) } else {
configuration.addJvmClasspathRoot(jar) configuration.addJvmClasspathRoot(
compileJavaFilesLibraryToJar(
testServices.sourceFileProvider.javaBinaryDirectory.path,
JAVA_BINARIES_JAR_NAME,
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath },
assertions = JUnit5Assertions,
useJava9 = useJava9ToCompileIncludedJavaFiles
)
)
}
} }
configuration.registerModuleDependencies(module) configuration.registerModuleDependencies(module)
@@ -196,9 +240,94 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig
configuration.put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, true) configuration.put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, true)
} }
if (JvmEnvironmentConfigurationDirectives.ALLOW_KOTLIN_PACKAGE in module.directives) {
configuration.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, true)
}
initBinaryDependencies(module, configuration) initBinaryDependencies(module, configuration)
} }
private fun addJavaSourceRootsByJavaModules(configuration: CompilerConfiguration, moduleInfoFiles: List<TestFile>) {
val javaSourceDirectory = testServices.sourceFileProvider.javaSourceDirectory
for (moduleInfoFile in moduleInfoFiles) {
val moduleName = moduleInfoFile.relativePath.substringBefore('/')
val moduleDir = File("${javaSourceDirectory.path}/$moduleName").also { it.mkdir() }
configuration.addJavaSourceRoot(moduleDir)
}
}
private fun addJavaBinaryRootsByJavaModules(
configuration: CompilerConfiguration,
configurationKind: ConfigurationKind,
moduleInfoFiles: List<TestFile>
) {
val javaBinaryDirectory = testServices.sourceFileProvider.javaBinaryDirectory
for (moduleInfoFile in moduleInfoFiles) {
val moduleName = moduleInfoFile.relativePath.substringBefore('/')
addJavaCompiledModule(configuration, configurationKind, moduleName, bySources = true, targetDir = javaBinaryDirectory)
}
}
private fun addJavaCompiledModulesFromDependentKotlinModules(
configuration: CompilerConfiguration,
configurationKind: ConfigurationKind,
module: TestModule,
bySources: Boolean
) {
val moduleDependencies = module.dependencies.map { testServices.dependencyProvider.getTestModule(it.moduleName) }
val filterJavaModuleInfoFiles = { testFile: TestFile ->
val binaryFilesFilter = INCLUDE_JAVA_AS_BINARY in testFile.directives || ALL_JAVA_AS_BINARY in module.directives
val includeOrExcludeBinaryFilesFilter = (bySources && !binaryFilesFilter) || (!bySources && binaryFilesFilter)
includeOrExcludeBinaryFilesFilter && testFile.name == MODULE_INFO_FILE
}
val moduleInfoFilesFromDependencies = moduleDependencies.mapNotNull { it.javaFiles.singleOrNull(filterJavaModuleInfoFiles) }
for (dependentModuleInfoFile in moduleInfoFilesFromDependencies) {
val moduleName = dependentModuleInfoFile.relativePath.substringBefore('/')
addJavaCompiledModule(configuration, configurationKind, moduleName, bySources)
}
}
private fun addJavaCompiledModule(
configuration: CompilerConfiguration,
configurationKind: ConfigurationKind,
moduleName: String,
bySources: Boolean,
targetDir: File = testServices.sourceFileProvider.run { if (bySources) javaSourceDirectory else javaBinaryDirectory }
) {
val moduleDir = File("${targetDir.path}/$moduleName")
val javaBinaries = if (bySources) {
compileJavaFilesToModularJar(configuration, configurationKind, moduleDir)
} else {
File("${moduleDir.path}/$JAVA_BINARIES_JAR_NAME.jar")
}
configuration.addModularRootIfNotNull(isModularJava = true, moduleName, javaBinaries)
}
@OptIn(ExperimentalStdlibApi::class)
private fun compileJavaFilesToModularJar(
configuration: CompilerConfiguration,
configurationKind: ConfigurationKind,
sourcesDir: File
): File {
val modulePath = buildList {
addAll(configuration.jvmModularRoots.map { it.absolutePath })
if (configurationKind.withRuntime) {
add(ForTestCompileRuntime.runtimeJarForTests().path)
}
}
return MockLibraryUtil.compileLibraryToJar(
sourcesDir.path,
sourcesDir,
JAVA_BINARIES_JAR_NAME,
extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath },
extraModulepath = modulePath,
assertions = JUnit5Assertions,
useJava9 = true
)
}
private fun configureDefaultJvmTarget(configuration: CompilerConfiguration) { private fun configureDefaultJvmTarget(configuration: CompilerConfiguration) {
if (DEFAULT_JVM_TARGET_FROM_PROPERTY == null) return if (DEFAULT_JVM_TARGET_FROM_PROPERTY == null) return
val customDefaultTarget = JvmTarget.fromString(DEFAULT_JVM_TARGET_FROM_PROPERTY) val customDefaultTarget = JvmTarget.fromString(DEFAULT_JVM_TARGET_FROM_PROPERTY)
@@ -15,22 +15,19 @@ import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives.JSR305_
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.utils.JavaTypeEnhancementState import org.jetbrains.kotlin.utils.JavaTypeEnhancementState
import org.jetbrains.kotlin.utils.ReportLevel import org.jetbrains.kotlin.utils.ReportLevel
import java.io.File
enum class JavaForeignAnnotationType(val path: String) { enum class JavaForeignAnnotationType(val path: String) {
Annotations("third-party/annotations"), Annotations("third-party/annotations"),
Java8Annotations("third-party/java8-annotations"); Java8Annotations("third-party/java8-annotations"),
Java9Annotations("third-party/java9-annotations");
} }
open class JvmForeignAnnotationsConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) { open class JvmForeignAnnotationsConfigurator(testServices: TestServices) : EnvironmentConfigurator(testServices) {
companion object { companion object {
val FOREIGN_ANNOTATIONS_SOURCES_PATH = Annotations.path const val JSR_305_TEST_ANNOTATIONS_PATH = "compiler/testData/diagnostics/helpers/jsr305_test_annotations"
val FOREIGN_JDK8_ANNOTATIONS_SOURCES_PATH = Jdk8Annotations.path
val JSR_305_TEST_ANNOTATIONS_PATH = "compiler/testData/diagnostics/helpers/jsr305_test_annotations"
} }
override val directivesContainers: List<DirectivesContainer> override val directivesContainers: List<DirectivesContainer>
@@ -55,33 +52,3 @@ open class JvmForeignAnnotationsConfigurator(testServices: TestServices) : Envir
) )
} }
} }
class JvmForeignAnnotationsAgainstCompiledJavaConfigurator(testServices: TestServices) : JvmForeignAnnotationsConfigurator(testServices) {
@OptIn(ExperimentalStdlibApi::class)
override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) {
val compiledJavaPath = testServices.createTempDirectory("java-compiled-files")
val foreignAnnotations = createJarWithForeignAnnotations(module)
val testAnnotations = compileTestAnnotations(foreignAnnotations)
val additionalClasspath = buildList {
addAll(foreignAnnotations)
addAll(testAnnotations)
}.map { it.path }
module.javaFiles.forEach { testServices.sourceFileProvider.getRealFileForSourceFile(it) }
CodegenTestUtil.compileJava(
CodegenTestUtil.findJavaSourcesInDirectory(testServices.sourceFileProvider.javaSourceDirectory),
additionalClasspath,
emptyList(),
compiledJavaPath,
JUnit5Assertions
)
val extraClassPath = buildList {
add(compiledJavaPath)
addAll(testAnnotations)
}
configuration.addJvmClasspathRoots(extraClassPath)
}
}
@@ -18,7 +18,15 @@ object MockLibraryUtilExt {
extraOptions: List<String> = emptyList(), extraOptions: List<String> = emptyList(),
extraClasspath: List<String> = emptyList(), extraClasspath: List<String> = emptyList(),
): File { ): File {
return MockLibraryUtil.compileJavaFilesLibraryToJar(sourcesPath, jarName, addSources, extraOptions, extraClasspath, JUnit4Assertions) return MockLibraryUtil.compileJavaFilesLibraryToJar(
sourcesPath,
jarName,
addSources,
extraOptions,
extraClasspath,
extraModulepath = listOf(),
JUnit4Assertions
)
} }
@JvmStatic @JvmStatic
@@ -39,6 +47,7 @@ object MockLibraryUtilExt {
allowKotlinSources, allowKotlinSources,
extraOptions, extraOptions,
extraClasspath, extraClasspath,
extraModulepath = listOf(),
useJava9, useJava9,
JUnit4Assertions JUnit4Assertions
) )
@@ -64,6 +73,7 @@ object MockLibraryUtilExt {
allowKotlinSources, allowKotlinSources,
extraOptions, extraOptions,
extraClasspath, extraClasspath,
extraModulepath = listOf(),
useJava9, useJava9,
JUnit4Assertions JUnit4Assertions
) )
@@ -9,15 +9,15 @@ package org.jetbrains.kotlin.test
import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.test.util.KtTestUtil
import org.jetbrains.kotlin.utils.rethrow import org.jetbrains.kotlin.utils.rethrow
import java.io.File import java.io.*
import java.io.IOException
import java.io.StringWriter
import java.nio.charset.Charset import java.nio.charset.Charset
import java.util.* import java.util.*
import javax.tools.Diagnostic import javax.tools.Diagnostic
import javax.tools.DiagnosticCollector import javax.tools.DiagnosticCollector
import javax.tools.JavaFileObject import javax.tools.JavaFileObject
import javax.tools.ToolProvider import javax.tools.ToolProvider
import java.util.stream.Collectors
@JvmOverloads @JvmOverloads
@Throws(IOException::class) @Throws(IOException::class)
@@ -66,13 +66,19 @@ fun compileJavaFilesExternally(files: Collection<File>, options: List<String?>,
for (file in files) { for (file in files) {
command.add(file.path) command.add(file.path)
} }
return try { val process = ProcessBuilder().command(command).start()
val process = ProcessBuilder().command(command).inheritIO().start() val errorsReader = BufferedReader(InputStreamReader(process.errorStream))
process.waitFor() val errors = errorsReader.lines().collect(Collectors.joining(System.lineSeparator()))
process.exitValue() == 0
} catch (e: Exception) { process.waitFor()
throw rethrow(e)
val isSuccess = process.exitValue() == 0
if (!isSuccess) {
System.err.println(errors)
} }
return isSuccess
} }
private fun errorsToString(diagnosticCollector: DiagnosticCollector<JavaFileObject>, humanReadable: Boolean): String { private fun errorsToString(diagnosticCollector: DiagnosticCollector<JavaFileObject>, humanReadable: Boolean): String {
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.preloading.ClassPreloadingUtils import org.jetbrains.kotlin.preloading.ClassPreloadingUtils
import org.jetbrains.kotlin.preloading.Preloader import org.jetbrains.kotlin.preloading.Preloader
import org.jetbrains.kotlin.test.KtAssert.assertTrue
import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.test.util.KtTestUtil
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
@@ -36,6 +37,7 @@ object MockLibraryUtil {
allowKotlinSources: Boolean = true, allowKotlinSources: Boolean = true,
extraOptions: List<String> = emptyList(), extraOptions: List<String> = emptyList(),
extraClasspath: List<String> = emptyList(), extraClasspath: List<String> = emptyList(),
extraModulepath: List<String> = emptyList(),
useJava9: Boolean = false, useJava9: Boolean = false,
assertions: Assertions assertions: Assertions
): File { ): File {
@@ -47,6 +49,7 @@ object MockLibraryUtil {
allowKotlinSources, allowKotlinSources,
extraOptions, extraOptions,
extraClasspath, extraClasspath,
extraModulepath,
useJava9, useJava9,
assertions assertions
) )
@@ -59,16 +62,22 @@ object MockLibraryUtil {
addSources: Boolean = false, addSources: Boolean = false,
extraOptions: List<String> = emptyList(), extraOptions: List<String> = emptyList(),
extraClasspath: List<String> = emptyList(), extraClasspath: List<String> = emptyList(),
assertions: Assertions extraModulepath: List<String> = emptyList(),
assertions: Assertions,
useJava9: Boolean = false
): File { ): File {
return compileJvmLibraryToJar( return compileJvmLibraryToJar(
sourcesPath, jarName, addSources, sourcesPath, jarName, addSources,
allowKotlinSources = false, allowKotlinSources = false,
extraClasspath = extraClasspath, extraOptions = extraOptions, extraOptions,
assertions = assertions extraClasspath,
extraModulepath,
useJava9,
assertions
) )
} }
@OptIn(ExperimentalStdlibApi::class)
@JvmStatic @JvmStatic
fun compileLibraryToJar( fun compileLibraryToJar(
sourcesPath: String, sourcesPath: String,
@@ -78,15 +87,18 @@ object MockLibraryUtil {
allowKotlinSources: Boolean = true, allowKotlinSources: Boolean = true,
extraOptions: List<String> = emptyList(), extraOptions: List<String> = emptyList(),
extraClasspath: List<String> = emptyList(), extraClasspath: List<String> = emptyList(),
extraModulepath: List<String> = emptyList(),
useJava9: Boolean = false, useJava9: Boolean = false,
assertions: Assertions assertions: Assertions
): File { ): File {
assertTrue("Module path can be used only for compilation using javac 9 and higher", useJava9 || extraModulepath.isEmpty())
val classesDir = File(contentDir, "classes") val classesDir = File(contentDir, "classes")
val srcFile = File(sourcesPath) val srcFile = File(sourcesPath)
val kotlinFiles = FileUtil.findFilesByMask(Pattern.compile(".*\\.kt"), srcFile) val kotlinFiles = FileUtil.findFilesByMask(Pattern.compile(".*\\.kt"), srcFile)
if (srcFile.isFile || kotlinFiles.isNotEmpty()) { if (srcFile.isFile || kotlinFiles.isNotEmpty()) {
KtAssert.assertTrue("Only java files are expected", allowKotlinSources) assertTrue("Only java files are expected", allowKotlinSources)
compileKotlin(sourcesPath, classesDir, extraOptions, *extraClasspath.toTypedArray()) compileKotlin(sourcesPath, classesDir, extraOptions, *extraClasspath.toTypedArray())
} }
@@ -94,7 +106,6 @@ object MockLibraryUtil {
if (javaFiles.isNotEmpty()) { if (javaFiles.isNotEmpty()) {
val classpath = mutableListOf<String>() val classpath = mutableListOf<String>()
classpath += ForTestCompileRuntime.runtimeJarForTests().path classpath += ForTestCompileRuntime.runtimeJarForTests().path
classpath += KtTestUtil.getAnnotationsJar().path
classpath += extraClasspath classpath += extraClasspath
// Probably no kotlin files were present, so dir might not have been created after kotlin compiler // Probably no kotlin files were present, so dir might not have been created after kotlin compiler
@@ -104,10 +115,17 @@ object MockLibraryUtil {
FileUtil.createDirectory(classesDir) FileUtil.createDirectory(classesDir)
} }
val options = listOf( val options = buildList {
"-classpath", classpath.joinToString(File.pathSeparator), add("-classpath")
"-d", classesDir.path add(classpath.joinToString(File.pathSeparator))
) add("-d")
add(classesDir.path)
if (useJava9) {
add("--module-path")
add(extraModulepath.joinToString(File.pathSeparator))
}
}
val compile = val compile =
if (useJava9) ::compileJavaFilesExternallyWithJava9 if (useJava9) ::compileJavaFilesExternallyWithJava9