3ae826c4e8d610d03d98b2ebbbfc5f83fb072bb4
[idea/community.git] / platform / indexing-impl / src / com / intellij / util / indexing / AdditionalIndexableFileSet.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.util.indexing;
17
18 import com.intellij.openapi.extensions.Extensions;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.roots.ContentIterator;
21 import com.intellij.openapi.vfs.VfsUtilCore;
22 import com.intellij.openapi.vfs.VirtualFile;
23 import com.intellij.openapi.vfs.VirtualFileVisitor;
24 import gnu.trove.THashSet;
25 import org.jetbrains.annotations.NotNull;
26
27 import java.util.Set;
28
29 /**
30  * @author peter
31  */
32 public class AdditionalIndexableFileSet implements IndexableFileSet {
33   private final Project myProject;
34   private volatile Set<VirtualFile> cachedFiles;
35   private volatile Set<VirtualFile> cachedDirectories;
36   private volatile IndexedRootsProvider[] myExtensions;
37
38   public AdditionalIndexableFileSet(Project project, IndexedRootsProvider... extensions) {
39     myProject = project;
40     myExtensions = extensions;
41   }
42
43   public AdditionalIndexableFileSet(Project project) {
44     myProject = project;
45   }
46
47   public AdditionalIndexableFileSet(IndexedRootsProvider... extensions) {
48     myProject = null;
49     myExtensions = extensions;
50   }
51
52   public AdditionalIndexableFileSet() {
53     myProject = null;
54   }
55
56   private Set<VirtualFile> getDirectories() {
57     Set<VirtualFile> directories = cachedDirectories;
58     if (directories == null || filesInvalidated(directories) || filesInvalidated(cachedFiles)) {
59       directories = collectFilesAndDirectories();
60     }
61     return directories;
62   }
63
64   private THashSet<VirtualFile> collectFilesAndDirectories() {
65     THashSet<VirtualFile> files = new THashSet<VirtualFile>();
66     THashSet<VirtualFile> directories = new THashSet<VirtualFile>();
67     if (myExtensions == null) {
68       myExtensions = Extensions.getExtensions(IndexedRootsProvider.EP_NAME);
69     }
70     for (IndexedRootsProvider provider : myExtensions) {
71       for (VirtualFile root : IndexableSetContributor.getRootsToIndex(provider)) {
72         if (root != null) {
73           (root.isDirectory() ? directories : files).add(root);
74         }
75       }
76       if (myProject != null) {
77         Set<VirtualFile> projectRoots = IndexableSetContributor.getProjectRootsToIndex(provider, myProject);
78         for (VirtualFile root : projectRoots) {
79           if (root != null) {
80             (root.isDirectory() ? directories : files).add(root);
81           }
82         }
83       }
84     }
85     cachedFiles = files;
86     cachedDirectories = directories;
87     return directories;
88   }
89
90   public static boolean filesInvalidated(Set<VirtualFile> files) {
91     for (VirtualFile file : files) {
92       if (!file.isValid()) {
93         return true;
94       }
95     }
96     return false;
97   }
98
99   @Override
100   public boolean isInSet(@NotNull VirtualFile file) {
101     return VfsUtilCore.isUnder(file, getDirectories()) || cachedFiles.contains(file);
102   }
103
104   @Override
105   public void iterateIndexableFilesIn(@NotNull VirtualFile file, @NotNull final ContentIterator iterator) {
106     VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
107       @Override
108       public boolean visitFile(@NotNull VirtualFile file) {
109         if (!isInSet(file)) {
110           return false;
111         }
112
113         if (!file.isDirectory()) {
114           iterator.processFile(file);
115         }
116
117         return true;
118       }
119     });
120   }
121 }