5d8b6f0f23a16bd58a0c5aa1257539b19f557243
[idea/community.git] / platform / projectModel-impl / src / com / intellij / openapi / roots / impl / ModuleFileIndexImpl.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
3 package com.intellij.openapi.roots.impl;
4
5 import com.intellij.openapi.application.ReadAction;
6 import com.intellij.openapi.fileTypes.FileTypeRegistry;
7 import com.intellij.openapi.module.Module;
8 import com.intellij.openapi.roots.*;
9 import com.intellij.openapi.vfs.VirtualFile;
10 import com.intellij.openapi.vfs.VirtualFileFilter;
11 import com.intellij.util.IncorrectOperationException;
12 import org.jetbrains.annotations.NotNull;
13 import org.jetbrains.annotations.Nullable;
14 import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
15
16 import java.util.*;
17
18 public class ModuleFileIndexImpl extends FileIndexBase implements ModuleFileIndex {
19   @NotNull
20   private final Module myModule;
21
22   public ModuleFileIndexImpl(@NotNull Module module, @NotNull DirectoryIndex directoryIndex) {
23     super(directoryIndex, FileTypeRegistry.getInstance());
24     myModule = module;
25   }
26
27   @Override
28   public boolean iterateContent(@NotNull ContentIterator processor, @Nullable VirtualFileFilter filter) {
29     Set<VirtualFile> contentRoots = getModuleRootsToIterate();
30     for (VirtualFile contentRoot : contentRoots) {
31       if (!iterateContentUnderDirectory(contentRoot, processor, filter)) {
32         return false;
33       }
34     }
35     return true;
36   }
37
38
39   @NotNull
40   Set<VirtualFile> getModuleRootsToIterate() {
41     return ReadAction.compute(() -> {
42       if (myModule.isDisposed()) return Collections.emptySet();
43       Set<VirtualFile> result = new LinkedHashSet<>();
44       VirtualFile[][] allRoots = getModuleContentAndSourceRoots(myModule);
45       for (VirtualFile[] roots : allRoots) {
46         for (VirtualFile root : roots) {
47           DirectoryInfo info = getInfoForFileOrDirectory(root);
48           if (!info.isInProject(root)) continue;
49
50           VirtualFile parent = root.getParent();
51           if (parent != null) {
52             DirectoryInfo parentInfo = myDirectoryIndex.getInfoForFile(parent);
53             if (myModule.equals(parentInfo.getModule())) continue; // inner content - skip it
54           }
55           result.add(root);
56         }
57       }
58       return result;
59     });
60   }
61
62   @Override
63   public boolean isInContent(@NotNull VirtualFile fileOrDir) {
64     return isInContent(fileOrDir, getInfoForFileOrDirectory(fileOrDir));
65   }
66
67   @Override
68   public boolean isInSourceContent(@NotNull VirtualFile fileOrDir) {
69     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
70     return info.isInModuleSource(fileOrDir) && myModule.equals(info.getModule());
71   }
72
73   @Override
74   @NotNull
75   public List<OrderEntry> getOrderEntriesForFile(@NotNull VirtualFile fileOrDir) {
76     return findAllOrderEntriesWithOwnerModule(myModule, myDirectoryIndex.getOrderEntries(getInfoForFileOrDirectory(fileOrDir)));
77   }
78
79   @Override
80   public OrderEntry getOrderEntryForFile(@NotNull VirtualFile fileOrDir) {
81     return findOrderEntryWithOwnerModule(myModule, myDirectoryIndex.getOrderEntries(getInfoForFileOrDirectory(fileOrDir)));
82   }
83
84   @Override
85   public boolean isInTestSourceContent(@NotNull VirtualFile fileOrDir) {
86     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
87     return info.isInModuleSource(fileOrDir) && myModule.equals(info.getModule()) && isTestSourcesRoot(info);
88   }
89
90   @Override
91   public boolean isUnderSourceRootOfType(@NotNull VirtualFile fileOrDir, @NotNull Set<? extends JpsModuleSourceRootType<?>> rootTypes) {
92     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
93     return info.isInModuleSource(fileOrDir) && myModule.equals(info.getModule()) && rootTypes.contains(myDirectoryIndex.getSourceRootType(info));
94   }
95
96   @Override
97   protected boolean isScopeDisposed() {
98     return myModule.isDisposed();
99   }
100
101   @Nullable
102   public static OrderEntry findOrderEntryWithOwnerModule(@NotNull Module ownerModule, @NotNull List<? extends OrderEntry> orderEntries) {
103     if (orderEntries.size() < 10) {
104       for (OrderEntry orderEntry : orderEntries) {
105         if (orderEntry.getOwnerModule() == ownerModule) {
106           return orderEntry;
107         }
108       }
109       return null;
110     }
111     int index = Collections.binarySearch(orderEntries, new FakeOrderEntry(ownerModule), RootIndex.BY_OWNER_MODULE);
112     return index < 0 ? null : orderEntries.get(index);
113   }
114
115   @NotNull
116   private static List<OrderEntry> findAllOrderEntriesWithOwnerModule(@NotNull Module ownerModule, @NotNull List<? extends OrderEntry> entries) {
117     if (entries.isEmpty()) return Collections.emptyList();
118
119     if (entries.size() == 1) {
120       OrderEntry entry = entries.get(0);
121       return entry.getOwnerModule() == ownerModule ?
122              new ArrayList<>(entries) : Collections.emptyList();
123     }
124     int index = Collections.binarySearch(entries, new FakeOrderEntry(ownerModule), RootIndex.BY_OWNER_MODULE);
125     if (index < 0) {
126       return Collections.emptyList();
127     }
128     int firstIndex = index;
129     while (firstIndex - 1 >= 0 && entries.get(firstIndex - 1).getOwnerModule() == ownerModule) {
130       firstIndex--;
131     }
132     int lastIndex = index + 1;
133     while (lastIndex < entries.size() && entries.get(lastIndex).getOwnerModule() == ownerModule) {
134       lastIndex++;
135     }
136     return new ArrayList<>(entries.subList(firstIndex, lastIndex));
137   }
138
139   private static class FakeOrderEntry implements OrderEntry {
140     private final Module myOwnerModule;
141
142     FakeOrderEntry(@NotNull Module ownerModule) {
143       myOwnerModule = ownerModule;
144     }
145
146     @NotNull
147     @Override
148     public VirtualFile[] getFiles(@NotNull OrderRootType type) {
149       throw new IncorrectOperationException();
150     }
151
152     @NotNull
153     @Override
154     public String[] getUrls(@NotNull OrderRootType rootType) {
155       throw new IncorrectOperationException();
156     }
157
158     @NotNull
159     @Override
160     public String getPresentableName() {
161       throw new IncorrectOperationException();
162     }
163
164     @Override
165     public boolean isValid() {
166       throw new IncorrectOperationException();
167     }
168
169     @NotNull
170     @Override
171     public Module getOwnerModule() {
172       return myOwnerModule;
173     }
174
175     @Override
176     public <R> R accept(@NotNull RootPolicy<R> policy, @Nullable R initialValue) {
177       throw new IncorrectOperationException();
178     }
179
180     @Override
181     public int compareTo(@NotNull OrderEntry o) {
182       throw new IncorrectOperationException();
183     }
184
185     @Override
186     public boolean isSynthetic() {
187       throw new IncorrectOperationException();
188     }
189   }
190
191   @Override
192   protected boolean isInContent(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
193     return ProjectFileIndexImpl.isFileInContent(file, info) && myModule.equals(info.getModule());
194   }
195 }