do not run todo index during project indexing

The todo index employs user-configurable patterns that can significantly slow down indexing process. To solve this problem the todo index is now excluded from the project indexing procedure while still reusing index storage. Later we can switch to gist API for that.

GitOrigin-RevId: fe4020a03bd1fd4a9a109ffc8782ca1c23d42735
This commit is contained in:
Gregory.Shrago
2022-02-28 15:39:56 +03:00
committed by intellij-monorepo-bot
parent 624deace3f
commit 1caf1486bb
12 changed files with 221 additions and 159 deletions

View File

@@ -15,12 +15,17 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.TodoAttributesUtil;
import com.intellij.psi.search.TodoPattern;
import com.intellij.psi.search.UsageSearchContext;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.CommonProcessors;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
public class IdCacheTest extends JavaCodeInsightTestCase {
private VirtualFile myRootDir;
@@ -69,7 +74,7 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
checkResult(new String[]{"2.java", "3.java"}, convert(cache.getFilesWithWord("d", UsageSearchContext.ANY,scope, false)));
checkResult(new String[]{"3.java"}, convert(cache.getFilesWithWord("e", UsageSearchContext.ANY,scope, false)));
checkResult(new String[]{"3.java"}, convert(todocache.getFilesWithTodoItems()));
checkResult(new String[]{"3.java"}, convert(getFilesWithTodoItems(todocache)));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("1.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("2.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(2, todocache.getTodoCount(myRootDir.findChild("3.java"), TodoIndexPatternProvider.getInstance()));
@@ -89,7 +94,7 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
checkResult(new String[]{"2.java", "3.java"}, convert(cache2.getFilesWithWord("d", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(cache2.getFilesWithWord("e", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(todocache2.getFilesWithTodoItems()));
checkResult(new String[]{"3.java"}, convert(getFilesWithTodoItems(todocache2)));
assertEquals(0, todocache2.getTodoCount(myRootDir.findChild("2.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(2, todocache2.getTodoCount(myRootDir.findChild("3.java"), TodoIndexPatternProvider.getInstance()));
}
@@ -109,7 +114,7 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
try{
final TodoCacheManager todocache = TodoCacheManager.SERVICE.getInstance(myProject);
checkResult(new String[]{"2.java"}, convert(todocache.getFilesWithTodoItems()));
checkResult(new String[]{"2.java"}, convert(getFilesWithTodoItems(todocache)));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("1.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(1, todocache.getTodoCount(myRootDir.findChild("2.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("3.java"), TodoIndexPatternProvider.getInstance()));
@@ -140,7 +145,7 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
checkResult(new String[]{"2.java", "3.java"}, convert(cache.getFilesWithWord("d", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(cache.getFilesWithWord("e", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(todocache.getFilesWithTodoItems()));
checkResult(new String[]{"3.java"}, convert(getFilesWithTodoItems(todocache)));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("1.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("2.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(2, todocache.getTodoCount(myRootDir.findChild("3.java"), TodoIndexPatternProvider.getInstance()));
@@ -162,7 +167,7 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
checkResult(new String[]{"2.java", "3.java"}, convert(cache.getFilesWithWord("d", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(cache.getFilesWithWord("e", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(todocache.getFilesWithTodoItems()));
checkResult(new String[]{"3.java"}, convert(getFilesWithTodoItems(todocache)));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("2.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(2, todocache.getTodoCount(myRootDir.findChild("3.java"), TodoIndexPatternProvider.getInstance()));
}
@@ -184,7 +189,7 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
checkResult(new String[]{"2.java", "3.java"}, convert(cache.getFilesWithWord("d", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(cache.getFilesWithWord("e", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"1.java", "3.java", "4.java"}, convert(todocache.getFilesWithTodoItems()));
checkResult(new String[]{"1.java", "3.java", "4.java"}, convert(getFilesWithTodoItems(todocache)));
assertEquals(1, todocache.getTodoCount(myRootDir.findChild("1.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("2.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(2, todocache.getTodoCount(myRootDir.findChild("3.java"), TodoIndexPatternProvider.getInstance()));
@@ -206,11 +211,17 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
checkResult(new String[]{"2.java", "3.java"}, convert(cache.getFilesWithWord("d", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"3.java"}, convert(cache.getFilesWithWord("e", UsageSearchContext.ANY, scope, false)));
checkResult(new String[]{"1.java", "3.java"}, convert(todocache.getFilesWithTodoItems()));
checkResult(new String[]{"1.java", "3.java"}, convert(getFilesWithTodoItems(todocache)));
assertEquals(1, todocache.getTodoCount(myRootDir.findChild("1.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(0, todocache.getTodoCount(myRootDir.findChild("2.java"), TodoIndexPatternProvider.getInstance()));
assertEquals(2, todocache.getTodoCount(myRootDir.findChild("3.java"), TodoIndexPatternProvider.getInstance()));
}
private static PsiFile @NotNull [] getFilesWithTodoItems(@NotNull TodoCacheManager todocache) {
HashSet<PsiFile> files = new HashSet<>();
todocache.processFilesWithTodoItems(new CommonProcessors.CollectProcessor<>(files));
return PsiUtilCore.toPsiFileArray(files);
}
private static VirtualFile[] convert(PsiFile[] psiFiles) {
final VirtualFile[] files = new VirtualFile[psiFiles.length];
@@ -222,13 +233,8 @@ public class IdCacheTest extends JavaCodeInsightTestCase {
private static void checkResult(String[] expected, VirtualFile[] result){
assertEquals(expected.length, result.length);
Arrays.sort(expected);
Arrays.sort(result, (o1, o2) -> {
VirtualFile file1 = o1;
VirtualFile file2 = o2;
return file1.getName().compareTo(file2.getName());
});
Arrays.sort(result, Comparator.comparing(VirtualFile::getName));
for(int i = 0; i < expected.length; i++){
String name = expected[i];

View File

@@ -20,7 +20,6 @@ import com.intellij.psi.impl.JavaPsiFacadeEx;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.cache.impl.id.IdIndex;
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry;
import com.intellij.psi.impl.cache.impl.todo.TodoIndex;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl;
import com.intellij.psi.search.*;
import com.intellij.psi.search.searches.ReferencesSearch;
@@ -117,10 +116,10 @@ public class UpdateCacheTest extends JavaPsiTestCase {
PsiClass objectClass = myJavaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT, GlobalSearchScope.allScope(getProject()));
assertNotNull(objectClass);
checkUsages(objectClass, ArrayUtil.EMPTY_STRING_ARRAY);
FileBasedIndex.getInstance().ensureUpToDate(TodoIndex.NAME, getProject(), GlobalSearchScope.allScope(getProject()));
ensureCachesAreUpToDate();
String projectLocation = myProject.getPresentableUrl();
assert projectLocation != null : myProject;
assertNotNull(projectLocation);
PlatformTestUtil.saveProject(myProject);
VirtualFile content = ModuleRootManager.getInstance(getModule()).getContentRoots()[0];
Project project = myProject;
@@ -158,11 +157,9 @@ public class UpdateCacheTest extends JavaPsiTestCase {
objectClass = myJavaFacade.findClass(CommonClassNames.JAVA_LANG_OBJECT, scope);
assertNotNull(objectClass);
Set<String> filesWithObject =
FileBasedIndex
.getInstance()
.getContainingFiles(IdIndex.NAME, new IdIndexEntry("Object", true), scope)
.stream().map(f -> f.getName()).collect(Collectors.toSet());
Set<String> filesWithObject = FileBasedIndex.getInstance().getContainingFiles(
IdIndex.NAME, new IdIndexEntry("Object", true), scope)
.stream().map(f -> f.getName()).collect(Collectors.toSet());
assertTrue(filesWithObject.contains("1.java"));
checkUsages(objectClass, new String[]{"1.java"});
@@ -215,7 +212,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
}
public void testAddExcludeRoot() {
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to initialize caches
ensureCachesAreUpToDate();
ProjectRootManagerEx rootManager = (ProjectRootManagerEx)ProjectRootManager.getInstance(myProject);
final VirtualFile root = rootManager.getContentRoots()[0];
@@ -245,7 +242,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
PsiTestUtil.addExcludedRoot(myModule, dir);
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to initialize caches
ensureCachesAreUpToDate();
WriteCommandAction.writeCommandAction(getProject()).run(() -> {
VirtualFile newFile = createChildData(dir, "New.java");
@@ -254,7 +251,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to update caches
ensureCachesAreUpToDate();
PsiTestUtil.removeExcludedRoot(myModule, dir);
@@ -279,7 +276,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to initialize caches
ensureCachesAreUpToDate();
PsiTestUtil.addSourceRoot(myModule, root);
@@ -292,7 +289,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
public void testRemoveSourceRoot() {
final VirtualFile root = ModuleRootManager.getInstance(myModule).getContentRoots()[0];
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to initialize caches
ensureCachesAreUpToDate();
WriteCommandAction.writeCommandAction(getProject()).run(() -> {
VirtualFile newFile = createChildData(root, "New.java");
@@ -301,7 +298,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to update caches
ensureCachesAreUpToDate();
VirtualFile[] sourceRoots = ModuleRootManager.getInstance(myModule).getSourceRoots();
LOG.assertTrue(sourceRoots.length == 1);
@@ -349,7 +346,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
ProjectRootManagerEx rootManager = (ProjectRootManagerEx)ProjectRootManager.getInstance(myProject);
final VirtualFile root = rootManager.getContentRoots()[0];
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to initialize caches
ensureCachesAreUpToDate();
WriteCommandAction.writeCommandAction(getProject()).run(() -> {
VirtualFile newFile = createChildData(root, "New.java");
@@ -358,7 +355,7 @@ public class UpdateCacheTest extends JavaPsiTestCase {
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
PsiTodoSearchHelper.SERVICE.getInstance(myProject).findFilesWithTodoItems(); // to update caches
ensureCachesAreUpToDate();
PsiTestUtil.addExcludedRoot(myModule, root);
@@ -392,20 +389,20 @@ public class UpdateCacheTest extends JavaPsiTestCase {
}
}
private void checkTodos(@NonNls String[] expectedFiles){
PsiTodoSearchHelper helper = PsiTodoSearchHelper.SERVICE.getInstance(myProject);
private void checkTodos(@NonNls String[] expectedFiles) {
List<String> names = new ArrayList<>();
PsiTodoSearchHelper.SERVICE.getInstance(myProject).processFilesWithTodoItems(o -> {
names.add(o.getName());
return true;
});
assertEquals(expectedFiles.length, names.size());
PsiFile[] files = helper.findFilesWithTodoItems();
assertEquals(expectedFiles.length, files.length);
Arrays.sort(files, Comparator.comparing(PsiFileSystemItem::getName));
Collections.sort(names);
Arrays.sort(expectedFiles);
assertEquals(Arrays.asList(expectedFiles), names);
}
for(int i = 0; i < expectedFiles.length; i++){
String name = expectedFiles[i];
PsiFile file = files[i];
assertEquals(name, file.getName());
}
private void ensureCachesAreUpToDate() {
FileBasedIndex.getInstance().ensureUpToDate(IdIndex.NAME, myProject, GlobalSearchScope.allScope(myProject));
}
}

View File

@@ -51,7 +51,6 @@ import com.intellij.psi.impl.PsiManagerEx
import com.intellij.psi.impl.cache.impl.id.IdIndex
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry
import com.intellij.psi.impl.cache.impl.id.IdIndexImpl
import com.intellij.psi.impl.cache.impl.todo.TodoIndex
import com.intellij.psi.impl.file.impl.FileManagerImpl
import com.intellij.psi.impl.java.JavaFunctionalExpressionIndex
import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys
@@ -1035,7 +1034,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
TodoPattern[] newPatterns = [pattern]
TodoConfiguration.getInstance().setTodoPatterns(newPatterns)
PlatformTestUtil.dispatchAllEventsInIdeEventQueue()
FileBasedIndex.instance.ensureUpToDate(TodoIndex.NAME, project, GlobalSearchScope.allScope(project))
FileBasedIndex.instance.ensureUpToDate(IdIndex.NAME, project, GlobalSearchScope.allScope(project))
myFixture.addFileToProject("Foo.txt", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
try {
@@ -1053,7 +1052,7 @@ class IndexTest extends JavaCodeInsightFixtureTestCase {
{
try {
progressStarted.countDown()
FileBasedIndex.instance.ensureUpToDate(TodoIndex.NAME, project, GlobalSearchScope.allScope(project))
FileBasedIndex.instance.ensureUpToDate(IdIndex.NAME, project, GlobalSearchScope.allScope(project))
}
catch (ProcessCanceledException ignore) {
canceled[0] = true

View File

@@ -7,30 +7,41 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.impl.cache.TodoCacheManager;
import com.intellij.psi.search.IndexPatternOccurrence;
import com.intellij.psi.search.PsiTodoSearchHelper;
import com.intellij.psi.search.TodoItem;
import com.intellij.psi.search.TodoPattern;
import com.intellij.psi.search.searches.IndexPatternSearch;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public class PsiTodoSearchHelperImpl implements PsiTodoSearchHelper {
private final PsiManagerEx myManager;
private static final TodoItem[] EMPTY_TODO_ITEMS = new TodoItem[0];
private final Project myProject;
public PsiTodoSearchHelperImpl(@NotNull Project project) {
myManager = PsiManagerEx.getInstanceEx(project);
myProject = project;
}
@Override
public PsiFile @NotNull [] findFilesWithTodoItems() {
return TodoCacheManager.SERVICE.getInstance(myManager.getProject()).getFilesWithTodoItems();
HashSet<PsiFile> files = new HashSet<>();
processFilesWithTodoItems(new CommonProcessors.CollectProcessor<>(files));
return PsiUtilCore.toPsiFileArray(files);
}
@Override
public boolean processFilesWithTodoItems(@NotNull Processor<? super PsiFile> processor) {
return TodoCacheManager.SERVICE.getInstance(myProject).processFilesWithTodoItems(processor);
}
@Override
@@ -87,7 +98,7 @@ public class PsiTodoSearchHelperImpl implements PsiTodoSearchHelper {
public int getTodoItemsCount(@NotNull PsiFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null) {
int count = TodoCacheManager.SERVICE.getInstance(myManager.getProject()).getTodoCount(virtualFile, TodoIndexPatternProvider.getInstance());
int count = TodoCacheManager.SERVICE.getInstance(myProject).getTodoCount(virtualFile, TodoIndexPatternProvider.getInstance());
if (count != -1) return count;
}
return findTodoItems(file).length;
@@ -98,7 +109,7 @@ public class PsiTodoSearchHelperImpl implements PsiTodoSearchHelper {
VirtualFile virtualFile = file.getVirtualFile();
int count = 0;
if (virtualFile != null) {
count = TodoCacheManager.SERVICE.getInstance(myManager.getProject()).getTodoCount(virtualFile, pattern.getIndexPattern());
count = TodoCacheManager.SERVICE.getInstance(myProject).getTodoCount(virtualFile, pattern.getIndexPattern());
if (count != -1) return count;
}
TodoItem[] items = findTodoItems(file);

View File

@@ -6,6 +6,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.IndexPattern;
import com.intellij.psi.search.IndexPatternProvider;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
public interface TodoCacheManager {
@@ -21,9 +22,13 @@ public interface TodoCacheManager {
/**
* @return all VirtualFile's that contain todoItems under project roots
* @deprecated Use {@link #processFilesWithTodoItems(Processor)} instead.
*/
@Deprecated
PsiFile @NotNull [] getFilesWithTodoItems();
boolean processFilesWithTodoItems(@NotNull Processor<? super PsiFile> processor);
/**
* @return -1 if it's not known
*/

View File

@@ -3,6 +3,7 @@ package com.intellij.psi.search;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
/**
@@ -22,9 +23,16 @@ public interface PsiTodoSearchHelper {
* Returns the list of all files in the project which have to do items.
*
* @return the list of files with to do items.
* @deprecated Use {@link #processFilesWithTodoItems(Processor)} instead.
*/
@Deprecated
PsiFile @NotNull [] findFilesWithTodoItems();
/**
* Processes all files in the project which have to do items.
*/
boolean processFilesWithTodoItems(@NotNull Processor<? super PsiFile> processor);
/**
* Searches the specified file for to do items.
*

View File

@@ -3,10 +3,9 @@
package com.intellij.psi.impl.cache.impl;
import com.intellij.injected.editor.VirtualFileWindow;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.ManagingFS;
import com.intellij.psi.PsiFile;
@@ -20,16 +19,17 @@ import com.intellij.psi.search.IndexPattern;
import com.intellij.psi.search.IndexPatternProvider;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.CommonProcessors;
import com.intellij.util.Processor;
import com.intellij.util.containers.ConcurrentBitSet;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.IntPredicate;
public class IndexTodoCacheManagerImpl implements TodoCacheManager {
private static final Logger LOG = Logger.getInstance(IndexTodoCacheManagerImpl.class);
@@ -42,28 +42,42 @@ public class IndexTodoCacheManagerImpl implements TodoCacheManager {
@Override
public PsiFile @NotNull [] getFilesWithTodoItems() {
if (myProject.isDefault()) {
return PsiFile.EMPTY_ARRAY;
}
HashSet<PsiFile> files = new HashSet<>();
processFilesWithTodoItems(new CommonProcessors.CollectProcessor<>(files));
return PsiUtilCore.toPsiFileArray(files);
}
@Override
public boolean processFilesWithTodoItems(@NotNull Processor<? super PsiFile> processor) {
if (myProject.isDefault()) return true;
GlobalSearchScope scope = GlobalSearchScope.allScope(myProject);
ConcurrentBitSet idSet = ConcurrentBitSet.create();
ManagingFS fs = ManagingFS.getInstance();
FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
Set<PsiFile> allFiles = new HashSet<>();
PsiManager psiManager = PsiManager.getInstance(myProject);
DumbModeAccessType.RELIABLE_DATA_ONLY.ignoreDumbMode(() -> {
GlobalSearchScope scope = GlobalSearchScope.allScope(myProject);
fileBasedIndex.processAllKeys(TodoIndex.NAME, fileId -> {
VirtualFile file = fs.findFileById(fileId);
if (file == null || !scope.contains(file)) return true;
ReadAction.run(() -> {
if (file.isValid() && TodoIndexers.belongsToProject(myProject, file)) {
ContainerUtil.addIfNotNull(allFiles, psiManager.findFile(file));
}
});
IntPredicate consumer = fileId -> {
VirtualFile file = fs.findFileById(fileId);
if (file == null || !file.isValid() || !scope.contains(file) || !TodoIndexers.belongsToProject(myProject, file)) return true;
PsiFile psiFile = psiManager.findFile(file);
return psiFile == null || processor.process(psiFile);
};
DumbModeAccessType.RAW_INDEX_DATA_ACCEPTABLE.ignoreDumbMode(() -> {
FileBasedIndex.getInstance().processAllKeys(TodoIndex.NAME, fileId -> {
idSet.set(fileId);
return true;
}, scope, null);
});
return allFiles.isEmpty() ? PsiFile.EMPTY_ARRAY : PsiUtilCore.toPsiFileArray(allFiles);
for (int fileId = idSet.nextSetBit(0); fileId > 0; fileId = idSet.nextSetBit(fileId + 1)) {
if (IndexingStamp.isFileIndexedStateCurrent(fileId, TodoIndex.NAME) != FileIndexingState.UP_TO_DATE) {
idSet.clear(fileId);
}
else if (!consumer.test(fileId)) return false;
}
IdFilter filter = ((FileBasedIndexEx)FileBasedIndex.getInstance()).extractIdFilter(scope, myProject);
if (!FileBasedIndexScanUtil.doProcessAllKeys(TodoIndex.NAME, fileId -> idSet.set(fileId) || consumer.test(fileId), scope, filter)) {
return false;
}
return true;
}
@Override
@@ -77,56 +91,37 @@ public class IndexTodoCacheManagerImpl implements TodoCacheManager {
}
private int getTodoCountImpl(@NotNull VirtualFile file, IndexPattern @NotNull ... indexPatterns) {
if (myProject.isDefault()) {
return 0;
}
if (file instanceof VirtualFileWindow) return -1;
if (file instanceof VirtualFileWindow) {
return -1;
}
Map<TodoIndexEntry, Integer> data = getTodoMap(myProject, file);
if (data == null || data.isEmpty()) return 0;
if (file instanceof LightVirtualFile) {
return calculateTodoCount((LightVirtualFile)file, indexPatterns);
int result = 0;
for (IndexPattern pattern : indexPatterns) {
result += data.getOrDefault(new TodoIndexEntry(pattern.getPatternString(), pattern.isCaseSensitive()), 0);
}
if (!TodoIndexers.belongsToProject(myProject, file)) {
return 0;
}
return fetchTodoCountFromIndex(file, indexPatterns);
return result;
}
private int calculateTodoCount(@NotNull LightVirtualFile file, IndexPattern @NotNull [] indexPatterns) {
public static @Nullable Map<TodoIndexEntry, Integer> getTodoMap(@NotNull Project project, @NotNull VirtualFile file) {
if (project.isDefault()) return null;
if (file instanceof VirtualFileWindow) return null;
return file instanceof LightVirtualFile ? calcTodoMap(project, (LightVirtualFile)file) :
TodoIndexers.belongsToProject(project, file) ? getTodoMapFromIndex(project, file) : null;
}
private static @Nullable Map<TodoIndexEntry, Integer> calcTodoMap(@NotNull Project project, @NotNull LightVirtualFile file) {
CharSequence content = file.getContent();
if (StringUtil.isEmpty(content)) return null;
TodoIndex extension = FileBasedIndexExtension.EXTENSION_POINT_NAME.findExtension(TodoIndex.class);
if (extension == null) return 0;
try {
FileContent fc = FileContentImpl.createByFile(file, myProject);
Map<Integer, Map<TodoIndexEntry, Integer>> data = extension.getIndexer().map(fc);
return getTodoCountForInputData(ContainerUtil.getFirstItem(data.values()), indexPatterns);
}
catch (IOException e) {
LOG.error(e);
return 0;
}
if (extension == null) return null;
FileContent fc = FileContentImpl.createByText(file, content, project);
Map<Integer, Map<TodoIndexEntry, Integer>> data = extension.getIndexer().map(fc);
return ContainerUtil.getFirstItem(data.values());
}
private int fetchTodoCountFromIndex(@NotNull VirtualFile file, IndexPattern @NotNull [] indexPatterns) {
Ref<Map<TodoIndexEntry, Integer>> inputData = Ref.create();
DumbModeAccessType.RELIABLE_DATA_ONLY.ignoreDumbMode(() -> {
Map<TodoIndexEntry, Integer> data = FileBasedIndex.getInstance().getSingleEntryIndexData(TodoIndex.NAME, file, myProject);
inputData.set(data);
});
return getTodoCountForInputData(inputData.get(), indexPatterns);
}
private static int getTodoCountForInputData(@Nullable Map<TodoIndexEntry, Integer> data, IndexPattern @NotNull [] indexPatterns) {
if (data == null) return 0;
return Arrays
.stream(indexPatterns)
.map(p -> new TodoIndexEntry(p.getPatternString(), p.isCaseSensitive()))
.mapToInt(e -> data.getOrDefault(e, 0))
.sum();
private static @Nullable Map<TodoIndexEntry, Integer> getTodoMapFromIndex(@NotNull Project project, @NotNull VirtualFile file) {
Map<Integer, Map<TodoIndexEntry, Integer>> map = FileBasedIndexScanUtil.getIndexData(TodoIndex.NAME, project, file);
return map == null ? null : ContainerUtil.getFirstItem(map.values());
}
}

View File

@@ -781,6 +781,9 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
if (project != null && project.isDefault()) {
LOG.error("FileBasedIndex should not receive default project");
}
if (FileBasedIndexScanUtil.isManuallyManaged(indexId)) {
return true;
}
if (ActionUtil.isDumbMode(project) && getCurrentDumbModeAccessType_NoDumbChecks() == null) {
handleDumbMode(project);
}
@@ -1213,7 +1216,10 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
@Override
public void requestRebuild(@NotNull final ID<?, ?> indexId, final @NotNull Throwable throwable) {
if (!myRegisteredIndexes.isExtensionsDataLoaded()) {
if (FileBasedIndexScanUtil.isManuallyManaged(indexId)) {
advanceIndexVersion(indexId);
}
else if (!myRegisteredIndexes.isExtensionsDataLoaded()) {
IndexDataInitializer.submitGenesisTask(() -> {
waitUntilIndicesAreInitialized(); // should be always true here since the genesis pool is sequential
doRequestRebuild(indexId, throwable);
@@ -1397,6 +1403,8 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
List<ID<?, ?>> affectedIndexCandidates = getAffectedIndexCandidates(indexedFile);
//noinspection ForLoopReplaceableByForEach
for (int i = 0, size = affectedIndexCandidates.size(); i < size; ++i) {
ID<?, ?> indexId = affectedIndexCandidates.get(i);
if (FileBasedIndexScanUtil.isManuallyManaged(indexId)) continue;
ProgressManager.checkCanceled();
if (fc == null) {
@@ -1409,7 +1417,6 @@ public final class FileBasedIndexImpl extends FileBasedIndexEx {
ProgressManager.checkCanceled();
}
final ID<?, ?> indexId = affectedIndexCandidates.get(i);
boolean update;
boolean acceptedAndRequired = acceptsInput(indexId, fc) && getIndexingState(fc, indexId).updateRequired();
if (acceptedAndRequired) {

View File

@@ -9,6 +9,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.NoAccessDuringPsiEvents;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.FilesScanExecutor;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.registry.Registry;
@@ -24,8 +25,10 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Processor;
import com.intellij.util.SlowOperations;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.impl.InputData;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -39,6 +42,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
@ApiStatus.Internal
public final class FileBasedIndexScanUtil {
private static void ensureUpToDate(@NotNull ID<?, ?> indexId) {
@@ -49,6 +53,13 @@ public final class FileBasedIndexScanUtil {
((FileBasedIndexImpl)FileBasedIndex.getInstance()).getChangedFilesCollector().processFilesToUpdateInReadAction();
}
public static <K, V> @Nullable Map<K, V> getIndexData(@NotNull ID<K, V> indexId,
@Nullable Project project,
@NotNull VirtualFile file) {
ensureUpToDate(indexId);
return getIndexer(indexId, project, true).apply(file);
}
static <K> @Nullable Boolean processAllKeys(@NotNull ID<K, ?> indexId,
@NotNull Processor<? super K> processor,
@NotNull GlobalSearchScope scope,
@@ -66,21 +77,26 @@ public final class FileBasedIndexScanUtil {
return threadProcessor.process(() -> processor.process(fileType));
}) && threadProcessor.processQueue();
}
else if (indexId == TodoIndex.NAME && Registry.is("indexing.todo.over.vfs") ||
indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
Project project = scope.getProject();
InThisThreadProcessor threadProcessor = new InThisThreadProcessor();
Function<VirtualFile, ? extends Map<K, ?>> indexer = getIndexer(indexId, project, false);
return processFilesInScope(indexId, scope, false, idFilter, file -> {
Map<K, ?> map = indexer.apply(file);
if (map == null) return true;
Collection<K> keys = map.keySet();
return threadProcessor.process(() -> ContainerUtil.process(keys, processor));
}) && threadProcessor.processQueue();
else if (indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
return doProcessAllKeys(indexId, processor, scope, idFilter);
}
return null;
}
public static <K> boolean doProcessAllKeys(@NotNull ID<K, ?> indexId,
@NotNull Processor<? super K> processor,
@NotNull GlobalSearchScope scope,
@Nullable IdFilter idFilter) {
Project project = scope.getProject();
InThisThreadProcessor threadProcessor = new InThisThreadProcessor();
Function<VirtualFile, ? extends Map<K, ?>> indexer = getIndexer(indexId, project, false);
return processFilesInScope(indexId, scope, false, idFilter, file -> {
Map<K, ?> map = indexer.apply(file);
if (map == null) return true;
return threadProcessor.process(() -> ContainerUtil.process(map.keySet(), processor));
}) && threadProcessor.processQueue();
}
static <K, V> @Nullable Boolean processValuesInScope(@NotNull ID<K, V> indexId,
@NotNull K dataKey,
boolean ensureValueProcessedOnce,
@@ -119,23 +135,31 @@ public final class FileBasedIndexScanUtil {
}) && !(ensureValueProcessedOnce && stoppedByVal.get())) return false;
return threadProcessor.processQueue();
}
else if (indexId == TodoIndex.NAME && Registry.is("indexing.todo.over.vfs") ||
indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
Project project = scope.getProject();
InThisThreadProcessor threadProcessor = new InThisThreadProcessor();
ConcurrentHashMap<V, Boolean> visitedValues = ensureValueProcessedOnce ? new ConcurrentHashMap<>() : null;
Function<VirtualFile, ? extends Map<K, V>> indexer = getIndexer(indexId, project, false);
return processFilesInScope(indexId, scope, false, idFilter, file -> {
Map<K, V> map = indexer.apply(file);
V value = map == null ? null : map.get(dataKey);
if (value == null) return true;
if (ensureValueProcessedOnce && visitedValues.put(value, true) != null) return true;
return threadProcessor.process(() -> processor.process(file, value));
}) && threadProcessor.processQueue();
else if (indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
return doProcessValuesInScope(indexId, dataKey, ensureValueProcessedOnce, scope, idFilter, processor);
}
return null;
}
public static <K, V> boolean doProcessValuesInScope(@NotNull ID<K, V> indexId,
@NotNull K dataKey,
boolean ensureValueProcessedOnce,
@NotNull GlobalSearchScope scope,
@Nullable IdFilter idFilter,
FileBasedIndex.@NotNull ValueProcessor<? super V> processor) {
Project project = scope.getProject();
InThisThreadProcessor threadProcessor = new InThisThreadProcessor();
ConcurrentHashMap<V, Boolean> visitedValues = ensureValueProcessedOnce ? new ConcurrentHashMap<>() : null;
Function<VirtualFile, ? extends Map<K, V>> indexer = getIndexer(indexId, project, false);
return processFilesInScope(indexId, scope, false, idFilter, file -> {
Map<K, V> map = indexer.apply(file);
V value = map == null ? null : map.get(dataKey);
if (value == null) return true;
if (ensureValueProcessedOnce && visitedValues.put(value, true) != null) return true;
return threadProcessor.process(() -> processor.process(file, value));
}) && threadProcessor.processQueue();
}
private static <K, V> @Nullable FileBasedIndexExtension<K, V> findIndexExtension(@NotNull ID<K, V> id) {
for (FileBasedIndexExtension<?, ?> extension : FileBasedIndexExtension.EXTENSION_POINT_NAME.getExtensionList()) {
if (extension.getName() == id) {
@@ -151,8 +175,7 @@ public final class FileBasedIndexScanUtil {
@NotNull VirtualFile file,
@NotNull GlobalSearchScope scope,
@NotNull FileBasedIndex.ValueProcessor<? super V> processor) {
if (indexId == TodoIndex.NAME && Registry.is("indexing.todo.over.vfs") ||
indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
if (indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
Map<K, V> map = getIndexer(indexId, scope.getProject(), false).apply(file);
V value = map == null ? null : map.get(dataKey);
if (value == null) return true;
@@ -166,8 +189,7 @@ public final class FileBasedIndexScanUtil {
@NotNull GlobalSearchScope scope,
@Nullable Condition<? super V> valueChecker,
@NotNull Processor<? super VirtualFile> processor) {
if (indexId == TodoIndex.NAME && Registry.is("indexing.todo.over.vfs") ||
indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
if (indexId == IdIndex.NAME && Registry.is("indexing.id.over.vfs")) {
Project project = scope.getProject();
InThisThreadProcessor threadProcessor = new InThisThreadProcessor();
Function<VirtualFile, ? extends Map<K, V>> indexer = getIndexer(indexId, project, false);
@@ -239,15 +261,28 @@ public final class FileBasedIndexScanUtil {
private static @NotNull <K, V> Function<VirtualFile, ? extends Map<K, V>> getIndexer(@NotNull ID<K, V> indexId,
@Nullable Project project,
boolean binary) {
UpdatableIndex<K, V, FileContent, ?> index = ((FileBasedIndexEx)FileBasedIndex.getInstance()).getIndex(indexId);
FileBasedIndexExtension<K, V> indexExtension = Objects.requireNonNull(findIndexExtension(indexId));
FileBasedIndex.InputFilter inputFilter = indexExtension.getInputFilter();
DataIndexer<K, V, FileContent> indexer = indexExtension.getIndexer();
return file -> {
if (FileBasedIndexEx.acceptsInput(inputFilter, new IndexedFileImpl(file, project))) {
FileContent content = getFileContent(file, project, binary);
return content == null ? null : indexer.map(content);
if (!FileBasedIndexEx.acceptsInput(inputFilter, new IndexedFileImpl(file, project))) return null;
int fileId = FileBasedIndex.getFileId(file);
if (IndexingStamp.isFileIndexedStateCurrent(fileId, TodoIndex.NAME) == FileIndexingState.UP_TO_DATE) {
try {
return index.getIndexedFileData(fileId);
}
catch (StorageException e) {
throw new RuntimeException(e);
}
}
return null;
FileContent content = getFileContent(file, project, binary);
Map<K, V> map = content == null ? null : indexer.map(content);
InputData<K, V> inputData = map == null || map.isEmpty() ? InputData.empty() : new InputData<>(map) {};
Computable<Boolean> computable = index.prepareUpdate(fileId, inputData);
ProgressManager.getInstance().computeInNonCancelableSection(computable::compute);
IndexingStamp.setFileIndexedStateCurrent(fileId, indexId);
return map;
};
}
@@ -267,6 +302,10 @@ public final class FileBasedIndexScanUtil {
}
}
public static boolean isManuallyManaged(@NotNull ID<?, ?> id) {
return id == TodoIndex.NAME;
}
private static class InThisThreadProcessor {
final Thread thread = Thread.currentThread();
final ConcurrentLinkedQueue<BooleanSupplier> queue = new ConcurrentLinkedQueue<>();

View File

@@ -121,6 +121,7 @@ final class UnindexedFilesFinder {
//noinspection ForLoopReplaceableByForEach
for (int i = 0, size = affectedIndexCandidates.size(); i < size; ++i) {
final ID<?, ?> indexId = affectedIndexCandidates.get(i);
if (FileBasedIndexScanUtil.isManuallyManaged(indexId)) continue;
try {
if (myFileBasedIndex.needsFileContentLoading(indexId)) {
FileIndexingState fileIndexingState = myFileBasedIndex.shouldIndexFile(indexedFile, indexId);

View File

@@ -2036,8 +2036,6 @@ indexing.filename.over.vfs.with.reverse.index=true
indexing.filename.over.vfs.with.reverse.index.description=Build reverse name index for VFS-based implementation for FilenameIndex
indexing.filetype.over.vfs=false
indexing.filetype.over.vfs.description=Use VFS-based implementation for FiletypeIndex
indexing.todo.over.vfs=false
indexing.todo.over.vfs.description=Use VFS-based implementation for TodoIndex
indexing.id.over.vfs=false
indexing.id.over.vfs.description=Use VFS-based implementation for IdIndex

View File

@@ -7,9 +7,8 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.ManagingFS;
import com.intellij.psi.impl.cache.TodoCacheManager;
import com.intellij.psi.impl.cache.impl.todo.TodoIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubUpdatingIndex;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.indexing.FileBasedIndex;
@@ -31,7 +30,6 @@ public class PyIndexingTest extends PyTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
final String testName = getTestName(false);
myFixture.copyDirectoryToProject(TEST_DIRECTORY + testName, "");
@@ -48,12 +46,10 @@ public class PyIndexingTest extends PyTestCase {
private static List<VirtualFile> getTodoFiles(@NotNull Project project) {
List<VirtualFile> files = new ArrayList<>();
ManagingFS fs = ManagingFS.getInstance();
FileBasedIndex.getInstance().processAllKeys(TodoIndex.NAME, fileId -> {
VirtualFile file = fs.findFileById(fileId);
if (file != null) files.add(file);
TodoCacheManager.SERVICE.getInstance(project).processFilesWithTodoItems(psi -> {
files.add(psi.getVirtualFile());
return true;
}, GlobalSearchScope.allScope(project), null);
});
return files;
}