From e5e3e9d326bec8c6946f58b0a630f6b198e785be Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Mon, 8 Nov 2021 12:14:17 +0100 Subject: [PATCH] Advanced modules supports #KT-29974 --- .../jvm/compiler/ClasspathRootsResolver.kt | 11 ++- .../cli/jvm/compiler/KotlinCoreEnvironment.kt | 6 +- .../cli/jvm/modules/CliJavaModuleFinder.kt | 72 +++++++++++++++---- .../kotlin/resolve/jvm/modules/JavaModule.kt | 2 +- 4 files changed, 73 insertions(+), 18 deletions(-) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt index 6540028f2c6..0152c198859 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt @@ -129,7 +129,7 @@ class ClasspathRootsResolver( addModularRoots(modules, result) } else { //TODO: see also `addJvmSdkRoots` usages, some refactoring is required with moving such logic into one place - val listFoldersForRelease = javaModuleFinder.listFoldersForRelease(release) + val listFoldersForRelease = javaModuleFinder.listFoldersForRelease() listFoldersForRelease.forEach { result += JavaRoot(it, JavaRoot.RootType.BINARY_SIG) } @@ -285,8 +285,13 @@ class ClasspathRootsResolver( if (module == null) { report(ERROR, "Module $moduleName cannot be found in the module graph") } else { - for ((root, isBinary) in module.moduleRoots) { - result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE)) + for ((root, isBinary, isBinarySignature) in module.moduleRoots) { + result.add( + JavaRoot( + root, + if (isBinarySignature) JavaRoot.RootType.BINARY_SIG else if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE + ) + ) } } } 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 d6146b525d4..128b03f38d3 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 @@ -240,6 +240,7 @@ class KotlinCoreEnvironment private constructor( val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME) val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL) + val releaseTarget = configuration.get(JVMConfigurationKeys.RELEASE, 0) val javaModuleFinder = CliJavaModuleFinder( jdkHome?.path?.let { path -> VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL).findFileByPath(path) @@ -248,7 +249,8 @@ class KotlinCoreEnvironment private constructor( jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR) }, javaFileManager, - project + project, + releaseTarget ) val outputDirectory = @@ -264,7 +266,7 @@ class KotlinCoreEnvironment private constructor( !configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE), outputDirectory?.let(this::findLocalFile), javaFileManager, - configuration.get(JVMConfigurationKeys.RELEASE, 0) + releaseTarget ) val (initialRoots, javaModules) = diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt index c5507f3c7b8..87e860623a7 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleFinder.kt @@ -32,7 +32,8 @@ class CliJavaModuleFinder( jdkRootFile: VirtualFile?, jrtFileSystemRoot: VirtualFile?, private val javaFileManager: KotlinCliJavaFileManager, - project: Project + project: Project, + private val releaseTarget: Int ) : JavaModuleFinder { private val modulesRoot = jrtFileSystemRoot?.findChild("modules") private val ctSymFile = jdkRootFile?.findChild("lib")?.findChild("ct.sym") @@ -44,7 +45,7 @@ class CliJavaModuleFinder( //TODO: add test with -jdk-home // Observe all JDK codes from folder name chars in ct.sym file, // there should be maximal one corresponding to used compilation JDK - listFoldersInCtSym()?.children?.maxOf { + ctSymRootFolder()?.children?.maxOf { if (it.name == "META-INF") -1 else it.name.substringBeforeLast("-modules").maxOf { char -> char.toString().toIntOrNull(36) ?: -1 @@ -52,6 +53,12 @@ class CliJavaModuleFinder( } ?: -1 } + private val isJDK12OrLater + get() = compilationJdkVersion >= 12 + + private val useLastJdkApi: Boolean + get() = releaseTarget == 0 || releaseTarget == compilationJdkVersion + fun addUserModule(module: JavaModule) { userModules.putIfAbsent(module.name, module) } @@ -59,16 +66,34 @@ class CliJavaModuleFinder( val allObservableModules: Sequence get() = systemModules + userModules.values + val ctSymModules by lazy { + collectModuleRoots(releaseTarget) + } + val systemModules: Sequence - get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule) + get() = if (useLastJdkApi) modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule) else + ctSymModules.values.asSequence().mapNotNull { findSystemModule(it, true) } override fun findModule(name: String): JavaModule? = - modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name] + when { + useLastJdkApi -> modulesRoot?.findChild(name)?.let(this::findSystemModule) + else -> ctSymModules[name]?.let { findSystemModule(it, true) } + } ?: userModules[name] - private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? { - val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null + private fun findSystemModule(moduleRoot: VirtualFile, useSig: Boolean = false): JavaModule.Explicit? { + val file = moduleRoot.findChild(if (useSig) PsiJavaModule.MODULE_INFO_CLASS + ".sig" else PsiJavaModule.MODULE_INFO_CLS_FILE) + ?: return null val moduleInfo = JavaModuleInfo.read(file, javaFileManager, allScope) ?: return null - return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file) + return JavaModule.Explicit( + moduleInfo, + when { + useLastJdkApi -> listOf(JavaModule.Root(moduleRoot, isBinary = true, isBinarySignature = useSig)) + //TODO: distinguish roots from different modules under JDK 10-11 + useSig -> listFoldersForRelease().map { JavaModule.Root(it, isBinary = true, isBinarySignature = true) } + else -> error("Can't find ${moduleRoot.path} module") + }, + file, true + ) } private fun codeFor(release: Int): String = release.toString(36).toUpperCase() @@ -78,11 +103,10 @@ class CliJavaModuleFinder( private fun hasCtSymFile() = ctSymFile != null && ctSymFile.isValid - fun listFoldersForRelease(release: Int): List { + fun listFoldersForRelease(): List { if (!hasCtSymFile()) return emptyList() - val findFileByPath = listFoldersInCtSym() ?: return emptyList() - val isJDK12OrLater = compilationJdkVersion >= 12 - return findFileByPath.children.filter { matchesRelease(it.name, release) }.flatMap { + val root = ctSymRootFolder() ?: return emptyList() + return root.children.filter { matchesRelease(it.name, releaseTarget) }.flatMap { if (isJDK12OrLater) it.children.toList() else { @@ -91,6 +115,30 @@ class CliJavaModuleFinder( } } - private fun listFoldersInCtSym() = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JAR_PROTOCOL) + private fun collectModuleRoots(release: Int): Map { + if (!hasCtSymFile()) return emptyMap() + val result = mutableMapOf() + val root = ctSymRootFolder() ?: return emptyMap() + + + if (isJDK12OrLater) { + listFoldersForRelease().forEach { modulesRoot -> + modulesRoot.findChild("module-info.sig")?.let { + result[modulesRoot.name] = modulesRoot + } + } + } else { + if (releaseTarget > 8) { + val moduleSigs = root.findChild(codeFor(release) + if (!isJDK12OrLater) "-modules" else "") + ?: error("Can't find modules signatures in `ct.sym` file for `-release $release` in ${ctSymFile?.path}") + moduleSigs.children.forEach { + result[it.name] = it + } + } + } + return result + } + + private fun ctSymRootFolder() = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JAR_PROTOCOL) ?.findFileByPath(ctSymFile!!.path + URLUtil.JAR_SEPARATOR) } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt index 9293303d49a..a959d5627ad 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModule.kt @@ -66,7 +66,7 @@ interface JavaModule { */ fun exportsTo(packageFqName: FqName, moduleName: String): Boolean - data class Root(val file: VirtualFile, val isBinary: Boolean) + data class Root(val file: VirtualFile, val isBinary: Boolean, val isBinarySignature: Boolean = false) class Automatic(override val name: String, override val moduleRoots: List) : JavaModule { override val moduleInfoFile: VirtualFile? get() = null