Support compilation against modular JDK (9+)
For more information about the "jrt" file system, see http://openjdk.java.net/jeps/220 and https://bugs.openjdk.java.net/browse/JDK-8066492. This commit fixes DiagnosticsWithJdk9TestGenerated.testKt11167 #KT-11167 Fixed
This commit is contained in:
@@ -343,24 +343,28 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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<KtFile>): 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<ContentRoot>.classpathRoots(): List<JavaRoot> =
|
||||
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<ContentRoot>): List<JavaRoot> {
|
||||
val result = mutableListOf<JavaRoot>()
|
||||
|
||||
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<JavaRoot>) {
|
||||
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<ContentRoot>): List<File>? {
|
||||
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<String>): 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)
|
||||
|
||||
@@ -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<String, Nothing>(), classLoader)
|
||||
}
|
||||
return CoreJrtFileSystem(fileSystem)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<out VirtualFile> {
|
||||
val paths = try {
|
||||
Files.newDirectoryStream(path).use(Iterable<Path>::toList)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
emptyList<Path>()
|
||||
}
|
||||
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()
|
||||
}
|
||||
@@ -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<Requires>,
|
||||
val exports: List<Exports>
|
||||
) {
|
||||
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<String>)
|
||||
|
||||
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<Requires>()
|
||||
val exports = arrayListOf<Exports>()
|
||||
|
||||
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<String>?) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String>): List<String> {
|
||||
val visited = linkedSetOf<String>()
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,9 @@ public class JVMConfigurationKeys {
|
||||
public static final CompilerConfigurationKey<Boolean> INCLUDE_RUNTIME =
|
||||
CompilerConfigurationKey.create("include runtime to the resulting .jar");
|
||||
|
||||
public static final CompilerConfigurationKey<File> JDK_HOME =
|
||||
CompilerConfigurationKey.create("jdk home");
|
||||
|
||||
public static final CompilerConfigurationKey<List<KotlinScriptDefinition>> SCRIPT_DEFINITIONS =
|
||||
CompilerConfigurationKey.create("script definitions");
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user