fix "IDEA-221944 Deadlock on opening second project" and support preloading for proje...
[idea/community.git] / platform / projectModel-impl / src / com / intellij / openapi / roots / impl / ProjectFileIndexImpl.java
1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.openapi.roots.impl;
3
4 import com.intellij.injected.editor.VirtualFileWindow;
5 import com.intellij.notebook.editor.BackedVirtualFile;
6 import com.intellij.openapi.application.ReadAction;
7 import com.intellij.openapi.diagnostic.Logger;
8 import com.intellij.openapi.fileTypes.FileTypeRegistry;
9 import com.intellij.openapi.module.Module;
10 import com.intellij.openapi.module.ModuleManager;
11 import com.intellij.openapi.project.Project;
12 import com.intellij.openapi.roots.*;
13 import com.intellij.openapi.vfs.VirtualFile;
14 import com.intellij.openapi.vfs.VirtualFileFilter;
15 import org.jetbrains.annotations.NotNull;
16 import org.jetbrains.annotations.Nullable;
17 import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
18
19 import java.util.Collections;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Set;
23
24 public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIndex {
25   private static final Logger LOG = Logger.getInstance(ProjectFileIndexImpl.class);
26   private final Project myProject;
27
28   public ProjectFileIndexImpl(@NotNull Project project) {
29     super(DirectoryIndex.getInstance(project));
30
31     myProject = project;
32   }
33
34   /**
35    * @deprecated Do not pass DirectoryIndex explicitly.
36    */
37   @Deprecated
38   public ProjectFileIndexImpl(@NotNull Project project, @NotNull DirectoryIndex index, @NotNull FileTypeRegistry fileTypeManager) {
39     super(index);
40
41     myProject = project;
42   }
43
44   @Override
45   public boolean iterateContent(@NotNull ContentIterator processor, @Nullable VirtualFileFilter filter) {
46     Module[] modules = ReadAction.compute(() -> ModuleManager.getInstance(myProject).getModules());
47     for (final Module module : modules) {
48       for (VirtualFile contentRoot : getRootsToIterate(module)) {
49         if (!iterateContentUnderDirectory(contentRoot, processor, filter)) {
50           return false;
51         }
52       }
53     }
54     return true;
55   }
56
57   @NotNull
58   private Set<VirtualFile> getRootsToIterate(@NotNull Module module) {
59     return ReadAction.compute(() -> {
60       if (module.isDisposed()) return Collections.emptySet();
61
62       ModuleFileIndexImpl moduleFileIndex = (ModuleFileIndexImpl)ModuleRootManager.getInstance(module).getFileIndex();
63       Set<VirtualFile> result = moduleFileIndex.getModuleRootsToIterate();
64
65       for (Iterator<VirtualFile> iterator = result.iterator(); iterator.hasNext(); ) {
66         VirtualFile root = iterator.next();
67         DirectoryInfo info = getInfoForFileOrDirectory(root);
68         if (!info.isInProject(root) // is excluded or ignored
69             || !module.equals(info.getModule())) { // maybe 2 modules have the same content root?
70           iterator.remove();
71           continue;
72         }
73
74         VirtualFile parent = root.getParent();
75         if (parent != null) {
76           DirectoryInfo parentInfo = getInfoForFileOrDirectory(parent);
77           if (isFileInContent(parent, parentInfo)) {
78             iterator.remove();
79           }
80         }
81       }
82
83       return result;
84     });
85   }
86
87   @Override
88   public boolean isExcluded(@NotNull VirtualFile file) {
89     DirectoryInfo info = getInfoForFileOrDirectory(file);
90     return info.isIgnored() || info.isExcluded(file);
91   }
92
93   @Override
94   public boolean isUnderIgnored(@NotNull VirtualFile file) {
95     return getInfoForFileOrDirectory(file).isIgnored();
96   }
97
98   @Override
99   public Module getModuleForFile(@NotNull VirtualFile file) {
100     return getModuleForFile(file, true);
101   }
102
103   @Nullable
104   @Override
105   public Module getModuleForFile(@NotNull VirtualFile file, boolean honorExclusion) {
106     if (file instanceof VirtualFileWindow) file = ((VirtualFileWindow)file).getDelegate();
107     file = BackedVirtualFile.getOriginFileIfBacked(file);
108     DirectoryInfo info = getInfoForFileOrDirectory(file);
109     if (info.isInProject(file) || !honorExclusion && info.isExcluded(file)) {
110       return info.getModule();
111     }
112     return null;
113   }
114
115   @Override
116   @NotNull
117   public List<OrderEntry> getOrderEntriesForFile(@NotNull VirtualFile file) {
118     return myDirectoryIndex.getOrderEntries(getInfoForFileOrDirectory(file));
119   }
120
121   @Override
122   public VirtualFile getClassRootForFile(@NotNull VirtualFile file) {
123     return getClassRootForFile(file, getInfoForFileOrDirectory(file));
124   }
125
126   @Nullable
127   public static VirtualFile getClassRootForFile(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
128     return info.isInProject(file) ? info.getLibraryClassRoot() : null;
129   }
130
131   @Override
132   public VirtualFile getSourceRootForFile(@NotNull VirtualFile file) {
133     return getSourceRootForFile(file, getInfoForFileOrDirectory(file));
134   }
135
136   @Nullable
137   public static VirtualFile getSourceRootForFile(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
138     return info.isInProject(file) ? info.getSourceRoot() : null;
139   }
140
141   @Override
142   public VirtualFile getContentRootForFile(@NotNull VirtualFile file) {
143     return getContentRootForFile(file, true);
144   }
145
146   @Override
147   public VirtualFile getContentRootForFile(@NotNull VirtualFile file, final boolean honorExclusion) {
148     return getContentRootForFile(getInfoForFileOrDirectory(file), file, honorExclusion);
149   }
150
151   @Nullable
152   public static VirtualFile getContentRootForFile(@NotNull DirectoryInfo info, @NotNull VirtualFile file, boolean honorExclusion) {
153     if (info.isInProject(file) || !honorExclusion && info.isExcluded(file)) {
154       return info.getContentRoot();
155     }
156     return null;
157   }
158
159   @Override
160   public String getPackageNameByDirectory(@NotNull VirtualFile dir) {
161     if (!dir.isDirectory()) LOG.error(dir.getPresentableUrl());
162     return myDirectoryIndex.getPackageName(dir);
163   }
164
165   @Override
166   public boolean isLibraryClassFile(@NotNull VirtualFile file) {
167     if (file.isDirectory()) return false;
168     DirectoryInfo parentInfo = getInfoForFileOrDirectory(file);
169     return parentInfo.isInProject(file) && parentInfo.hasLibraryClassRoot();
170   }
171
172   @Override
173   public boolean isInSource(@NotNull VirtualFile fileOrDir) {
174     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
175     return info.isInModuleSource(fileOrDir) || info.isInLibrarySource(fileOrDir);
176   }
177
178   @Override
179   public boolean isInLibraryClasses(@NotNull VirtualFile fileOrDir) {
180     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
181     return info.isInProject(fileOrDir) && info.hasLibraryClassRoot();
182   }
183
184   @Override
185   public boolean isInLibrarySource(@NotNull VirtualFile fileOrDir) {
186     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
187     return info.isInProject(fileOrDir) && info.isInLibrarySource(fileOrDir);
188   }
189
190   // a slightly faster implementation then the default one
191   @Override
192   public boolean isInLibrary(@NotNull VirtualFile fileOrDir) {
193     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
194     return info.isInProject(fileOrDir) && (info.hasLibraryClassRoot() || info.isInLibrarySource(fileOrDir));
195   }
196
197   @Override
198   public boolean isIgnored(@NotNull VirtualFile file) {
199     return isExcluded(file);
200   }
201
202   @Override
203   public boolean isInContent(@NotNull VirtualFile fileOrDir) {
204     return isFileInContent(fileOrDir, getInfoForFileOrDirectory(fileOrDir));
205   }
206
207   public static boolean isFileInContent(@NotNull VirtualFile fileOrDir, @NotNull DirectoryInfo info) {
208     return info.isInProject(fileOrDir) && info.getModule() != null;
209   }
210
211   @Override
212   public boolean isInSourceContent(@NotNull VirtualFile fileOrDir) {
213     return getInfoForFileOrDirectory(fileOrDir).isInModuleSource(fileOrDir);
214   }
215
216   @Override
217   public boolean isInTestSourceContent(@NotNull VirtualFile fileOrDir) {
218     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
219     return info.isInModuleSource(fileOrDir) && isTestSourcesRoot(info);
220   }
221
222   @Override
223   public boolean isUnderSourceRootOfType(@NotNull VirtualFile fileOrDir, @NotNull Set<? extends JpsModuleSourceRootType<?>> rootTypes) {
224     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
225     return info.isInModuleSource(fileOrDir) && rootTypes.contains(myDirectoryIndex.getSourceRootType(info));
226   }
227
228   public SourceFolder getSourceFolder(@NotNull VirtualFile fileOrDir) {
229     return myDirectoryIndex.getSourceRootFolder(getInfoForFileOrDirectory(fileOrDir));
230   }
231
232   @Override
233   protected boolean isScopeDisposed() {
234     return myProject.isDisposed();
235   }
236 }