[AA] KT-55566 StandaloneProjectFactory: Setup JDK default module roots
- Setup JDK default module roots in `StandaloneProjectFactory` (compare with `KotlinCoreEnvironment`). The implementation is a distilled version of `ClasspathRootsResolver`'s default module handling. - This fixes an issue where some LL FIR tests with JDK 17 and 11 had mismatched types between Kotlin and Java sources. ^KT-55566 fixed
This commit is contained in:
committed by
Space Team
parent
e68111c218
commit
a777ffcd8a
+39
-19
@@ -98,37 +98,42 @@ object StandaloneProjectFactory {
|
|||||||
jdkHome: Path?,
|
jdkHome: Path?,
|
||||||
) {
|
) {
|
||||||
val project = environment.project
|
val project = environment.project
|
||||||
|
val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
|
||||||
|
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.toFile(), null, javaFileManager, project, null)
|
||||||
|
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
||||||
|
|
||||||
val allSourceFileRoots = sourceFiles.map { JavaRoot(it.virtualFile, JavaRoot.RootType.SOURCE) }
|
val allSourceFileRoots = sourceFiles.map { JavaRoot(it.virtualFile, JavaRoot.RootType.SOURCE) }
|
||||||
val libraryRoots = getAllBinaryRoots(modules, environment)
|
val libraryRoots = getAllBinaryRoots(modules, environment)
|
||||||
libraryRoots.forEach { environment.addSourcesToClasspath(it.file) }
|
val jdkRoots = getDefaultJdkModuleRoots(javaModuleFinder, javaModuleGraph)
|
||||||
|
|
||||||
val sourceAndLibraryRoots = buildList {
|
val rootsWithSingleJavaFileRoots = buildList {
|
||||||
addAll(libraryRoots)
|
addAll(libraryRoots)
|
||||||
addAll(allSourceFileRoots)
|
addAll(allSourceFileRoots)
|
||||||
|
addAll(jdkRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
val (roots, singleJavaFileRoots) =
|
val (roots, singleJavaFileRoots) =
|
||||||
sourceAndLibraryRoots.partition { (file) -> file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION }
|
rootsWithSingleJavaFileRoots.partition { (file) -> file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION }
|
||||||
|
|
||||||
val javaFileManager = project.getService(JavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
|
|
||||||
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.toFile(), null, javaFileManager, project, null)
|
|
||||||
|
|
||||||
val corePackageIndex = project.getService(PackageIndex::class.java) as CorePackageIndex
|
val corePackageIndex = project.getService(PackageIndex::class.java) as CorePackageIndex
|
||||||
val rootsIndex = JvmDependenciesDynamicCompoundIndex().apply {
|
val rootsIndex = JvmDependenciesDynamicCompoundIndex().apply {
|
||||||
addIndex(JvmDependenciesIndexImpl(roots))
|
addIndex(JvmDependenciesIndexImpl(roots))
|
||||||
indexedRoots.forEach { javaRoot ->
|
indexedRoots.forEach { javaRoot ->
|
||||||
if (javaRoot.file.isDirectory && javaRoot.type == JavaRoot.RootType.SOURCE) {
|
if (javaRoot.file.isDirectory) {
|
||||||
// NB: [JavaCoreProjectEnvironment#addSourcesToClasspath] calls:
|
if (javaRoot.type == JavaRoot.RootType.SOURCE) {
|
||||||
// 1) [CoreJavaFileManager#addToClasspath], which is used to look up Java roots;
|
// NB: [JavaCoreProjectEnvironment#addSourcesToClasspath] calls:
|
||||||
// 2) [CorePackageIndex#addToClasspath], which populates [PackageIndex]; and
|
// 1) [CoreJavaFileManager#addToClasspath], which is used to look up Java roots;
|
||||||
// 3) [FileIndexFacade#addLibraryRoot], which conflicts with this SOURCE root when generating a library scope.
|
// 2) [CorePackageIndex#addToClasspath], which populates [PackageIndex]; and
|
||||||
// Thus, here we manually call first two, which are used to:
|
// 3) [FileIndexFacade#addLibraryRoot], which conflicts with this SOURCE root when generating a library scope.
|
||||||
// 1) create [PsiPackage] as a package resolution result; and
|
// Thus, here we manually call first two, which are used to:
|
||||||
// 2) find directories by package name.
|
// 1) create [PsiPackage] as a package resolution result; and
|
||||||
// With both supports, annotations defined in package-info.java can be properly propagated.
|
// 2) find directories by package name.
|
||||||
javaFileManager.addToClasspath(javaRoot.file)
|
// With both supports, annotations defined in package-info.java can be properly propagated.
|
||||||
corePackageIndex.addToClasspath(javaRoot.file)
|
javaFileManager.addToClasspath(javaRoot.file)
|
||||||
|
corePackageIndex.addToClasspath(javaRoot.file)
|
||||||
|
} else {
|
||||||
|
environment.addSourcesToClasspath(javaRoot.file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +141,7 @@ object StandaloneProjectFactory {
|
|||||||
javaFileManager.initialize(
|
javaFileManager.initialize(
|
||||||
rootsIndex,
|
rootsIndex,
|
||||||
listOf(
|
listOf(
|
||||||
createPackagePartsProvider(project, libraryRoots, languageVersionSettings)
|
createPackagePartsProvider(project, libraryRoots + jdkRoots, languageVersionSettings)
|
||||||
.invoke(ProjectScope.getLibrariesScope(project))
|
.invoke(ProjectScope.getLibrariesScope(project))
|
||||||
),
|
),
|
||||||
SingleJavaFileRootsIndex(singleJavaFileRoots),
|
SingleJavaFileRootsIndex(singleJavaFileRoots),
|
||||||
@@ -145,7 +150,7 @@ object StandaloneProjectFactory {
|
|||||||
|
|
||||||
project.registerService(
|
project.registerService(
|
||||||
JavaModuleResolver::class.java,
|
JavaModuleResolver::class.java,
|
||||||
CliJavaModuleResolver(JavaModuleGraph(javaModuleFinder), emptyList(), javaModuleFinder.systemModules.toList(), project)
|
CliJavaModuleResolver(javaModuleGraph, emptyList(), javaModuleFinder.systemModules.toList(), project)
|
||||||
)
|
)
|
||||||
|
|
||||||
val finderFactory = CliVirtualFileFinderFactory(rootsIndex, false)
|
val finderFactory = CliVirtualFileFinderFactory(rootsIndex, false)
|
||||||
@@ -154,6 +159,21 @@ object StandaloneProjectFactory {
|
|||||||
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
|
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the [JavaRoot]s of the JDK's default modules.
|
||||||
|
*
|
||||||
|
* @see ClasspathRootsResolver.addModularRoots
|
||||||
|
*/
|
||||||
|
private fun getDefaultJdkModuleRoots(javaModuleFinder: CliJavaModuleFinder, javaModuleGraph: JavaModuleGraph): List<JavaRoot> {
|
||||||
|
// In contrast to `ClasspathRootsResolver.addModularRoots`, we do not need to handle automatic Java modules because JDK modules
|
||||||
|
// aren't automatic.
|
||||||
|
return javaModuleGraph.getAllDependencies(javaModuleFinder.computeDefaultRootModules()).flatMap { moduleName ->
|
||||||
|
val module = javaModuleFinder.findModule(moduleName) ?: return@flatMap emptyList<JavaRoot>()
|
||||||
|
val result = module.getJavaModuleRoots()
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note that [findJvmRootsForJavaFiles] parses the given [files] because it needs access to each file's package name. To avoid parsing
|
* Note that [findJvmRootsForJavaFiles] parses the given [files] because it needs access to each file's package name. To avoid parsing
|
||||||
* errors, [registerJavaPsiFacade] ensures that the Java language level is configured before [findJvmRootsForJavaFiles] is called.
|
* errors, [registerJavaPsiFacade] ensures that the Java language level is configured before [findJvmRootsForJavaFiles] is called.
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ class ClasspathRootsResolver(
|
|||||||
val rootModules = when {
|
val rootModules = when {
|
||||||
sourceModule != null -> listOf(sourceModule.name) + additionalModules
|
sourceModule != null -> listOf(sourceModule.name) + additionalModules
|
||||||
addAllModulePathToRoots -> modules.map(JavaModule::name)
|
addAllModulePathToRoots -> modules.map(JavaModule::name)
|
||||||
else -> computeDefaultRootModules() + additionalModules
|
else -> javaModuleFinder.computeDefaultRootModules() + additionalModules
|
||||||
}
|
}
|
||||||
|
|
||||||
val allDependencies = javaModuleGraph.getAllDependencies(rootModules)
|
val allDependencies = javaModuleGraph.getAllDependencies(rootModules)
|
||||||
@@ -282,14 +282,7 @@ class ClasspathRootsResolver(
|
|||||||
if (module == null) {
|
if (module == null) {
|
||||||
report(ERROR, "Module $moduleName cannot be found in the module graph")
|
report(ERROR, "Module $moduleName cannot be found in the module graph")
|
||||||
} else {
|
} else {
|
||||||
module.moduleRoots.mapTo(result) { (root, isBinary, isBinarySignature) ->
|
result.addAll(module.getJavaModuleRoots())
|
||||||
val type = when {
|
|
||||||
isBinarySignature -> JavaRoot.RootType.BINARY_SIG
|
|
||||||
isBinary -> JavaRoot.RootType.BINARY
|
|
||||||
else -> JavaRoot.RootType.SOURCE
|
|
||||||
}
|
|
||||||
JavaRoot(root, type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,40 +296,6 @@ class ClasspathRootsResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See http://openjdk.java.net/jeps/261
|
|
||||||
private fun computeDefaultRootModules(): List<String> {
|
|
||||||
val result = arrayListOf<String>()
|
|
||||||
|
|
||||||
val systemModules = javaModuleFinder.systemModules.associateBy(JavaModule::name)
|
|
||||||
val javaSeExists = "java.se" in systemModules
|
|
||||||
if (javaSeExists) {
|
|
||||||
// The java.se module is a root, if it exists.
|
|
||||||
result.add("java.se")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun JavaModule.Explicit.exportsAtLeastOnePackageUnqualified(): Boolean = moduleInfo.exports.any { it.toModules.isEmpty() }
|
|
||||||
|
|
||||||
if (!javaSeExists) {
|
|
||||||
// If it does not exist then every java.* module on the upgrade module path or among the system modules
|
|
||||||
// that exports at least one package, without qualification, is a root.
|
|
||||||
for ((name, module) in systemModules) {
|
|
||||||
if (name.startsWith("java.") && module.exportsAtLeastOnePackageUnqualified()) {
|
|
||||||
result.add(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((name, module) in systemModules) {
|
|
||||||
// Every non-java.* module on the upgrade module path or among the system modules that exports at least one package,
|
|
||||||
// without qualification, is also a root.
|
|
||||||
if (!name.startsWith("java.") && module.exportsAtLeastOnePackageUnqualified()) {
|
|
||||||
result.add(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun report(severity: CompilerMessageSeverity, message: String, file: VirtualFile? = null) {
|
private fun report(severity: CompilerMessageSeverity, message: String, file: VirtualFile? = null) {
|
||||||
if (messageCollector == null) {
|
if (messageCollector == null) {
|
||||||
throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)")
|
throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)")
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.cli.jvm.compiler
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
|
||||||
|
|
||||||
|
fun JavaModule.getJavaModuleRoots(): List<JavaRoot> =
|
||||||
|
moduleRoots.map { (root, isBinary, isBinarySignature) ->
|
||||||
|
val type = when {
|
||||||
|
isBinarySignature -> JavaRoot.RootType.BINARY_SIG
|
||||||
|
isBinary -> JavaRoot.RootType.BINARY
|
||||||
|
else -> JavaRoot.RootType.SOURCE
|
||||||
|
}
|
||||||
|
JavaRoot(root, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the JDK's default root modules. See [JEP 261: Module System](http://openjdk.java.net/jeps/261).
|
||||||
|
*/
|
||||||
|
fun CliJavaModuleFinder.computeDefaultRootModules(): List<String> {
|
||||||
|
val result = arrayListOf<String>()
|
||||||
|
|
||||||
|
val systemModules = systemModules.associateBy(JavaModule::name)
|
||||||
|
val javaSeExists = "java.se" in systemModules
|
||||||
|
if (javaSeExists) {
|
||||||
|
// The java.se module is a root, if it exists.
|
||||||
|
result.add("java.se")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JavaModule.Explicit.exportsAtLeastOnePackageUnqualified(): Boolean = moduleInfo.exports.any { it.toModules.isEmpty() }
|
||||||
|
|
||||||
|
if (!javaSeExists) {
|
||||||
|
// If it does not exist then every java.* module on the upgrade module path or among the system modules
|
||||||
|
// that exports at least one package, without qualification, is a root.
|
||||||
|
for ((name, module) in systemModules) {
|
||||||
|
if (name.startsWith("java.") && module.exportsAtLeastOnePackageUnqualified()) {
|
||||||
|
result.add(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((name, module) in systemModules) {
|
||||||
|
// Every non-java.* module on the upgrade module path or among the system modules that exports at least one package,
|
||||||
|
// without qualification, is also a root.
|
||||||
|
if (!name.startsWith("java.") && module.exportsAtLeastOnePackageUnqualified()) {
|
||||||
|
result.add(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDE_IGNORE
|
|
||||||
// FIR_IDENTICAL
|
// FIR_IDENTICAL
|
||||||
// JDK_KIND: FULL_JDK_11
|
// JDK_KIND: FULL_JDK_11
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// !API_VERSION: 1.5
|
// !API_VERSION: 1.5
|
||||||
// !LANGUAGE: -JvmRecordSupport
|
// !LANGUAGE: -JvmRecordSupport
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// !API_VERSION: 1.5
|
// !API_VERSION: 1.5
|
||||||
// !LANGUAGE: -JvmRecordSupport
|
// !LANGUAGE: -JvmRecordSupport
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
|
|||||||
Vendored
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_IDENTICAL
|
// FIR_IDENTICAL
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// API_VERSION: 1.5
|
// API_VERSION: 1.5
|
||||||
// LANGUAGE: +JvmRecordSupport
|
// LANGUAGE: +JvmRecordSupport
|
||||||
// SCOPE_DUMP: MyRecord:x
|
// SCOPE_DUMP: MyRecord:x
|
||||||
|
|||||||
Vendored
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// !API_VERSION: 1.5
|
// !API_VERSION: 1.5
|
||||||
// !LANGUAGE: +JvmRecordSupport
|
// !LANGUAGE: +JvmRecordSupport
|
||||||
// JVM_TARGET: 17
|
// JVM_TARGET: 17
|
||||||
|
|||||||
Vendored
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// !API_VERSION: 1.5
|
// !API_VERSION: 1.5
|
||||||
// !LANGUAGE: +JvmRecordSupport
|
// !LANGUAGE: +JvmRecordSupport
|
||||||
// JVM_TARGET: 17
|
// JVM_TARGET: 17
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_IDENTICAL
|
// FIR_IDENTICAL
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// API_VERSION: 1.5
|
// API_VERSION: 1.5
|
||||||
// LANGUAGE: +JvmRecordSupport
|
// LANGUAGE: +JvmRecordSupport
|
||||||
// SCOPE_DUMP: MyRecord:x;y;z
|
// SCOPE_DUMP: MyRecord:x;y;z
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// !API_VERSION: 1.5
|
// !API_VERSION: 1.5
|
||||||
// !LANGUAGE: +JvmRecordSupport
|
// !LANGUAGE: +JvmRecordSupport
|
||||||
// JVM_TARGET: 17
|
// JVM_TARGET: 17
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
// FIR_DISABLE_LAZY_RESOLVE_CHECKS
|
||||||
// FIR_IDE_IGNORE
|
|
||||||
// !API_VERSION: 1.5
|
// !API_VERSION: 1.5
|
||||||
// !LANGUAGE: +JvmRecordSupport
|
// !LANGUAGE: +JvmRecordSupport
|
||||||
// JVM_TARGET: 17
|
// JVM_TARGET: 17
|
||||||
|
|||||||
Reference in New Issue
Block a user