diff --git a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java index 7c3a8684a7ee..7b219916d8b0 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java +++ b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java @@ -63,10 +63,7 @@ import org.jetbrains.ide.PooledThreadExecutor; import javax.swing.*; import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; @@ -113,7 +110,7 @@ public class DocumentCommitThread implements Runnable, Disposable, DocumentCommi enable("Listener installed, started"); } - }); + }); } @Override @@ -949,4 +946,21 @@ public class DocumentCommitThread implements Runnable, Disposable, DocumentCommi return lock != null ? lock : ((UserDataHolderEx)document).putUserDataIfAbsent(DOCUMENT_LOCK, new ReentrantLock()); } private static final Key DOCUMENT_LOCK = Key.create("DOCUMENT_LOCK"); + + void cancelTasksOnProjectDispose(@NotNull final Project project) { + synchronized (lock) { + cancelTasksOnProjectDispose(project, documentsToCommit); + cancelTasksOnProjectDispose(project, documentsToApplyInEDT); + } + } + + private void cancelTasksOnProjectDispose(@NotNull Project project, @NotNull HashSetQueue queue) { + for (HashSetQueue.PositionalIterator iterator = queue.iterator(); iterator.hasNext(); ) { + CommitTask commitTask = iterator.next(); + if (commitTask.project == project) { + iterator.remove(); + commitTask.cancel("project is disposed", this); + } + } + } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index f518ab982eb5..ccbefe64ab09 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -33,6 +33,7 @@ import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectLocator; import com.intellij.openapi.project.impl.ProjectImpl; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.core.impl.PomModelImpl; @@ -66,20 +67,21 @@ public class PsiDocumentManagerImpl extends PsiDocumentManagerBase implements Se super(project, psiManager, bus, documentCommitThread); myDocumentCommitThread = documentCommitThread; editorFactory.getEventMulticaster().addDocumentListener(this, project); - MessageBusConnection busConnection = bus.connect(); - busConnection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { + MessageBusConnection connection = bus.connect(); + connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC, new FileDocumentManagerAdapter() { @Override public void fileContentLoaded(@NotNull final VirtualFile virtualFile, @NotNull Document document) { PsiFile psiFile = ReadAction.compute(() -> myProject.isDisposed() || !virtualFile.isValid() ? null : getCachedPsiFile(virtualFile)); fireDocumentCreated(document, psiFile); } }); - busConnection.subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() { + connection.subscribe(DocumentBulkUpdateListener.TOPIC, new DocumentBulkUpdateListener.Adapter() { @Override public void updateFinished(@NotNull Document doc) { documentCommitThread.commitAsynchronously(project, doc, "Bulk update finished", ApplicationManager.getApplication().getDefaultModalityState()); } }); + Disposer.register(project, () -> ((DocumentCommitThread)myDocumentCommitThread).cancelTasksOnProjectDispose(project)); } @Nullable