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.ProjectFileIndex;
28 import com.intellij.openapi.roots.ProjectRootManager;
29 import com.intellij.openapi.vfs.VirtualFile;
30 import com.intellij.psi.PsiFile;
31 import com.intellij.psi.PsiManager;
32 import com.intellij.psi.impl.cache.CacheManager;
33 import com.intellij.psi.impl.cache.impl.id.IdIndex;
34 import com.intellij.psi.impl.cache.impl.id.IdIndexEntry;
35 import com.intellij.psi.impl.cache.impl.todo.TodoIndex;
36 import com.intellij.psi.impl.cache.impl.todo.TodoIndexEntry;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.psi.search.IndexPattern;
39 import com.intellij.psi.search.IndexPatternProvider;
40 import com.intellij.psi.util.PsiUtilCore;
41 import com.intellij.util.CommonProcessors;
42 import com.intellij.util.Processor;
43 import com.intellij.util.indexing.FileBasedIndex;
44 import gnu.trove.THashSet;
45 import org.jetbrains.annotations.NotNull;
47 import java.util.Collection;
48 import java.util.HashSet;
52 * @author Eugene Zhuravlev
55 public class IndexCacheManagerImpl implements CacheManager{
56 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.cache.impl.IndexCacheManagerImpl");
57 private final Project myProject;
58 private final PsiManager myPsiManager;
60 public IndexCacheManagerImpl(PsiManager psiManager) {
61 myPsiManager = psiManager;
62 myProject = psiManager.getProject();
66 public PsiFile[] getFilesWithWord(@NotNull final String word, final short occurenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
67 if (myProject.isDefault()) {
68 return PsiFile.EMPTY_ARRAY;
70 CommonProcessors.CollectProcessor<PsiFile> processor = new CommonProcessors.CollectProcessor<PsiFile>();
71 processFilesWithWord(processor, word, occurenceMask, scope, caseSensitively);
72 return processor.getResults().isEmpty() ? PsiFile.EMPTY_ARRAY : processor.toArray(PsiFile.EMPTY_ARRAY);
75 public static boolean shouldBeFound(GlobalSearchScope scope, VirtualFile virtualFile, ProjectFileIndex index) {
76 return (scope.isSearchOutsideRootModel() || index.isInContent(virtualFile) || index.isInLibrarySource(virtualFile)) && !virtualFile.getFileType().isBinary();
79 public boolean processFilesWithWord(@NotNull final Processor<PsiFile> psiFileProcessor, @NotNull final String word, final short occurrenceMask, @NotNull final GlobalSearchScope scope, final boolean caseSensitively) {
80 if (myProject.isDefault()) {
83 final Set<VirtualFile> vFiles = new THashSet<VirtualFile>();
84 final GlobalSearchScope projectScope = GlobalSearchScope.allScope(myProject);
86 ApplicationManager.getApplication().runReadAction(new Runnable() {
88 FileBasedIndex.getInstance().processValues(IdIndex.NAME, new IdIndexEntry(word, caseSensitively), null, new FileBasedIndex.ValueProcessor<Integer>() {
89 public boolean process(final VirtualFile file, final Integer value) {
90 ProgressManager.checkCanceled();
91 final int mask = value.intValue();
92 if ((mask & occurrenceMask) != 0) {
101 catch (IndexNotReadyException e) {
102 throw new ProcessCanceledException();
105 if (vFiles.isEmpty()) return true;
107 final ProjectFileIndex index = ProjectRootManager.getInstance(myProject).getFileIndex();
109 final Processor<VirtualFile> virtualFileProcessor = new ReadActionProcessor<VirtualFile>() {
111 public boolean processInReadAction(VirtualFile virtualFile) {
112 LOG.assertTrue(virtualFile.isValid());
113 if (virtualFile.isValid() && scope.contains(virtualFile) && shouldBeFound(scope, virtualFile, index)) {
114 final PsiFile psiFile = myPsiManager.findFile(virtualFile);
115 return psiFile == null || psiFileProcessor.process(psiFile);
123 // Since implementation of virtualFileProcessor.process() may call indices directly or indirectly,
124 // we cannot call it inside FileBasedIndex.processValues() method
125 // If we do, deadlocks are possible (IDEADEV-42137). So first we obtain files with the word specified,
126 // and then process them not holding indices' read lock.
127 for (VirtualFile vFile : vFiles) {
128 ProgressManager.checkCanceled();
129 if (!virtualFileProcessor.process(vFile)) {
137 public PsiFile[] getFilesWithTodoItems() {
138 if (myProject.isDefault()) {
139 return PsiFile.EMPTY_ARRAY;
141 final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
142 final Set<PsiFile> allFiles = new HashSet<PsiFile>();
143 final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex();
144 for (IndexPattern indexPattern : IndexPatternUtil.getIndexPatterns()) {
145 final Collection<VirtualFile> files = fileBasedIndex.getContainingFiles(
147 new TodoIndexEntry(indexPattern.getPatternString(), indexPattern.isCaseSensitive()), GlobalSearchScope.allScope(myProject));
148 ApplicationManager.getApplication().runReadAction(new Runnable() {
150 for (VirtualFile file : files) {
151 if (projectFileIndex.isInContent(file)) {
152 final PsiFile psiFile = myPsiManager.findFile(file);
153 if (psiFile != null) {
154 allFiles.add(psiFile);
161 return allFiles.isEmpty() ? PsiFile.EMPTY_ARRAY : PsiUtilCore.toPsiFileArray(allFiles);
164 public int getTodoCount(@NotNull final VirtualFile file, final IndexPatternProvider patternProvider) {
165 if (myProject.isDefault()) {
168 if (file instanceof VirtualFileWindow) return -1;
169 final FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
171 for (IndexPattern indexPattern : patternProvider.getIndexPatterns()) {
172 count += fetchCount(fileBasedIndex, file, indexPattern);
177 public int getTodoCount(@NotNull final VirtualFile file, final IndexPattern pattern) {
178 if (myProject.isDefault()) {
181 if (file instanceof VirtualFileWindow) return -1;
182 return fetchCount(FileBasedIndex.getInstance(), file, pattern);
185 private int fetchCount(final FileBasedIndex fileBasedIndex, final VirtualFile file, final IndexPattern indexPattern) {
186 final int[] count = {0};
187 fileBasedIndex.processValues(
188 TodoIndex.NAME, new TodoIndexEntry(indexPattern.getPatternString(), indexPattern.isCaseSensitive()), file,
189 new FileBasedIndex.ValueProcessor<Integer>() {
190 public boolean process(final VirtualFile file, final Integer value) {
191 count[0] += value.intValue();
194 }, GlobalSearchScope.fileScope(myProject, file));