diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JvmContentRoots.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JvmContentRoots.kt index 15d35f26583..bc374d5f32e 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JvmContentRoots.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/config/JvmContentRoots.kt @@ -49,6 +49,9 @@ fun CompilerConfiguration.addJvmSdkRoots(files: List) { val CompilerConfiguration.jvmClasspathRoots: List get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance().map(JvmContentRoot::file) +val CompilerConfiguration.jvmModularRoots: List + get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance().map(JvmContentRoot::file) + @JvmOverloads fun CompilerConfiguration.addJavaSourceRoot(file: File, packagePrefix: String? = null) { add(CLIConfigurationKeys.CONTENT_ROOTS, JavaSourceRoot(file, packagePrefix)) diff --git a/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/test/TestJavacVersion.kt b/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/test/TestJavacVersion.kt new file mode 100644 index 00000000000..1f9d5c7839d --- /dev/null +++ b/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/test/TestJavacVersion.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt index db986d80644..af6a6dbff10 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/JvmEnvironmentConfigurationDirectives.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.test.directives import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.test.TestJavacVersion import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.directives.model.DirectiveApplicability 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 ALLOW_KOTLIN_PACKAGE by directive("Don't require stdlib as a java 9 module") + val WITH_JSR305_TEST_ANNOTATIONS by directive( description = """ 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", 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( + "Compile all including java files using javac of specific version", + applicability = DirectiveApplicability.Global + ) val JSPECIFY_MUTE by directive( "Skip jspecify checks for compliance Kotlin diagnostics to jspecify marks", diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractForeignAnnotationsTest.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractForeignAnnotationsTest.kt index da797393b20..55245576d27 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractForeignAnnotationsTest.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractForeignAnnotationsTest.kt @@ -5,22 +5,20 @@ package org.jetbrains.kotlin.test.runners -import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.test.Constructor +import org.jetbrains.kotlin.test.TestJavacVersion import org.jetbrains.kotlin.test.TestJdkKind 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.SKIP_TXT 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.JVM_TARGET 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.WITH_FOREIGN_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.handlers.ClassicDiagnosticsHandler 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 abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest() { - protected abstract val foreignAnnotationsConfigurator: Constructor + protected open val foreignAnnotationsConfigurator: Constructor? = null override fun TestConfigurationBuilder.configuration() { globalDefaults { @@ -46,17 +44,17 @@ abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest() defaultDirectives { +REPORT_JVM_DIAGNOSTICS_ON_FRONTEND +WITH_FOREIGN_ANNOTATIONS - +WITH_JSR305_TEST_ANNOTATIONS } enableMetaInfoHandler() useConfigurators( ::CommonEnvironmentConfigurator, - ::JvmEnvironmentConfigurator, - foreignAnnotationsConfigurator + ::JvmEnvironmentConfigurator ) + foreignAnnotationsConfigurator.takeIf { it != null }?.also { useConfigurators(it) } + useMetaInfoProcessors(::OldNewInferenceMetaInfoProcessor) useAdditionalSourceProviders( ::AdditionalDiagnosticsSourceFilesProvider, @@ -72,6 +70,7 @@ abstract class AbstractForeignAnnotationsTestBase : AbstractKotlinCompilerTest() forTestsMatching("compiler/testData/diagnostics/foreignAnnotationsTests/tests/*") { defaultDirectives { 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/*") { useSourcePreprocessor(::JspecifyTestsPreprocessor, needToPrepend = true) } @@ -93,9 +100,6 @@ abstract class AbstractForeignAnnotationsTest : AbstractForeignAnnotationsTestBa } abstract class AbstractForeignAnnotationsNoAnnotationInClasspathTest : AbstractForeignAnnotationsTestBase() { - override val foreignAnnotationsConfigurator: Constructor - get() = ::JvmForeignAnnotationsAgainstCompiledJavaConfigurator - override fun configure(builder: TestConfigurationBuilder) { super.configure(builder) with(builder) { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt index 650e0d52d85..d0af840ef96 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmEnvironmentConfigurator.kt @@ -6,19 +6,24 @@ package org.jetbrains.kotlin.test.services.configuration import com.intellij.openapi.util.SystemInfo -import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot -import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot -import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots -import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots +import com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +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.config.* import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.MockLibraryUtil import org.jetbrains.kotlin.test.MockLibraryUtil.compileJavaFilesLibraryToJar +import org.jetbrains.kotlin.test.TestJavacVersion import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.directives.ForeignAnnotationsDirectives import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives 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.INCLUDE_JAVA_AS_BINARY 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.model.DependencyDescription 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.services.* -import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.FOREIGN_ANNOTATIONS_SOURCES_PATH -import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.FOREIGN_JDK8_ANNOTATIONS_SOURCES_PATH -import org.jetbrains.kotlin.test.services.configuration.JdkForeignAnnotationType.Companion.JSR_305_TEST_ANNOTATIONS_PATH +import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue +import org.jetbrains.kotlin.test.services.configuration.JvmForeignAnnotationsConfigurator.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.util.KtTestUtil import org.jetbrains.kotlin.test.util.joinToArrayString +import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.addIfNotNull import java.io.File import kotlin.io.path.ExperimentalPathApi @@ -56,6 +62,8 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig val TEST_CONFIGURATION_KIND_KEY = CompilerConfigurationKey.create("ConfigurationKind") 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 @@ -81,6 +89,7 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig register(JVM_TARGET, JVMConfigurationKeys.JVM_TARGET) } + @OptIn(ExperimentalPathApi::class, ExperimentalStdlibApi::class) override fun configureCompilerConfiguration(configuration: CompilerConfiguration, module: TestModule) { if (module.targetPlatform !in JvmPlatforms.allJvmPlatforms) return configureDefaultJvmTarget(configuration) @@ -120,9 +129,20 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig 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) { - configuration.addJvmClasspathRoot(ForTestCompileRuntime.runtimeJarForTests()) - configuration.addJvmClasspathRoot(ForTestCompileRuntime.scriptRuntimeJarForTests()) + configuration.configureStandardLibs(PathUtil.kotlinPathsForDistDirectory, K2JVMCompilerArguments().also { it.noReflect = true }) configuration.addJvmClasspathRoot(ForTestCompileRuntime.kotlinTestJarForTests()) } else if (configurationKind.withMockRuntime) { configuration.addJvmClasspathRoot(ForTestCompileRuntime.minimalRuntimeJarForTests()) @@ -131,63 +151,87 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig if (configurationKind.withReflection) { configuration.addJvmClasspathRoot(ForTestCompileRuntime.reflectJarForTests()) } - configuration.addJvmClasspathRoot(KtTestUtil.getAnnotationsJar()) if (JvmEnvironmentConfigurationDirectives.STDLIB_JDK8 in module.directives) { configuration.addJvmClasspathRoot(ForTestCompileRuntime.runtimeJarForTestsWithJdk8()) } - if (JvmEnvironmentConfigurationDirectives.WITH_FOREIGN_ANNOTATIONS in registeredDirectives) { + if (withForeignAnnotations) { val annotationPath = registeredDirectives[ForeignAnnotationsDirectives.ANNOTATIONS_PATH].singleOrNull() - ?: JdkForeignAnnotationType.Jdk8Annotations + ?: JavaForeignAnnotationType.Java8Annotations val javaFilesDir = createTempDirectory().toFile().also { File(annotationPath.path).copyRecursively(it) } - val jar = compileJavaFilesLibraryToJar( + val foreignAnnotationsJar = compileJavaFilesLibraryToJar( javaFilesDir.path, "foreign-annotations", 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()) + } 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) { val javaFilesDir = createTempDirectory().toFile().also { File(JSR_305_TEST_ANNOTATIONS_PATH).copyRecursively(it) } - val jar = compileJavaFilesLibraryToJar( - javaFilesDir.path, - "jsr-305-test-annotations", - assertions = JUnit5Assertions, - extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath } + configuration.addJvmClasspathRoot( + compileJavaFilesLibraryToJar( + javaFilesDir.path, + "jsr-305-test-annotations", + assertions = JUnit5Assertions, + extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath } + ) ) - configuration.addJvmClasspathRoot(jar) + configuration.addJvmClasspathRoot(KtTestUtil.getAnnotationsJar()) } val isIr = module.targetBackend?.isIR == true 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 } - javaSourceFiles.takeIf { it.isNotEmpty() }?.let { javaFiles -> - javaFiles.forEach { testServices.sourceFileProvider.getRealFileForSourceFile(it) } + val javaSourceFiles = module.javaFiles.filter { INCLUDE_JAVA_AS_BINARY !in it.directives } + + if (javaSourceFiles.isNotEmpty() && JvmEnvironmentConfigurationDirectives.SKIP_JAVA_SOURCES !in module.directives && ALL_JAVA_AS_BINARY !in registeredDirectives) { + 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) } } - 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 -> - javaFiles.forEach { testServices.sourceFileProvider.getRealFileForBinaryFile(it) } - val jar = compileJavaFilesLibraryToJar( - testServices.sourceFileProvider.javaBinaryDirectory.path, - "java-binaries", - extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath }, - assertions = JUnit5Assertions - ) - configuration.addJvmClasspathRoot(jar) + addJavaCompiledModulesFromDependentKotlinModules(configuration, configurationKind, module, bySources = false) + + val moduleInfoFiles = javaBinaryFiles.filter { it.name == MODULE_INFO_FILE } + + // TODO: Use module graph to build proper modulepath for each module according cross-module dependencies + if (moduleInfoFiles.isNotEmpty()) { + addJavaBinaryRootsByJavaModules(configuration, configurationKind, moduleInfoFiles) + } else { + configuration.addJvmClasspathRoot( + compileJavaFilesLibraryToJar( + testServices.sourceFileProvider.javaBinaryDirectory.path, + JAVA_BINARIES_JAR_NAME, + extraClasspath = configuration.jvmClasspathRoots.map { it.absolutePath }, + assertions = JUnit5Assertions, + useJava9 = useJava9ToCompileIncludedJavaFiles + ) + ) + } } configuration.registerModuleDependencies(module) @@ -196,9 +240,94 @@ class JvmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfig 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) } + private fun addJavaSourceRootsByJavaModules(configuration: CompilerConfiguration, moduleInfoFiles: List) { + 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 + ) { + 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) { if (DEFAULT_JVM_TARGET_FROM_PROPERTY == null) return val customDefaultTarget = JvmTarget.fromString(DEFAULT_JVM_TARGET_FROM_PROPERTY) diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt index da3dd9280ca..fd2ae4a843d 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/JvmForeignAnnotationsConfigurator.kt @@ -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.RegisteredDirectives 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.utils.JavaTypeEnhancementState import org.jetbrains.kotlin.utils.ReportLevel -import java.io.File enum class JavaForeignAnnotationType(val path: String) { 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) { companion object { - val FOREIGN_ANNOTATIONS_SOURCES_PATH = Annotations.path - val FOREIGN_JDK8_ANNOTATIONS_SOURCES_PATH = Jdk8Annotations.path - val JSR_305_TEST_ANNOTATIONS_PATH = "compiler/testData/diagnostics/helpers/jsr305_test_annotations" + const val JSR_305_TEST_ANNOTATIONS_PATH = "compiler/testData/diagnostics/helpers/jsr305_test_annotations" } override val directivesContainers: List @@ -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) - } -} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/MockLibraryUtilExt.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/MockLibraryUtilExt.kt index 9c7a18975a7..03d39796080 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/MockLibraryUtilExt.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/MockLibraryUtilExt.kt @@ -18,7 +18,15 @@ object MockLibraryUtilExt { extraOptions: List = emptyList(), extraClasspath: List = emptyList(), ): File { - return MockLibraryUtil.compileJavaFilesLibraryToJar(sourcesPath, jarName, addSources, extraOptions, extraClasspath, JUnit4Assertions) + return MockLibraryUtil.compileJavaFilesLibraryToJar( + sourcesPath, + jarName, + addSources, + extraOptions, + extraClasspath, + extraModulepath = listOf(), + JUnit4Assertions + ) } @JvmStatic @@ -39,6 +47,7 @@ object MockLibraryUtilExt { allowKotlinSources, extraOptions, extraClasspath, + extraModulepath = listOf(), useJava9, JUnit4Assertions ) @@ -64,6 +73,7 @@ object MockLibraryUtilExt { allowKotlinSources, extraOptions, extraClasspath, + extraModulepath = listOf(), useJava9, JUnit4Assertions ) diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/JvmCompilationUtils.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/JvmCompilationUtils.kt index fbd55b95280..1b1b1a805ca 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/JvmCompilationUtils.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/JvmCompilationUtils.kt @@ -9,15 +9,15 @@ package org.jetbrains.kotlin.test import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.utils.rethrow -import java.io.File -import java.io.IOException -import java.io.StringWriter +import java.io.* import java.nio.charset.Charset import java.util.* import javax.tools.Diagnostic import javax.tools.DiagnosticCollector import javax.tools.JavaFileObject import javax.tools.ToolProvider +import java.util.stream.Collectors + @JvmOverloads @Throws(IOException::class) @@ -66,13 +66,19 @@ fun compileJavaFilesExternally(files: Collection, options: List, for (file in files) { command.add(file.path) } - return try { - val process = ProcessBuilder().command(command).inheritIO().start() - process.waitFor() - process.exitValue() == 0 - } catch (e: Exception) { - throw rethrow(e) + val process = ProcessBuilder().command(command).start() + val errorsReader = BufferedReader(InputStreamReader(process.errorStream)) + val errors = errorsReader.lines().collect(Collectors.joining(System.lineSeparator())) + + process.waitFor() + + val isSuccess = process.exitValue() == 0 + + if (!isSuccess) { + System.err.println(errors) } + + return isSuccess } private fun errorsToString(diagnosticCollector: DiagnosticCollector, humanReadable: Boolean): String { diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt index 0e7df93f0d0..ce4b662e83e 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/test/MockLibraryUtil.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.preloading.ClassPreloadingUtils import org.jetbrains.kotlin.preloading.Preloader +import org.jetbrains.kotlin.test.KtAssert.assertTrue import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.utils.PathUtil import java.io.ByteArrayOutputStream @@ -36,6 +37,7 @@ object MockLibraryUtil { allowKotlinSources: Boolean = true, extraOptions: List = emptyList(), extraClasspath: List = emptyList(), + extraModulepath: List = emptyList(), useJava9: Boolean = false, assertions: Assertions ): File { @@ -47,6 +49,7 @@ object MockLibraryUtil { allowKotlinSources, extraOptions, extraClasspath, + extraModulepath, useJava9, assertions ) @@ -59,16 +62,22 @@ object MockLibraryUtil { addSources: Boolean = false, extraOptions: List = emptyList(), extraClasspath: List = emptyList(), - assertions: Assertions + extraModulepath: List = emptyList(), + assertions: Assertions, + useJava9: Boolean = false ): File { return compileJvmLibraryToJar( sourcesPath, jarName, addSources, allowKotlinSources = false, - extraClasspath = extraClasspath, extraOptions = extraOptions, - assertions = assertions + extraOptions, + extraClasspath, + extraModulepath, + useJava9, + assertions ) } + @OptIn(ExperimentalStdlibApi::class) @JvmStatic fun compileLibraryToJar( sourcesPath: String, @@ -78,15 +87,18 @@ object MockLibraryUtil { allowKotlinSources: Boolean = true, extraOptions: List = emptyList(), extraClasspath: List = emptyList(), + extraModulepath: List = emptyList(), useJava9: Boolean = false, assertions: Assertions ): File { + assertTrue("Module path can be used only for compilation using javac 9 and higher", useJava9 || extraModulepath.isEmpty()) + val classesDir = File(contentDir, "classes") val srcFile = File(sourcesPath) val kotlinFiles = FileUtil.findFilesByMask(Pattern.compile(".*\\.kt"), srcFile) 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()) } @@ -94,7 +106,6 @@ object MockLibraryUtil { if (javaFiles.isNotEmpty()) { val classpath = mutableListOf() classpath += ForTestCompileRuntime.runtimeJarForTests().path - classpath += KtTestUtil.getAnnotationsJar().path classpath += extraClasspath // 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) } - val options = listOf( - "-classpath", classpath.joinToString(File.pathSeparator), - "-d", classesDir.path - ) + val options = buildList { + add("-classpath") + add(classpath.joinToString(File.pathSeparator)) + add("-d") + add(classesDir.path) + + if (useJava9) { + add("--module-path") + add(extraModulepath.joinToString(File.pathSeparator)) + } + } val compile = if (useJava9) ::compileJavaFilesExternallyWithJava9