diff --git a/platform/core-api/src/com/intellij/openapi/project/DumbModeTask.java b/platform/core-api/src/com/intellij/openapi/project/DumbModeTask.java index 56fab1229f48..b7a0e0ee1cbf 100644 --- a/platform/core-api/src/com/intellij/openapi/project/DumbModeTask.java +++ b/platform/core-api/src/com/intellij/openapi/project/DumbModeTask.java @@ -20,9 +20,32 @@ import com.intellij.openapi.progress.ProgressIndicator; import org.jetbrains.annotations.NotNull; /** + * A task that should be executed in IDE dumb mode, via {@link DumbService#queueTask(DumbModeTask)}. + * * @author peter */ public abstract class DumbModeTask implements Disposable { + private final Object myEquivalenceObject; + + public DumbModeTask() { + myEquivalenceObject = this; + } + + /** + * @param equivalenceObject see {@link #getEquivalenceObject()} + */ + public DumbModeTask(@NotNull Object equivalenceObject) { + myEquivalenceObject = equivalenceObject; + } + + /** + * @return an object whose {@link Object#equals(Object)} determines task equivalence. If several equivalent tasks are queued + * for dumb mode execution at once, only one of them will be executed. By default the task object itself is returned. + */ + @NotNull + public final Object getEquivalenceObject() { + return myEquivalenceObject; + } public abstract void performInDumbMode(@NotNull ProgressIndicator indicator); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java index 9d57ec867e83..55de678f3017 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexProjectHandler.java @@ -20,7 +20,6 @@ package com.intellij.util.indexing; import com.intellij.ide.IdeBundle; -import com.intellij.ide.caches.FileContent; import com.intellij.ide.startup.StartupManagerEx; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.TransactionGuard; @@ -38,7 +37,6 @@ import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileVisitor; -import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -141,7 +139,7 @@ public class FileBasedIndexProjectHandler extends AbstractProjectComponent imple return null; } - return new DumbModeTask() { + return new DumbModeTask(project.getComponent(FileBasedIndexProjectHandler.class)) { @Override public void performInDumbMode(@NotNull ProgressIndicator indicator) { final Collection files = index.getFilesToUpdate(project); diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index d30e47a2b84e..f6abe730fb68 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -46,7 +46,9 @@ import org.jetbrains.annotations.TestOnly; import javax.swing.*; import java.util.ArrayList; +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class DumbServiceImpl extends DumbService implements Disposable, ModificationTracker { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.project.DumbServiceImpl"); @@ -64,6 +66,7 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica private boolean myUpdateFinishedQueued; private final DumbModeListener myPublisher; private long myModificationCount; + private final Set myQueuedEquivalences = new HashSet<>(); private final Queue myUpdatesQueue = new Queue<>(5); /** @@ -99,6 +102,7 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica public void dispose() { ApplicationManager.getApplication().assertIsDispatchThread(); myUpdatesQueue.clear(); + myQueuedEquivalences.clear(); myRunWhenSmartQueue.clear(); for (DumbModeTask task : new ArrayList<>(myProgresses.keySet())) { cancelTask(task); @@ -190,6 +194,11 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica return; } + if (!myQueuedEquivalences.add(task.getEquivalenceObject())) { + Disposer.dispose(task); + return; + } + final DumbModePermission permission = schedulerPermission != null ? schedulerPermission : getEdtPermission(); myProgresses.put(task, new ProgressIndicatorBase()); @@ -493,6 +502,7 @@ public class DumbServiceImpl extends DumbService implements Disposable, Modifica } DumbModeTask queuedTask = myUpdatesQueue.pullFirst(); + myQueuedEquivalences.remove(queuedTask.getEquivalenceObject()); ProgressIndicatorEx indicator = myProgresses.get(queuedTask); if (indicator.isCanceled()) { Disposer.dispose(queuedTask);