Advanced modules supports

#KT-29974
This commit is contained in:
Mikhael Bogdanov
2021-11-08 12:14:17 +01:00
committed by Space
parent ae81aaa7b0
commit e5e3e9d326
4 changed files with 73 additions and 18 deletions
@@ -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
)
)
}
}
}
@@ -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) =
@@ -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<JavaModule>
get() = systemModules + userModules.values
val ctSymModules by lazy {
collectModuleRoots(releaseTarget)
}
val systemModules: Sequence<JavaModule.Explicit>
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<VirtualFile> {
fun listFoldersForRelease(): List<VirtualFile> {
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<String, VirtualFile> {
if (!hasCtSymFile()) return emptyMap()
val result = mutableMapOf<String, VirtualFile>()
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)
}