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