diff --git a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/util/LibraryUtils.kt b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/util/LibraryUtils.kt index 8bf068fdfb1..d53c372fe97 100644 --- a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/util/LibraryUtils.kt +++ b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/util/LibraryUtils.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.analysis.api.impl.base.util import com.intellij.openapi.project.Project +import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile @@ -13,7 +14,9 @@ import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager import com.intellij.util.io.URLUtil.JAR_SEPARATOR +import java.nio.file.Files import java.nio.file.Path +import java.util.Properties object LibraryUtils { /** @@ -83,4 +86,46 @@ object LibraryUtils { ) return files } + + // Copied (and adjusted) from JavaSdkImpl#readModulesFromReleaseFile + private fun readModulesFromReleaseFile(jrtBaseDir: Path): List? { + Files.newInputStream(jrtBaseDir.resolve("release")).use { stream -> + val p = Properties() + p.load(stream) + val modules = p.getProperty("MODULES") + if (modules != null) { + return StringUtil.split(StringUtil.unquoteString(modules), " ") + } + } + return null + } + + // Copied from JdkUtil#isModularRuntime + private fun isModularRuntime(homePath: Path): Boolean { + return Files.isRegularFile(homePath.resolve("lib/jrt-fs.jar")) || isExplodedModularRuntime(homePath) + } + + // Copied from JdkUtil#isExplodedModularRuntime + private fun isExplodedModularRuntime(homePath: Path): Boolean { + return Files.isDirectory(homePath.resolve("modules/java.base")) + } + + // Copied (and adjusted) from JavaSdkImpl#findClasses + // Currently, handle modular runtime only + fun findClassesFromJdkHome(jdkHome: Path): List { + val result = mutableListOf() + + if (isModularRuntime(jdkHome)) { + val jrtBaseUrl: String = StandardFileSystems.JRT_PROTOCOL_PREFIX + jdkHome.toString() + JAR_SEPARATOR + val modules = readModulesFromReleaseFile(jdkHome) + if (modules != null) { + for (module in modules) { + result.add(jrtBaseUrl + module) + } + } + } + + result.sort() + return result + } } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/AbstractDeclarationFromLibraryModuleProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/AbstractDeclarationFromBinaryModuleProvider.kt similarity index 91% rename from analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/AbstractDeclarationFromLibraryModuleProvider.kt rename to analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/AbstractDeclarationFromBinaryModuleProvider.kt index d53c216b139..a53315c09e0 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/AbstractDeclarationFromLibraryModuleProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/AbstractDeclarationFromBinaryModuleProvider.kt @@ -13,22 +13,23 @@ import com.intellij.openapi.vfs.VirtualFileSystem import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem import com.intellij.psi.search.GlobalSearchScope import com.intellij.util.io.URLUtil -import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule import org.jetbrains.kotlin.name.FqName +import java.nio.file.Files import java.nio.file.Path -public interface AbstractDeclarationFromLibraryModuleProvider { +public interface AbstractDeclarationFromBinaryModuleProvider { public val scope: GlobalSearchScope public val jarFileSystem: CoreJarFileSystem public fun virtualFilesFromModule( - libraryModule: KtLibraryModule, + binaryModule: KtBinaryModule, fqName: FqName, isPackageName: Boolean, ): Collection { val fqNameString = fqName.asString() val fs = StandardFileSystems.local() - return libraryModule.getBinaryRoots().flatMap r@{ rootPath -> + return binaryModule.getBinaryRoots().flatMap r@{ rootPath -> val root = findRoot(rootPath, fs) ?: return@r emptySet() val files = mutableSetOf() VfsUtilCore.iterateChildrenRecursively( @@ -68,10 +69,10 @@ public interface AbstractDeclarationFromLibraryModuleProvider { rootPath: Path, fs: VirtualFileSystem, ): VirtualFile? { - return if (rootPath.toFile().isDirectory) { - fs.findFileByPath(rootPath.toAbsolutePath().toString()) - } else { + return if (Files.isRegularFile(rootPath) && ".jar" in rootPath.toString()) { jarFileSystem.refreshAndFindFileByPath(rootPath.toAbsolutePath().toString() + URLUtil.JAR_SEPARATOR) + } else { + fs.findFileByPath(rootPath.toAbsolutePath().toString()) } } diff --git a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt index aeb834d025f..bba69aad95c 100644 --- a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt +++ b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/KtStaticModuleProvider.kt @@ -19,8 +19,8 @@ class KtStaticModuleProvider( }.ktModule } - override fun getKtLibraryModules(): Collection { - return testProjectStructure.allKtModules().filterIsInstance() + override fun getKtBinaryModules(): Collection { + return testProjectStructure.allKtModules().filterIsInstance() } override fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule { diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleByCompilerConfiguration.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleByCompilerConfiguration.kt index d37ebc66238..830344f2311 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleByCompilerConfiguration.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleByCompilerConfiguration.kt @@ -6,12 +6,13 @@ package org.jetbrains.kotlin.analysis.project.structure.impl import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.ProjectScope -import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule -import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule -import org.jetbrains.kotlin.analysis.project.structure.KtModule -import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule +import com.intellij.util.io.URLUtil +import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils +import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots @@ -22,6 +23,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import java.nio.file.Path +import java.nio.file.Paths internal abstract class BaseKtModuleByCompilerConfiguration( private val compilerConfig: CompilerConfiguration, @@ -51,7 +53,7 @@ internal class KtSourceModuleByCompilerConfiguration( project: Project, ktFiles: List, ) : BaseKtModuleByCompilerConfiguration(compilerConfig, project), KtSourceModule { - override val directRegularDependencies: List by lazy { + override val directRegularDependencies: List by lazy { val libraryRoots = compilerConfig.jvmModularRoots + compilerConfig.jvmClasspathRoots val libraryRootsByType = libraryRoots.groupBy { it.isDirectory } buildList { @@ -69,6 +71,15 @@ internal class KtSourceModuleByCompilerConfiguration( add(KtLibraryModuleByCompilerConfiguration(compilerConfig, project, root)) } } + compilerConfig.get(JVMConfigurationKeys.JDK_HOME)?.let { jdkHome -> + val vfm = VirtualFileManager.getInstance() + val jdkHomePath = jdkHome.toPath() + val jdkHomeVirtualFile = vfm.findFileByNioPath(jdkHomePath) + val binaryRoots = LibraryUtils.findClassesFromJdkHome(jdkHomePath).map { + Paths.get(URLUtil.extractPath(it)) + } + add(KtSdkModuleByCompilerConfiguration(compilerConfig, project, "JDK", jdkHomeVirtualFile, binaryRoots)) + } } } @@ -98,3 +109,18 @@ internal class KtLibraryModuleByCompilerConfiguration( override fun getBinaryRoots(): Collection = binaryRoots } + +internal class KtSdkModuleByCompilerConfiguration( + compilerConfig: CompilerConfiguration, + project: Project, + override val sdkName: String, + sdkHome: VirtualFile?, + private val binaryRoots: Collection +) : BaseKtModuleByCompilerConfiguration(compilerConfig, project), KtSdkModule { + override val directRegularDependencies: List get() = emptyList() + + override val contentScope: GlobalSearchScope = + GlobalSearchScope.fileScope(project, sdkHome) + + override fun getBinaryRoots(): Collection = binaryRoots +} diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderByCompilerConfiguration.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderByCompilerConfiguration.kt index 0155ec897d4..da8a529866b 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderByCompilerConfiguration.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleProviderByCompilerConfiguration.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.project.structure.impl import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider @@ -20,7 +21,7 @@ internal class KtModuleProviderByCompilerConfiguration( ) : ProjectStructureProvider() { private val sourceModule = KtSourceModuleByCompilerConfiguration(compilerConfig, project, ktFiles) - private val libraryModules: Collection by lazy { + private val binaryModules: Collection by lazy { sourceModule.directRegularDependencies } @@ -34,8 +35,8 @@ internal class KtModuleProviderByCompilerConfiguration( } } - override fun getKtLibraryModules(): Collection { - return libraryModules + override fun getKtBinaryModules(): Collection { + return binaryModules } override fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule? { diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt index 8d8c5010876..4fc8dffe7dc 100644 --- a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/ProjectStructureProvider.kt @@ -15,10 +15,10 @@ public abstract class ProjectStructureProvider { public abstract fun getKtModuleForKtElement(element: PsiElement): KtModule /** - * Returns all [KtLibraryModule]s in this project. + * Returns all dependent [KtBinaryModule]s in this project. */ // TODO: We rather need a session or facade that maintains this information. - public abstract fun getKtLibraryModules(): Collection + public abstract fun getKtBinaryModules(): Collection public abstract fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule? }