From d010a993759351c6898f0baedfd685eb4c6dea12 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Fri, 26 Sep 2025 16:29:57 +0200 Subject: [PATCH] [java] migrate some usages of getOrderEntriesForFile to findContainingSdks/Libraries to improve performance (IJPL-930) 'getOrderEntriesForFile' builds 'OrderEntryGraph' for the whole project when called for the first time after a 'rootsChanged' event. This may lead to freezes, so it's much more efficient to use newly introduced 'findContainingSdks' and 'findContainingLibraries' methods from 'ProjectFileIndex' instead where it's possible. Semantics of code which used 'ModuleFileIndex' (not 'ProjectFileIndex') before may change if some file is part of an SDK in one module and part of a source code of another module, but in practice such cases shouldn't happen. GitOrigin-RevId: 57ee33df6fe10d4d90687d68245a7dba3e6b7b03 --- .../java/codeserver/core/JpmsModuleAccessInfo.kt | 12 ++++++------ .../java/codeserver/highlighting/ModuleChecker.java | 2 +- .../psi/impl/file/impl/JavaFileManagerImpl.java | 4 ++-- .../com/intellij/ide/FileNotInSourceRootChecker.kt | 4 ++-- .../psi/util/proximity/SdkOrLibraryWeigher.java | 12 +----------- .../com/intellij/openapi/module/ModuleUtilCore.java | 8 +------- 6 files changed, 13 insertions(+), 29 deletions(-) diff --git a/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt b/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt index 22cf73cf5ded..50e6aa319cf5 100644 --- a/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt +++ b/java/codeserver/core/src/com/intellij/java/codeserver/core/JpmsModuleAccessInfo.kt @@ -3,8 +3,8 @@ package com.intellij.java.codeserver.core import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleUtilCore -import com.intellij.openapi.roots.JdkOrderEntry import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.roots.ProjectFileIndex import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile @@ -65,7 +65,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v if (current.module == null) { val origin = targetModule.containingFile?.virtualFile if (origin == null || currentJpsModule == null || - ModuleRootManager.getInstance(currentJpsModule).fileIndex.getOrderEntryForFile(origin) !is JdkOrderEntry + ProjectFileIndex.getInstance(currentJpsModule.project).findContainingSdks(origin).isEmpty() ) { return null // a target is not on the mandatory module path } @@ -133,7 +133,7 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v if (origin == null && targetModule is LightJavaModule) origin = targetModule.rootVirtualFile if (origin == null || currentJpsModule == null) return null - if (ModuleRootManager.getInstance(currentJpsModule).fileIndex.getOrderEntryForFile(origin) !is JdkOrderEntry) { + if (ProjectFileIndex.getInstance(currentJpsModule.project).findContainingSdks(origin).isEmpty()) { val searchScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(currentJpsModule) if (searchScope.contains(origin)) return null return JpmsModuleAccessProblem.JPS_DEPENDENCY_PROBLEM @@ -248,10 +248,10 @@ data class JpmsModuleAccessInfo(val current: JpmsModuleInfo.CurrentModuleInfo, v if (target != null) { val useVFile = place.virtualFile if (useVFile != null) { - val index = ModuleRootManager.getInstance(module).fileIndex - val test = index.isInTestSourceContent(useVFile) + val test = ModuleRootManager.getInstance(module).fileIndex.isInTestSourceContent(useVFile) val dirs = target.getDirectories(module.getModuleWithDependenciesAndLibrariesScope(test)) - return dirs.any { index.getOrderEntryForFile(it.virtualFile) !is JdkOrderEntry } + val projectFileIndex = ProjectFileIndex.getInstance(module.project) + return dirs.any { projectFileIndex.findContainingSdks(it.virtualFile).isEmpty() } } } } diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ModuleChecker.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ModuleChecker.java index a7d2789b12e5..9acd67f6d506 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ModuleChecker.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ModuleChecker.java @@ -64,7 +64,7 @@ final class ModuleChecker { PsiJavaModule anotherJavaModule = JavaPsiModuleUtil.findDescriptorByElement(directory); if (anotherJavaModule != null) { VirtualFile moduleVFile = PsiUtilCore.getVirtualFile(anotherJavaModule); - if (moduleVFile != null && ContainerUtil.find(fileIndex.getOrderEntriesForFile(moduleVFile), JdkOrderEntry.class::isInstance) != null) { + if (moduleVFile != null && !fileIndex.findContainingSdks(moduleVFile).isEmpty()) { VirtualFile rootForFile = fileIndex.getSourceRootForFile(file.getVirtualFile()); if (rootForFile != null && JavaCompilerConfigurationProxy.isPatchedModuleRoot(anotherJavaModule.getName(), module, rootForFile)) { return; diff --git a/java/java-analysis-impl/src/com/intellij/psi/impl/file/impl/JavaFileManagerImpl.java b/java/java-analysis-impl/src/com/intellij/psi/impl/file/impl/JavaFileManagerImpl.java index 20d18cb70b24..0df48bd29ec7 100644 --- a/java/java-analysis-impl/src/com/intellij/psi/impl/file/impl/JavaFileManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/psi/impl/file/impl/JavaFileManagerImpl.java @@ -242,10 +242,10 @@ public final class JavaFileManagerImpl implements JavaFileManager, Disposable { if (isModular) { List list = new ArrayList<>(modules); - ModuleFileIndex index = ModuleRootManager.getInstance(module).getFileIndex(); + ProjectFileIndex index = ProjectFileIndex.getInstance(module.getProject()); for (ListIterator i = list.listIterator(); i.hasNext(); ) { PsiJavaModule candidate = i.next(); - if (index.getOrderEntryForFile(PsiImplUtil.getModuleVirtualFile(candidate)) instanceof JdkOrderEntry) { + if (!index.findContainingSdks(PsiImplUtil.getModuleVirtualFile(candidate)).isEmpty()) { if (i.previousIndex() > 0) { i.remove(); // not at the top -> is upgraded } diff --git a/java/java-impl/src/com/intellij/ide/FileNotInSourceRootChecker.kt b/java/java-impl/src/com/intellij/ide/FileNotInSourceRootChecker.kt index 3abb5143d58a..0e60c179a31c 100644 --- a/java/java-impl/src/com/intellij/ide/FileNotInSourceRootChecker.kt +++ b/java/java-impl/src/com/intellij/ide/FileNotInSourceRootChecker.kt @@ -11,8 +11,8 @@ import com.intellij.ide.util.PropertiesComponent import com.intellij.java.JavaBundle import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.readAction import com.intellij.openapi.application.edtWriteAction +import com.intellij.openapi.application.readAction import com.intellij.openapi.components.Service import com.intellij.openapi.components.serviceAsync import com.intellij.openapi.editor.Editor @@ -112,7 +112,7 @@ private class FileNotInSourceRootService( val fileIndex = ProjectFileIndex.getInstance(project) if (fileIndex.isInSource(virtualFile) || fileIndex.isExcluded(virtualFile) || fileIndex.isUnderIgnored(virtualFile)) return null - if (fileIndex.getOrderEntriesForFile(virtualFile).isNotEmpty()) return null + if (fileIndex.findContainingLibraries(virtualFile).isNotEmpty() || fileIndex.findContainingSdks(virtualFile).isNotEmpty()) return null val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) as? PsiJavaFile ?: return null if (DaemonCodeAnalyzerEx.getInstanceEx(project).hasFileLevelHighlights(GROUP, psiFile)) return null diff --git a/platform/lang-impl/src/com/intellij/psi/util/proximity/SdkOrLibraryWeigher.java b/platform/lang-impl/src/com/intellij/psi/util/proximity/SdkOrLibraryWeigher.java index aa5a51a45955..5ef0dc662939 100644 --- a/platform/lang-impl/src/com/intellij/psi/util/proximity/SdkOrLibraryWeigher.java +++ b/platform/lang-impl/src/com/intellij/psi/util/proximity/SdkOrLibraryWeigher.java @@ -2,8 +2,6 @@ package com.intellij.psi.util.proximity; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.JdkOrderEntry; -import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; @@ -12,8 +10,6 @@ import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import java.util.List; - @ApiStatus.Internal public final class SdkOrLibraryWeigher extends ProximityWeigher { @@ -25,12 +21,6 @@ public final class SdkOrLibraryWeigher extends ProximityWeigher { private static boolean isJdkElement(PsiElement element, final @NotNull Project project) { final VirtualFile file = PsiUtilCore.getVirtualFile(element); - if (file != null) { - List orderEntries = ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(file); - if (!orderEntries.isEmpty() && orderEntries.get(0) instanceof JdkOrderEntry) { - return true; - } - } - return false; + return file != null && !ProjectRootManager.getInstance(project).getFileIndex().findContainingSdks(file).isEmpty(); } } diff --git a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java index 7613b0d3e775..5aa73d42d26c 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java +++ b/platform/projectModel-api/src/com/intellij/openapi/module/ModuleUtilCore.java @@ -38,13 +38,7 @@ public class ModuleUtilCore { public static boolean projectContainsFile(@NotNull Project project, @NotNull VirtualFile file, boolean isLibraryElement) { ProjectFileIndex projectFileIndex = ProjectFileIndex.getInstance(project); if (isLibraryElement) { - List orders = projectFileIndex.getOrderEntriesForFile(file); - for (OrderEntry orderEntry : orders) { - if (orderEntry instanceof JdkOrderEntry || orderEntry instanceof LibraryOrderEntry) { - return true; - } - } - return false; + return !projectFileIndex.findContainingSdks(file).isEmpty() || !projectFileIndex.findContainingLibraries(file).isEmpty(); } else { return projectFileIndex.isInContent(file);