Indices: do not iterate content of visited roots twice
authorAlexander Zolotov <goldifit@gmail.com>
Mon, 29 May 2017 13:36:27 +0000 (16:36 +0300)
committerAlexander Zolotov <goldifit@gmail.com>
Tue, 30 May 2017 18:58:56 +0000 (21:58 +0300)
While iterating ProjectFileIndex visited roots should not be processed,
their content should be skipped

java/java-tests/testSrc/com/intellij/java/openapi/roots/impl/DirectoryIndexTest.java
platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexScanRunnableCollectorImpl.java
platform/projectModel-api/src/com/intellij/openapi/roots/FileIndex.java
platform/projectModel-impl/src/com/intellij/openapi/roots/impl/FileIndexBase.java
platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ModuleFileIndexImpl.java
platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectFileIndexImpl.java

index c13e80a89cfaa5d2727c62035d8a49fc4796beab..a2552d61c6eddf7ee7e978cd106707e63659765c 100644 (file)
@@ -58,7 +58,7 @@ public class DirectoryIndexTest extends DirectoryIndexTestCase {
   private VirtualFile myPack1Dir, myPack2Dir;
   private VirtualFile myFileLibDir, myFileLibSrc, myFileLibCls;
   private VirtualFile myLibAdditionalOutsideDir, myLibAdditionalOutsideSrcDir, myLibAdditionalOutsideExcludedDir;
-  private VirtualFile myLibDir, myLibSrcDir, myLibAdditionalDir, myLibAdditionalSrcDir, myLibAdditionalExcludedDir, myLibClsDir;
+  private VirtualFile myLibDir, myLibSrcDir, myLibAdditionalDir, myLibAdditionalSrcDir, myLibAdditionalSrcFile, myLibAdditionalExcludedDir, myLibClsDir;
   private VirtualFile myCvsDir;
   private VirtualFile myExcludeDir;
   private VirtualFile myOutputDir;
@@ -91,11 +91,12 @@ public class DirectoryIndexTest extends DirectoryIndexTestCase {
                 lib
                     src
                       exc
-                    additional-lib
-                      src
-                      excluded
                     cls
                       exc
+                additional-lib
+                    src
+                    a.txt
+                    excluded
                 module2
                     src2
                         CVS
@@ -124,8 +125,9 @@ public class DirectoryIndexTest extends DirectoryIndexTestCase {
       myLibDir = createChildDirectory(myModule1Dir, "lib");
       myLibSrcDir = createChildDirectory(myLibDir, "src");
       myExcludedLibSrcDir = createChildDirectory(myLibSrcDir, "exc");
-      myLibAdditionalDir = createChildDirectory(myLibDir, "additional-lib");
+      myLibAdditionalDir = createChildDirectory(myModule1Dir, "additional-lib");
       myLibAdditionalSrcDir = createChildDirectory(myLibAdditionalDir, "src");
+      myLibAdditionalSrcFile = createChildData(myLibAdditionalDir, "a.txt");
       myLibAdditionalExcludedDir = createChildDirectory(myLibAdditionalDir, "excluded");
       myLibClsDir = createChildDirectory(myLibDir, "cls");
       myExcludedLibClsDir = createChildDirectory(myLibClsDir, "exc");
@@ -621,6 +623,15 @@ public class DirectoryIndexTest extends DirectoryIndexTestCase {
     assertInProject(LocalFileSystem.getInstance().findFileByIoFile(f));
   }
 
+  public void testSyntheticLibraryInContent() {
+    ModuleRootModificationUtil.addContentRoot(myModule, FileUtil.toSystemIndependentName(myModule1Dir.getPath()));
+    checkInfo(myLibAdditionalDir, myModule, false, true, null, null);
+    checkInfo(myLibAdditionalSrcDir, myModule, false, true, null, null);
+    checkInfo(myLibAdditionalExcludedDir, myModule, false, false, null, null);
+    assertInProject(myLibAdditionalExcludedDir);
+    assertIndexableContent(Arrays.asList(myLibAdditionalSrcDir, myLibAdditionalSrcFile, myLibAdditionalExcludedDir), null);
+  }
+
   public void testLibraryDirInContent() {
     ModuleRootModificationUtil.addModuleLibrary(myModule, myModule1Dir.getUrl());
 
@@ -636,11 +647,6 @@ public class DirectoryIndexTest extends DirectoryIndexTestCase {
 
     //myModule is included into order entries instead of myModule2 because classes root for libraries dominates on source roots
     checkInfo(myLibSrcDir, myModule, true, true, "", null, myModule, myModule3);
-    checkInfo(myLibAdditionalDir, myModule, true, true, null, null, myModule);
-
-    checkInfo(myLibAdditionalSrcDir, myModule, true, true, null, null, myModule);
-    checkInfo(myLibAdditionalExcludedDir, myModule, true, false, "lib.additional-lib.excluded", null, myModule);
-    assertIndexableContent(Arrays.asList(myLibAdditionalSrcDir, myLibAdditionalExcludedDir), null);
 
     checkInfo(myResDir, myModule, true, false, "", JavaResourceRootType.RESOURCE, myModule);
     assertInstanceOf(assertOneElement(toArray(myIndex.getOrderEntries(assertInProject(myResDir)))), ModuleSourceOrderEntry.class);
index 5b4de6594742cb356667d52ae40925721515547f..2d875f31603e2eb8ed978b240fa712472e609898 100644 (file)
@@ -63,11 +63,7 @@ public class FileBasedIndexScanRunnableCollectorImpl extends FileBasedIndexScanR
       List<Runnable> tasks = new ArrayList<>();
       final Set<VirtualFile> visitedRoots = ContainerUtil.newConcurrentSet();
 
-      tasks.add(() -> myProjectFileIndex.iterateContent(
-        (file) ->
-          (file.isDirectory() && !visitedRoots.add(file)) || processor.processFile(file))
-      );
-
+      tasks.add(() -> myProjectFileIndex.iterateContent(processor, file -> !file.isDirectory() || visitedRoots.add(file)));
       /*
       Module[] modules = ModuleManager.getInstance(project).getModules();
       for(final Module module: modules) {
index abb79aecfa9c7927b12ee917c5207a566bae9656..a82e6cef1f2695765fdcc0aa86120fd6f3693da1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileFilter;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
 
 import java.util.Set;
@@ -38,6 +39,18 @@ public interface FileIndex {
   boolean iterateContent(@NotNull ContentIterator processor);
 
   /**
+   * Same as {@link #iterateContent(ContentIterator)} but allows to pass {@code filter} to
+   * provide filtering in condition for directories.
+   * <p>
+   * If <code>filter</code> returns false on a directory, the directory won't be processed, but iteration will go on.
+   * <p>
+   * {@code null} filter means that all directories should be processed.
+   *
+   * @return false if files processing was stopped ({@link ContentIterator#processFile(VirtualFile)} returned false)
+   */
+  boolean iterateContent(@NotNull ContentIterator processor, @Nullable VirtualFileFilter filter);
+
+  /**
    * Processes all files and directories in the content under directory <code>dir</code> (including the directory itself) skipping excluded
    * and ignored files and directories. Does nothing if <code>dir</code> is not in the content.
    *
@@ -49,10 +62,12 @@ public interface FileIndex {
    * Same as {@link #iterateContentUnderDirectory(VirtualFile, ContentIterator)} but allows to pass additional <code>customFilter</code> to
    * the iterator, in case you need to skip some file system branches using your own logic. If <code>customFilter</code> returns false on
    * a directory, it won't be processed, but iteration will go on.
+   * <p>
+   * {@code null} filter means that all directories should be processed.
    */
   boolean iterateContentUnderDirectory(@NotNull VirtualFile dir,
                                        @NotNull ContentIterator processor,
-                                       @NotNull VirtualFileFilter customFilter);
+                                       @Nullable VirtualFileFilter customFilter);
 
   /**
    * Returns {@code true} if {@code fileOrDir} is a file or directory under a content root of this project or module and not excluded or
index 9dc464d3e29748288b412d1db81f3d113342e09b..acd2b296fc00d8fba2fecfd413214f2597930456 100644 (file)
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.intellij.openapi.roots.impl;
 
 import com.intellij.injected.editor.VirtualFileWindow;
@@ -11,6 +26,7 @@ import com.intellij.openapi.vfs.VfsUtilCore;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileFilter;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * @author nik
@@ -32,15 +48,21 @@ public abstract class FileIndexBase implements FileIndex {
   protected abstract boolean isScopeDisposed();
 
   @Override
+  public boolean iterateContent(@NotNull ContentIterator processor) {
+    return iterateContent(processor, null);
+  }
+
+  @Override
   public boolean iterateContentUnderDirectory(@NotNull VirtualFile dir,
                                               @NotNull ContentIterator processor,
-                                              @NotNull VirtualFileFilter customFilter) {
-    return iterateContentUnderDirectoryWithFilter(dir, processor, file -> myContentFilter.accept(file) && customFilter.accept(file));
+                                              @Nullable VirtualFileFilter customFilter) {
+    VirtualFileFilter filter = customFilter != null ? file -> myContentFilter.accept(file) && customFilter.accept(file) : myContentFilter;
+    return iterateContentUnderDirectoryWithFilter(dir, processor, filter);
   }
 
   @Override
   public boolean iterateContentUnderDirectory(@NotNull VirtualFile dir, @NotNull ContentIterator processor) {
-    return iterateContentUnderDirectoryWithFilter(dir, processor, myContentFilter);
+    return iterateContentUnderDirectory(dir, processor, null);
   }
 
   private static boolean iterateContentUnderDirectoryWithFilter(@NotNull VirtualFile dir,
index b620fa16f091acba980b547c2eac6a3594e34fae..b46bbc98ccca7d364fb8be4da1a8ca511fc2a3a1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2017 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import com.intellij.openapi.fileTypes.FileTypeRegistry;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.roots.*;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileFilter;
 import com.intellij.util.IncorrectOperationException;
 import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
@@ -42,7 +43,7 @@ public class ModuleFileIndexImpl extends FileIndexBase implements ModuleFileInde
   }
 
   @Override
-  public boolean iterateContent(@NotNull ContentIterator processor) {
+  public boolean iterateContent(@NotNull ContentIterator processor, @Nullable VirtualFileFilter filter) {
     final Set<VirtualFile> contentRoots = ReadAction.compute(() -> {
       if (myModule.isDisposed()) return Collections.emptySet();
 
@@ -65,15 +66,13 @@ public class ModuleFileIndexImpl extends FileIndexBase implements ModuleFileInde
       return result;
     });
     for (VirtualFile contentRoot : contentRoots) {
-      if (!iterateContentUnderDirectory(contentRoot, processor)) {
+      if (!iterateContentUnderDirectory(contentRoot, processor, filter)) {
         return false;
       }
     }
-
     return true;
   }
 
-
   @Override
   public boolean isInContent(@NotNull VirtualFile fileOrDir) {
     DirectoryInfo info = getInfoForFileOrDirectory(fileOrDir);
index faad7333c57e270c45cc0fd8b1d31fe340eee2e9..60767648e79487c3aac085436b3de7f863a697e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2017 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ import com.intellij.openapi.roots.ContentIterator;
 import com.intellij.openapi.roots.OrderEntry;
 import com.intellij.openapi.roots.ProjectFileIndex;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileFilter;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
@@ -47,17 +48,15 @@ public class ProjectFileIndexImpl extends FileIndexBase implements ProjectFileIn
   }
 
   @Override
-  public boolean iterateContent(@NotNull ContentIterator processor) {
-    Module[] modules =
-      ReadAction.compute(() -> ModuleManager.getInstance(myProject).getModules());
+  public boolean iterateContent(@NotNull ContentIterator processor, @Nullable VirtualFileFilter filter) {
+    Module[] modules = ReadAction.compute(() -> ModuleManager.getInstance(myProject).getModules());
     for (final Module module : modules) {
       for (VirtualFile contentRoot : getRootsToIterate(module)) {
-        if (!iterateContentUnderDirectory(contentRoot, processor)) {
+        if (!iterateContentUnderDirectory(contentRoot, processor, filter)) {
           return false;
         }
       }
     }
-
     return true;
   }