800165f47158223770cc4a96b687db70ab9380da
[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       ModuleFileIndex moduleFileIndex = 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 (!module.equals(info.getModule())) { // maybe 2 modules have the same content root?
69           iterator.remove();
70           continue;
71         }
72
73         VirtualFile parent = root.getParent();
74         if (parent != null) {
75           if (isInContent(parent)) {
76             iterator.remove();
77           }
78         }
79       }
80
81       return result;
82     });
83   }
84
85   @Override
86   public boolean isExcluded(@NotNull VirtualFile file) {
87     DirectoryInfo info = getInfoForFileOrDirectory(file);
88     return info.isIgnored() || info.isExcluded(file);
89   }
90
91   @Override
92   public boolean isUnderIgnored(@NotNull VirtualFile file) {
93     return getInfoForFileOrDirectory(file).isIgnored();
94   }
95
96   @Override
97   public Module getModuleForFile(@NotNull VirtualFile file) {
98     return getModuleForFile(file, true);
99   }
100
101   @Nullable
102   @Override
103   public Module getModuleForFile(@NotNull VirtualFile file, boolean honorExclusion) {
104     if (file instanceof VirtualFileWindow) file = ((VirtualFileWindow)file).getDelegate();
105     file = BackedVirtualFile.getOriginFileIfBacked(file);
106     DirectoryInfo info = getInfoForFileOrDirectory(file);
107     if (info.isInProject(file) || !honorExclusion && info.isExcluded(file)) {
108       return info.getModule();
109     }
110     return null;
111   }
112
113   @Override
114   @NotNull
115   public List<OrderEntry> getOrderEntriesForFile(@NotNull VirtualFile file) {
116     return myDirectoryIndex.getOrderEntries(getInfoForFileOrDirectory(file));
117   }
118
119   @Override
120   public VirtualFile getClassRootForFile(@NotNull VirtualFile file) {
121     return getClassRootForFile(file, getInfoForFileOrDirectory(file));
122   }
123
124   @Nullable
125   public static VirtualFile getClassRootForFile(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
126     return info.isInProject(file) ? info.getLibraryClassRoot() : null;
127   }
128
129   @Override
130   public VirtualFile getSourceRootForFile(@NotNull VirtualFile file) {
131     return getSourceRootForFile(file, getInfoForFileOrDirectory(file));
132   }
133
134   @Nullable
135   public static VirtualFile getSourceRootForFile(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
136     return info.isInProject(file) ? info.getSourceRoot() : null;
137   }
138
139   @Override
140   public VirtualFile getContentRootForFile(@NotNull VirtualFile file) {
141     return getContentRootForFile(file, true);
142   }
143
144   @Override
145   public VirtualFile getContentRootForFile(@NotNull VirtualFile file, final boolean honorExclusion) {
146     return getContentRootForFile(getInfoForFileOrDirectory(file), file, honorExclusion);
147   }
148
149   @Nullable
150   public static VirtualFile getContentRootForFile(@NotNull DirectoryInfo info, @NotNull VirtualFile file, boolean honorExclusion) {
151     if (info.isInProject(file) || !honorExclusion && info.isExcluded(file)) {
152       return info.getContentRoot();
153     }
154     return null;
155   }
156
157   @Override
158   public String getPackageNameByDirectory(@NotNull VirtualFile dir) {
159     if (!dir.isDirectory()) LOG.error(dir.getPresentableUrl());
160     return myDirectoryIndex.getPackageName(dir);
161   }
162
163   @Override
164   public boolean isLibraryClassFile(@NotNull VirtualFile file) {
165     if (file.isDirectory()) return false;
166     DirectoryInfo parentInfo = getInfoForFileOrDirectory(file);
167     return parentInfo.isInProject(file) && parentInfo.hasLibraryClassRoot();
168   }
169
170   @Override
171   public boolean isInSource(@NotNull VirtualFile fileOrDir) {
172     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
173     return info.isInModuleSource(fileOrDir) || info.isInLibrarySource(fileOrDir);
174   }
175
176   @Override
177   public boolean isInLibraryClasses(@NotNull VirtualFile fileOrDir) {
178     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
179     return info.isInProject(fileOrDir) && info.hasLibraryClassRoot();
180   }
181
182   @Override
183   public boolean isInLibrarySource(@NotNull VirtualFile fileOrDir) {
184     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
185     return info.isInProject(fileOrDir) && info.isInLibrarySource(fileOrDir);
186   }
187
188   // a slightly faster implementation then the default one
189   @Override
190   public boolean isInLibrary(@NotNull VirtualFile fileOrDir) {
191     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
192     return info.isInProject(fileOrDir) && (info.hasLibraryClassRoot() || info.isInLibrarySource(fileOrDir));
193   }
194
195   @Override
196   public boolean isIgnored(@NotNull VirtualFile file) {
197     return isExcluded(file);
198   }
199
200   @Override
201   public boolean isInContent(@NotNull VirtualFile fileOrDir) {
202     return isFileInContent(fileOrDir, getInfoForFileOrDirectory(fileOrDir));
203   }
204
205   public static boolean isFileInContent(@NotNull VirtualFile fileOrDir, @NotNull DirectoryInfo info) {
206     return info.isInProject(fileOrDir) && info.getModule() != null;
207   }
208
209   @Override
210   public boolean isInSourceContent(@NotNull VirtualFile fileOrDir) {
211     return getInfoForFileOrDirectory(fileOrDir).isInModuleSource(fileOrDir);
212   }
213
214   @Override
215   public boolean isInTestSourceContent(@NotNull VirtualFile fileOrDir) {
216     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
217     return info.isInModuleSource(fileOrDir) && isTestSourcesRoot(info);
218   }
219
220   @Override
221   public boolean isUnderSourceRootOfType(@NotNull VirtualFile fileOrDir, @NotNull Set<? extends JpsModuleSourceRootType<?>> rootTypes) {
222     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
223     return info.isInModuleSource(fileOrDir) && rootTypes.contains(myDirectoryIndex.getSourceRootType(info));
224   }
225
226   public SourceFolder getSourceFolder(@NotNull VirtualFile fileOrDir) {
227     return myDirectoryIndex.getSourceRootFolder(getInfoForFileOrDirectory(fileOrDir));
228   }
229
230   @Override
231   protected boolean isScopeDisposed() {
232     return myProject.isDisposed();
233   }
234 }