AA: restore JavaRoot from binary roots in JDK module

This commit is contained in:
Jinseong Jeon
2022-06-12 00:40:20 -07:00
committed by Ilya Kirillov
parent 911963bafd
commit 814920b344
2 changed files with 42 additions and 10 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndexImpl
import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleResolver
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
@@ -155,16 +156,7 @@ object StandaloneProjectFactory {
environment: KotlinCoreProjectEnvironment
): List<JavaRoot> = withAllTransitiveDependencies(modules)
.filterIsInstance<KtBinaryModule>()
.flatMap { it.getBinaryRoots() }
.mapNotNull { path ->
val pathString = path.toAbsolutePath().toString()
val jar =
if (pathString.endsWith(JAR_PROTOCOL))
environment.environment.jarFileSystem.findFileByPath(pathString + JAR_SEPARATOR)
else null
if (jar == null) return@mapNotNull null
JavaRoot(jar, JavaRoot.RootType.BINARY)
}
.flatMap { it.getJavaRoots(environment) }
private fun withAllTransitiveDependencies(ktModules: List<KtModule>): List<KtModule> {
val visited = hashSetOf<KtModule>()
@@ -194,6 +186,45 @@ object StandaloneProjectFactory {
}
}
private fun KtBinaryModule.getJavaRoots(
environment: KotlinCoreProjectEnvironment,
): List<JavaRoot> {
return buildList {
getBinaryRoots().forEach { path ->
val pathString = path.toAbsolutePath().toString()
when {
pathString.endsWith(JAR_PROTOCOL) -> {
environment.environment.jarFileSystem.findFileByPath(pathString + JAR_SEPARATOR)
}
pathString.contains(JAR_SEPARATOR) -> {
environment.environment.jrtFileSystem?.findFileByPath(adjustModulePath(pathString))
}
else -> {
null
}
}?.let { root ->
add(JavaRoot(root, JavaRoot.RootType.BINARY))
}
}
}
}
private fun adjustModulePath(pathString: String): String {
return if (pathString.contains(JAR_SEPARATOR)) {
// URLs loaded from JDK point to module names in a JRT protocol format,
// e.g., "jrt:///path/to/jdk/home!/java.base" (JRT protocol prefix + JDK home path + JAR separator + module name)
// After protocol erasure, we will see "/path/to/jdk/home!/java.base" as a binary root.
// CoreJrtFileSystem.CoreJrtHandler#findFile, which uses Path#resolve, finds a virtual file path to the file itself,
// e.g., "/path/to/jdk/home!/modules/java.base". (JDK home path + JAR separator + actual file path)
// To work with that JRT handler, a hacky workaround here is to add "modules" before the module name so that it can
// find the actual file path.
// See [LLFirJavaFacadeForBinaries#getBinaryPath] for a similar hack.
val (libHomePath, pathInImage) = CoreJrtFileSystem.splitPath(pathString)
libHomePath + JAR_SEPARATOR + "modules/$pathInImage"
} else
pathString
}
fun createPackagePartsProvider(
project: MockProject,
libraryRoots: List<JavaRoot>,
@@ -48,6 +48,7 @@ internal class LLFirJavaFacadeForBinaries(
// To work with LibraryPathFilter, a hacky workaround here is to remove "modules/" from actual file path.
// e.g. "/path/to/jdk/home!/java.base/java/lang/Object.class", which, from Path viewpoint, belongs to "/java.base",
// after splitting at the JAR separator, in a similar way.
// See [StandaloneProjectFactory#getAllBinaryRoots] for a similar hack.
Paths.get(path.replace("modules/", ""))
}
else ->