2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.intellij.psi.impl.cache.impl;
19 import com.intellij.injected.editor.VirtualFileWindow;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.application.ReadActionProcessor;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.progress.ProcessCanceledException;
24 import com.intellij.openapi.progress.ProgressManager;
25 import com.intellij.openapi.project.IndexNotReadyException;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.roots.FileIndexFacade;
28 import com.intellij.openapi.roots.ProjectFileIndex;
29 import com.intellij.openapi.roots.ProjectRootManager;
30 import com.intellij.openapi.vfs.VirtualFile;
31 import com.intellij.psi.PsiFile;
32 import com.intellij.psi.PsiManager;
33 import com.intellij.psi.impl.cache.CacheManager;
34 import com.intellij.psi.impl.cache.impl.id.IdIndex;
35 import com.intellij.psi.impl.cache.impl.id.IdIndexEntry;
36 import com.intellij.psi.impl.cache.impl.todo.TodoIndex;
37 import com.intellij.psi.impl.cache.impl.todo.TodoIndexEntry;
38 import com.intellij.psi.search.GlobalSearchScope;
39 import com.intellij.psi.search.IndexPattern;
40 import com.intellij.psi.search.IndexPatternProvider;
41 import com.intellij.psi.util.PsiUtilCore;
42 import com.intellij.util.CommonProcessors;
43 import com.intellij.util.Processor;
44 import com.intellij.util.indexing.FileBasedIndex;
45 import gnu.trove.THashSet;
46 import org.jetbrains.annotations.NotNull;
48 import java.util.Collection;
49 import java.util.HashSet;
53 * @author Eugene Zhuravlev
56 public class IndexCacheManagerImpl implements CacheManager{
57 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.cache.impl.IndexCacheManagerImpl");
58 private final Project myProject;
59 private final PsiManager myPsiManager;
61 public IndexCacheManagerImpl(PsiManager psiManager) {
62 myPsiManager = psiManager;
63 myProject = psiManager.getProject();
67 public PsiFile[] getFilesWithWord(@NotNull final String word, final short occurenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
68 if (myProject.isDefault()) {
69 return PsiFile.EMPTY_ARRAY;
71 CommonProcessors.CollectProcessor<PsiFile> processor = new CommonProcessors.CollectProcessor<PsiFile>();
72 processFilesWithWord(processor, word, occurenceMask, scope, caseSensitively);
73 return processor.getResults().isEmpty() ? PsiFile.EMPTY_ARRAY : processor.toArray(PsiFile.EMPTY_ARRAY);
76 public static boolean shouldBeFound(GlobalSearchScope scope, VirtualFile virtualFile, FileIndexFacade index) {
77 return (scope.isSearchOutsideRootModel() || index.isInContent(virtualFile) || index.isInLibrarySource(virtualFile)) && !virtualFile.getFileType().isBinary();
80 public boolean processFilesWithWord(@NotNull final Processor<PsiFile> psiFileProcessor, @NotNull final String word, final short occurrenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
81 if (myProject.isDefault()) {
84 final Set<VirtualFile> vFiles = new THashSet<VirtualFile>();
85 final GlobalSearchScope projectScope = GlobalSearchScope.allScope(myProject);
87 ApplicationManager.getApplication().runReadAction(new Runnable() {
89 FileBasedIndex.getInstance().processValues(IdIndex.NAME, new IdIndexEntry(word, caseSensitively), null, new FileBasedIndex.ValueProcessor<Integer>() {
90 public boolean process(final VirtualFile file, final Integer value) {
91 ProgressManager.checkCanceled();
92 final int mask = value.intValue();
93 if ((mask & occurrenceMask) != 0) {
102 catch (IndexNotReadyException e) {
103 throw new ProcessCanceledException();
106 if (vFiles.isEmpty()) return true;
108 final FileIndexFacade index = FileIndexFacade.getInstance(myProject);
110 final Processor<VirtualFile> virtualFileProcessor = new ReadActionProcessor<VirtualFile>() {
112 public boolean processInReadAction(VirtualFile virtualFile) {
113 LOG.assertTrue(virtualFile.isValid());
114 if (virtualFile.isValid() && scope.contains(virtualFile) && shouldBeFound(scope, virtualFile, index)) {
115 final PsiFile psiFile = myPsiManager.findFile(virtualFile);
116 return psiFile == null || psiFileProcessor.process(psiFile);
124 // Since implementation of virtualFileProcessor.process() may call indices directly or indirectly,
125 // we cannot call it inside FileBasedIndex.processValues() method
126 // If we do, deadlocks are possible (IDEADEV-42137). So first we obtain files with the word specified,
127 // and then process them not holding indices' read lock.
128 for (VirtualFile vFile : vFiles) {
129 ProgressManager.checkCanceled();
130 if (!virtualFileProcessor.process(vFile)) {
138 public PsiFile[] getFilesWithTodoItems() {
139 if (myProject.isDefault()) {
140 return PsiFile.EMPTY_ARRAY;
142 final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
143 final Set<PsiFile> allFiles = new HashSet<PsiFile>();
144 final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
145 for (IndexPattern indexPattern : IndexPatternUtil.getIndexPatterns()) {
146 final Collection<VirtualFile> files = fileBasedIndex.getContainingFiles(
148 new TodoIndexEntry(indexPattern.getPatternString(), indexPattern.isCaseSensitive()), GlobalSearchScope.allScope(myProject));
149 ApplicationManager.getApplication().runReadAction(new Runnable() {
151 for (VirtualFile file : files) {
152 if (projectFileIndex.isInContent(file)) {
153 final PsiFile psiFile = myPsiManager.findFile(file);
154 if (psiFile != null) {
155 allFiles.add(psiFile);
162 return allFiles.isEmpty() ? PsiFile.EMPTY_ARRAY : PsiUtilCore.toPsiFileArray(allFiles);
165 public int getTodoCount(@NotNull final VirtualFile file, final IndexPatternProvider patternProvider) {
166 if (myProject.isDefault()) {
169 if (file instanceof VirtualFileWindow) return -1;
170 final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
172 for (IndexPattern indexPattern : patternProvider.getIndexPatterns()) {
173 count += fetchCount(fileBasedIndex, file, indexPattern);
178 public int getTodoCount(@NotNull final VirtualFile file, final IndexPattern pattern) {
179 if (myProject.isDefault()) {
182 if (file instanceof VirtualFileWindow) return -1;
183 return fetchCount(FileBasedIndex.getInstance(), file, pattern);
186 private int fetchCount(final FileBasedIndex fileBasedIndex, final VirtualFile file, final IndexPattern indexPattern) {
187 final int[] count = {0};
188 fileBasedIndex.processValues(
189 TodoIndex.NAME, new TodoIndexEntry(indexPattern.getPatternString(), indexPattern.isCaseSensitive()), file,
190 new FileBasedIndex.ValueProcessor<Integer>() {
191 public boolean process(final VirtualFile file, final Integer value) {
192 count[0] += value.intValue();
195 }, GlobalSearchScope.fileScope(myProject, file));