diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index 612f27dff18..2a49a527d13 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -343,24 +343,28 @@ class K2JVMCompiler : CLICompiler() { private fun setupJdkClasspathRoots(arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration, messageCollector: MessageCollector): ExitCode { try { - if (!arguments.noJdk) { - if (arguments.jdkHome != null) { - messageCollector.report(LOGGING, "Using JDK home directory ${arguments.jdkHome}") - val classesRoots = PathUtil.getJdkClassesRoots(File(arguments.jdkHome)) - if (classesRoots.isEmpty()) { - messageCollector.report(ERROR, "No class roots are found in the JDK path: ${arguments.jdkHome}") - return COMPILATION_ERROR - } - configuration.addJvmClasspathRoots(classesRoots) - } - else { - configuration.addJvmClasspathRoots(PathUtil.getJdkClassesRootsFromCurrentJre()) - } - } - else { + if (arguments.noJdk) { if (arguments.jdkHome != null) { messageCollector.report(STRONG_WARNING, "The '-jdk-home' option is ignored because '-no-jdk' is specified") } + return OK + } + + if (arguments.jdkHome != null) { + val jdkHome = File(arguments.jdkHome) + configuration.put(JVMConfigurationKeys.JDK_HOME, jdkHome) + val classesRoots = PathUtil.getJdkClassesRoots(jdkHome) + configuration.addJvmClasspathRoots(classesRoots) + + messageCollector.report(LOGGING, "Using JDK home directory $jdkHome") + if (classesRoots.isEmpty()) { + messageCollector.report(ERROR, "No class roots are found in the JDK path: $jdkHome") + return COMPILATION_ERROR + } + } + else { + configuration.put(JVMConfigurationKeys.JDK_HOME, File(System.getProperty("java.home"))) + configuration.addJvmClasspathRoots(PathUtil.getJdkClassesRootsFromCurrentJre()) } } catch (t: Throwable) { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index dde3e90d06b..d02ecec08d0 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -43,8 +43,7 @@ import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.vfs.PersistentFSConstants -import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.* import com.intellij.openapi.vfs.impl.ZipHandler import com.intellij.psi.FileContextProvider import com.intellij.psi.PsiElementFinder @@ -68,8 +67,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.* import org.jetbrains.kotlin.cli.common.toBooleanLenient import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot @@ -80,6 +78,9 @@ import org.jetbrains.kotlin.cli.jvm.index.JavaRoot import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesDynamicCompoundIndex import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex import org.jetbrains.kotlin.cli.jvm.index.JvmUpdateableDependenciesIndexFactory +import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem +import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleInfo +import org.jetbrains.kotlin.cli.jvm.modules.ModuleGraph import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar @@ -191,7 +192,7 @@ class KotlinCoreEnvironment private constructor( } } - val initialRoots = configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS).classpathRoots() + val initialRoots = convertClasspathRoots(configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS)) if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK)) { val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) @@ -230,34 +231,65 @@ class KotlinCoreEnvironment private constructor( val sourceLinesOfCode: Int by lazy { countLinesOfCode(sourceFiles) } fun countLinesOfCode(sourceFiles: List): Int = - sourceFiles.sumBy { - val text = it.text - StringUtil.getLineBreakCount(it.text) + (if (StringUtil.endsWithLineBreak(text)) 0 else 1) + sourceFiles.sumBy { sourceFile -> + val text = sourceFile.text + StringUtil.getLineBreakCount(text) + (if (StringUtil.endsWithLineBreak(text)) 0 else 1) } - private fun Iterable.classpathRoots(): List = - filterIsInstance(JvmContentRoot::class.java).mapNotNull { javaRoot -> - contentRootToVirtualFile(javaRoot)?.let { virtualFile -> - val prefixPackageFqName = (javaRoot as? JavaSourceRoot)?.packagePrefix?.let { - if (isValidJavaFqName(it)) { - FqName(it) - } - else { - report(STRONG_WARNING, "Invalid package prefix name is ignored: $it") - null - } - } + private fun convertClasspathRoots(roots: Iterable): List { + val result = mutableListOf() - val rootType = when (javaRoot) { - is JavaSourceRoot -> JavaRoot.RootType.SOURCE - is JvmClasspathRoot -> JavaRoot.RootType.BINARY - else -> throw IllegalStateException() - } + for (javaRoot in roots) { + if (javaRoot !is JvmContentRoot) continue + val virtualFile = contentRootToVirtualFile(javaRoot) ?: continue - JavaRoot(virtualFile, rootType, prefixPackageFqName) + val prefixPackageFqName = (javaRoot as? JavaSourceRoot)?.packagePrefix?.let { prefix -> + if (isValidJavaFqName(prefix)) FqName(prefix) + else null.also { + report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix") } } + val rootType = when (javaRoot) { + is JavaSourceRoot -> JavaRoot.RootType.SOURCE + is JvmClasspathRoot -> JavaRoot.RootType.BINARY + else -> error("Unknown root type: $javaRoot") + } + + result.add(JavaRoot(virtualFile, rootType, prefixPackageFqName)) + } + + val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL) + if (jrtFileSystem != null) { + addModularJdkRoots(jrtFileSystem, result) + } + + return result + } + + private fun addModularJdkRoots(fileSystem: VirtualFileSystem, result: MutableList) { + val graph = ModuleGraph { moduleName -> + fileSystem.findFileByPath("/modules/$moduleName/module-info.class")?.let((JavaModuleInfo)::read) ?: run { + report(ERROR, "Module $moduleName cannot be found in the Java runtime image") + JavaModuleInfo(moduleName, emptyList(), emptyList()) + } + } + + val allReachableModules = graph.getAllReachable(listOf("java.base", "java.se")).also { modules -> + report(LOGGING, "Loading modules exported by java.se: $modules") + } + + for (moduleName in allReachableModules) { + val root = fileSystem.findFileByPath("/modules/$moduleName") + if (root == null) { + report(ERROR, "Module $moduleName cannot be found in the module graph") + } + else { + result.add(JavaRoot(root, JavaRoot.RootType.BINARY)) + } + } + } + private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) { index.indexedRoots.forEach { projectEnvironment.addSourcesToClasspath(it.file) @@ -273,10 +305,10 @@ class KotlinCoreEnvironment private constructor( } fun updateClasspath(roots: List): List? { - return rootsIndex.addNewIndexForRoots(roots.classpathRoots())?.let { - updateClasspathFromRootsIndex(it) - it.indexedRoots.mapNotNull { File(it.file.path.substringBefore(URLUtil.JAR_SEPARATOR)) }.toList() - } ?: emptyList() + return rootsIndex.addNewIndexForRoots(convertClasspathRoots(roots))?.let { newIndex -> + updateClasspathFromRootsIndex(newIndex) + newIndex.indexedRoots.mapNotNull { (file) -> File(file.path.substringBefore(URLUtil.JAR_SEPARATOR)) }.toList() + }.orEmpty() } @Suppress("unused") // used externally @@ -415,7 +447,12 @@ class KotlinCoreEnvironment private constructor( private fun createApplicationEnvironment(parentDisposable: Disposable, configuration: CompilerConfiguration, configFilePaths: List): JavaCoreApplicationEnvironment { Extensions.cleanRootArea(parentDisposable) registerAppExtensionPoints() - val applicationEnvironment = JavaCoreApplicationEnvironment(parentDisposable) + val applicationEnvironment = object : JavaCoreApplicationEnvironment(parentDisposable) { + override fun createJrtFileSystem(): VirtualFileSystem? { + val jdkHome = configuration[JVMConfigurationKeys.JDK_HOME] ?: return null + return CoreJrtFileSystem.create(jdkHome) + } + } for (configPath in configFilePaths) { registerApplicationExtensionPointsAndExtensionsFrom(configuration, configPath) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CoreJrtFileSystem.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CoreJrtFileSystem.kt new file mode 100644 index 00000000000..e2ac8928428 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CoreJrtFileSystem.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.cli.jvm.modules + +import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.vfs.DeprecatedVirtualFileSystem +import com.intellij.openapi.vfs.StandardFileSystems +import com.intellij.openapi.vfs.VirtualFile +import java.io.File +import java.net.URI +import java.net.URLClassLoader +import java.nio.file.FileSystem +import java.nio.file.FileSystems +import java.nio.file.Files +import java.nio.file.Path + +// There's JrtFileSystem in idea-full which we can't use in the compiler because it depends on NewVirtualFileSystem, absent in intellij-core +class CoreJrtFileSystem(private val fileSystem: FileSystem) : DeprecatedVirtualFileSystem() { + override fun getProtocol(): String = StandardFileSystems.JRT_PROTOCOL + + private fun findFileByPath(path: Path): VirtualFile? = + if (Files.exists(path)) CoreLocalPathVirtualFile(this, path) else null + + override fun findFileByPath(path: String): VirtualFile? = + findFileByPath(fileSystem.getPath(path)) + + override fun refresh(asynchronous: Boolean) {} + + override fun refreshAndFindFileByPath(path: String): VirtualFile? = findFileByPath(path) + + companion object { + fun create(jdkHome: File): CoreJrtFileSystem? { + val rootUri = URI.create(StandardFileSystems.JRT_PROTOCOL + ":/") + val fileSystem = + if (SystemInfo.isJavaVersionAtLeast("9")) { + FileSystems.newFileSystem(rootUri, mapOf("java.home" to jdkHome.absolutePath)) + } + else { + val jrtFsJar = File(jdkHome, "lib/jrt-fs.jar") + if (!jrtFsJar.exists()) return null + + val classLoader = URLClassLoader(arrayOf(jrtFsJar.toURI().toURL()), null) + FileSystems.newFileSystem(rootUri, emptyMap(), classLoader) + } + return CoreJrtFileSystem(fileSystem) + } + } +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CoreLocalPathVirtualFile.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CoreLocalPathVirtualFile.kt new file mode 100644 index 00000000000..1aa4d5bf18c --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CoreLocalPathVirtualFile.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.cli.jvm.modules + +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VfsUtilCore +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileSystem +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.attribute.BasicFileAttributes + +class CoreLocalPathVirtualFile(private val fileSystem: VirtualFileSystem, private val path: Path) : VirtualFile() { + // TODO: catch IOException? + private val attributes: BasicFileAttributes get() = Files.readAttributes(path, BasicFileAttributes::class.java) + + override fun getFileSystem(): VirtualFileSystem = fileSystem + + override fun getName(): String = + path.fileName.toString() + + override fun getPath(): String = + FileUtil.toSystemIndependentName(path.toString()) + + override fun isWritable(): Boolean = false + + override fun isDirectory(): Boolean = Files.isDirectory(path) + + override fun isValid(): Boolean = true + + override fun getParent(): VirtualFile? { + val parentPath = path.parent + return if (parentPath != null) CoreLocalPathVirtualFile(fileSystem, parentPath) else null + } + + override fun getChildren(): Array { + val paths = try { + Files.newDirectoryStream(path).use(Iterable::toList) + } + catch (e: IOException) { + emptyList() + } + return when { + paths.isEmpty() -> VirtualFile.EMPTY_ARRAY + else -> paths.map { path -> CoreLocalPathVirtualFile(fileSystem, path) }.toTypedArray() + } + } + + override fun getOutputStream(requestor: Any, newModificationStamp: Long, newTimeStamp: Long): OutputStream = + throw UnsupportedOperationException() + + override fun contentsToByteArray(): ByteArray = + Files.readAllBytes(path) + + override fun getTimeStamp(): Long = + attributes.lastModifiedTime().toMillis() + + override fun getLength(): Long = attributes.size() + + override fun refresh(asynchronous: Boolean, recursive: Boolean, postRunnable: Runnable?) {} + + override fun getInputStream(): InputStream = + VfsUtilCore.inputStreamSkippingBOM(Files.newInputStream(path).buffered(), this) + + override fun getModificationStamp(): Long = 0 + + override fun equals(other: Any?): Boolean = + other is CoreLocalPathVirtualFile && path == other.path && fileSystem == other.fileSystem + + override fun hashCode(): Int = + path.hashCode() +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/JavaModuleInfo.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/JavaModuleInfo.kt new file mode 100644 index 00000000000..313994cb036 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/JavaModuleInfo.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.cli.jvm.modules + +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.utils.compactIfPossible +import org.jetbrains.org.objectweb.asm.ClassReader +import org.jetbrains.org.objectweb.asm.ClassVisitor +import org.jetbrains.org.objectweb.asm.ModuleVisitor +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Opcodes.ACC_TRANSITIVE +import java.io.IOException + +class JavaModuleInfo( + val moduleName: String, + val requires: List, + val exports: List +) { + data class Requires(val moduleName: String, val flags: Int) { + val isTransitive get() = (flags and ACC_TRANSITIVE) != 0 + } + + data class Exports(val packageFqName: FqName, val flags: Int, val toModules: List) + + override fun toString(): String = + "Module $moduleName (${requires.size} requires, ${exports.size} exports)" + + companion object { + fun read(file: VirtualFile): JavaModuleInfo? { + val contents = try { file.contentsToByteArray() } catch (e: IOException) { return null } + + var moduleName: String? = null + val requires = arrayListOf() + val exports = arrayListOf() + + ClassReader(contents).accept(object : ClassVisitor(Opcodes.ASM6) { + override fun visitModule(name: String, access: Int, version: String?): ModuleVisitor { + moduleName = name + + return object : ModuleVisitor(Opcodes.ASM6) { + override fun visitRequire(module: String, access: Int, version: String?) { + requires.add(Requires(module, access)) + } + + override fun visitExport(packageFqName: String, access: Int, modules: Array?) { + exports.add(Exports(FqName(packageFqName), access, modules?.toList().orEmpty())) + } + } + } + }, ClassReader.SKIP_DEBUG or ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES) + + return if (moduleName != null) + JavaModuleInfo(moduleName!!, requires.compactIfPossible(), exports.compactIfPossible()) + else null + } + } +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/ModuleGraph.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/ModuleGraph.kt new file mode 100644 index 00000000000..ca554eb9306 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/ModuleGraph.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.cli.jvm.modules + +import org.jetbrains.kotlin.storage.LockBasedStorageManager + +class ModuleGraph(getModuleInfo: (String) -> JavaModuleInfo) { + private val moduleInfo: (String) -> JavaModuleInfo = LockBasedStorageManager.NO_LOCKS.createMemoizedFunction(getModuleInfo) + + fun getAllReachable(rootModules: List): List { + val visited = linkedSetOf() + + fun dfs(module: String) { + if (!visited.add(module)) return + for (dependency in moduleInfo(module).requires) { + if (dependency.isTransitive) { + dfs(dependency.moduleName) + } + } + } + + rootModules.forEach(::dfs) + return visited.toList() + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java index 81629b115a6..ae87353713f 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/config/JVMConfigurationKeys.java @@ -39,6 +39,9 @@ public class JVMConfigurationKeys { public static final CompilerConfigurationKey INCLUDE_RUNTIME = CompilerConfigurationKey.create("include runtime to the resulting .jar"); + public static final CompilerConfigurationKey JDK_HOME = + CompilerConfigurationKey.create("jdk home"); + public static final CompilerConfigurationKey> SCRIPT_DEFINITIONS = CompilerConfigurationKey.create("script definitions"); diff --git a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java index 4e5c0b3cfbf..f2767698ad6 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java +++ b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java @@ -49,6 +49,10 @@ import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.analyzer.AnalysisResult; import org.jetbrains.kotlin.builtins.DefaultBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; +import org.jetbrains.kotlin.cli.common.messages.MessageCollector; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.config.JvmContentRootsKt; @@ -428,6 +432,30 @@ public class KotlinTestUtils { public static CompilerConfiguration newConfiguration() { CompilerConfiguration configuration = new CompilerConfiguration(); configuration.put(CommonConfigurationKeys.MODULE_NAME, TEST_MODULE_NAME); + + configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, new MessageCollector() { + @Override + public void clear() { + } + + @Override + public void report( + @NotNull CompilerMessageSeverity severity, @NotNull String message, @Nullable CompilerMessageLocation location + ) { + if (severity == CompilerMessageSeverity.ERROR) { + String prefix = location == null + ? "" + : "(" + location.getPath() + ":" + location.getLine() + ":" + location.getColumn() + ") "; + throw new AssertionError(prefix + message); + } + } + + @Override + public boolean hasErrors() { + return false; + } + }); + return configuration; } @@ -466,7 +494,7 @@ public class KotlinTestUtils { else if (jdkKind == TestJdkKind.FULL_JDK_9) { String jdk9 = System.getenv("JDK_9"); if (jdk9 != null) { - JvmContentRootsKt.addJvmClasspathRoots(configuration, PathUtil.getJdkClassesRootsFromJre(getJreHome(jdk9))); + configuration.put(JVMConfigurationKeys.JDK_HOME, new File(getJreHome(jdk9))); } else { System.err.println("Environment variable JDK_9 is not set, the test will be skipped");