diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 858f42ec57e2..6fbd35e6d74d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -798,6 +798,7 @@ class Foo { int actions = 5 for (a1 in 0..actions) { + println "a1 = $a1" for (a2 in 0..actions) { myFixture.configureByText("$a1 $a2 .java", src) myFixture.type 'i' diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy index 62c5c9d0fd8e..ced2ee95db92 100644 --- a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy +++ b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy @@ -26,6 +26,7 @@ import com.intellij.psi.PsiDocumentManager import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase import com.intellij.util.ui.UIUtil import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger /** * @author peter @@ -87,21 +88,39 @@ abstract class CompletionAutoPopupTestCase extends LightCodeInsightFixtureTestCa fail("Too long completion") } - protected def joinCommit(Closure cl = {}) { + final static AtomicInteger cnt = new AtomicInteger() + protected def joinCommit(Closure c1={}) { final AtomicBoolean committed = new AtomicBoolean() - edt { - PsiDocumentManager.getInstance(project).cancelAndRunWhenAllCommitted("wait for all comm") { + boolean executed=true; + def closureSeq = cnt.getAndIncrement() + Runnable r = new Runnable() { + @Override + public void run() { ApplicationManager.application.invokeLater { - cl() - committed.set(true) - } + c1(); + committed.set(true) + }; } + + @Override + public String toString() { + return "Closure "+closureSeq; + } + }; + edt { + executed = PsiDocumentManager.getInstance(project).performWhenAllCommitted(r); } + assert !ApplicationManager.getApplication().isWriteAccessAllowed() + assert !ApplicationManager.getApplication().isReadAccessAllowed() + assert !ApplicationManager.getApplication().isDispatchThread() def start = System.currentTimeMillis() while (!committed.get()) { - if (System.currentTimeMillis() - start >= 10000) { + if ((System.currentTimeMillis() - start) % 1000 == 0) { + // println("waiting..." + ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).printStat()) + } + if (System.currentTimeMillis() - start >= 20000) { + fail("too long waiting for a document to be committed. executed: $executed ;") printThreadDump() - fail('too long waiting for a document to be committed') } UIUtil.pump(); } diff --git a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java index eaf7ebfcd2b5..9aafbbb94336 100644 --- a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java +++ b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java @@ -18,7 +18,6 @@ package com.intellij.psi; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,11 +33,10 @@ public abstract class PsiDocumentManager { * Defer action until all documents are committed * must be called from EDT only * - * @param key unique key for this action. Subsequent call with the same key overwrites previous associated action. * @param action to run when all documents committed * @return true if action was run immediately (i.e. all documents are already committed) */ - public abstract boolean cancelAndRunWhenAllCommitted(@NonNls @NotNull Object key, @NotNull Runnable action); + public abstract boolean performWhenAllCommitted(@NotNull Runnable action); /** * Returns the document manager instance for the specified project. diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index d4973948b383..cac94ba7b189 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -57,6 +57,7 @@ import com.intellij.psi.PsiCompiledElement; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopeManager; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; @@ -693,7 +694,8 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx ApplicationManager.getApplication().invokeLater(this, myProject.getDisposed()); } if (PsiDocumentManager.getInstance(myProject).hasUncommitedDocuments()) { - PsiDocumentManager.getInstance(myProject).cancelAndRunWhenAllCommitted("restart daemon when all committed", this); + ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject)).cancelAndRunWhenAllCommitted( + "restart daemon when all committed", this); return; } @@ -716,7 +718,8 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx runnable.run(); } else { - PsiDocumentManager.getInstance(myProject).cancelAndRunWhenAllCommitted("start daemon when all committed", runnable); + ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject)).cancelAndRunWhenAllCommitted( + "start daemon when all committed", runnable); } } }; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java index 87a34547ed31..a87af81063b2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CompletionAutoPopupHandler.java @@ -33,7 +33,6 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; @@ -124,23 +123,23 @@ public class CompletionAutoPopupHandler extends TypedHandlerDelegate { @NotNull final Document document, @NotNull final Runnable runnable) { final long beforeStamp = document.getModificationStamp(); - ((PsiDocumentManagerImpl)PsiDocumentManager.getInstance(project)).performWhenAllCommitted(new Runnable() { - @Override - public void run() { - // later because we may end up in write action here if there was a synchronous commit - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (beforeStamp != document.getModificationStamp()) { - // no luck, will try later - runLaterWithCommitted(project, document, runnable); - } - else { - runnable.run(); - } + PsiDocumentManager.getInstance(project).performWhenAllCommitted(new Runnable() { + @Override + public void run() { + // later because we may end up in write action here if there was a synchronous commit + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (beforeStamp != document.getModificationStamp()) { + // no luck, will try later + runLaterWithCommitted(project, document, runnable); } - }, project.getDisposed()); - } - }); + else { + runnable.run(); + } + } + }, project.getDisposed()); + } + }); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java b/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java index 5bbb2b52ef44..fd59c6ebea85 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/DocumentCommitThread.java @@ -175,6 +175,7 @@ public class DocumentCommitThread implements Runnable, Disposable { indicator.start(); documentsToCommit.addLast(new CommitTask(document, project, indicator, reason)); log("Queued", document, false, reason); + wakeUpQueue(); return true; } } @@ -183,7 +184,7 @@ public class DocumentCommitThread implements Runnable, Disposable { void log(@NonNls String msg, Document document, boolean synchronously, @NonNls Object... args) { if (debug()) { @NonNls - String s = (SwingUtilities.isEventDispatchThread() ? " " : "") + + String s = (SwingUtilities.isEventDispatchThread() ? "- " : "-") + msg + (synchronously ? " (sync)" : "") + (document == null ? "" : "; Document: " + System.identityHashCode(document) + "; stage: " + getCommitStage(document)) @@ -192,7 +193,7 @@ public class DocumentCommitThread implements Runnable, Disposable { for (Object arg : args) { s += "; "+arg; } - //System.out.println(s); + System.out.println(s); synchronized (log) { log.append(s).append("\n"); if (log.length() > 1000000) { @@ -207,8 +208,8 @@ public class DocumentCommitThread implements Runnable, Disposable { } @TestOnly - public void printLog() { - System.err.println(log); + public String getLog() { + return log.toString(); } private void clearLog() { log.setLength(0); @@ -221,6 +222,7 @@ public class DocumentCommitThread implements Runnable, Disposable { } clearLog(); disable("end of test"); + wakeUpQueue(); } private static class CommitTask { 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 99c8d59d44e2..a6c68ebee7d3 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -244,11 +244,17 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec } private final Map actionsWhenAllDocumentsAreCommitted = new LinkedHashMap(); //accessed from EDT only - private static final Object PERFORM_ALWAYS_KEY = new Object(); + private static final Object PERFORM_ALWAYS_KEY = new Object(){ + @Override + public String toString() { + return "PERFORM_ALWAYS"; + } + }; /** Schedules action to be executed when all documents are committed. * @return true if action has been run immediately, or false if action was scheduled for execution later. */ + @Override public boolean performWhenAllCommitted(@NotNull final Runnable action) { ApplicationManager.getApplication().assertIsDispatchThread(); if (myUncommittedDocuments.isEmpty()) { @@ -278,7 +284,6 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec * @param key the (unique) name of the action. This action will overwrite any action which was registered under this key earlier. * @return true if action has been run immediately, or false if action was scheduled for execution later. */ - @Override public boolean cancelAndRunWhenAllCommitted(@NotNull Object key, @NotNull final Runnable action) { ApplicationManager.getApplication().assertIsDispatchThread(); if (myProject.isDisposed()) { @@ -398,6 +403,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec } private void runAfterCommitActions(@NotNull Document document) { + ApplicationManager.getApplication().assertIsDispatchThread(); List list; synchronized (ACTION_AFTER_COMMIT) { list = document.getUserData(ACTION_AFTER_COMMIT); diff --git a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java index 4f6e66eb5c83..3d19cb8fceb7 100644 --- a/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java +++ b/platform/testFramework/src/com/intellij/mock/MockPsiDocumentManager.java @@ -107,7 +107,7 @@ public class MockPsiDocumentManager extends PsiDocumentManager { } @Override - public boolean cancelAndRunWhenAllCommitted(@NotNull Object key, @NotNull Runnable action) { + public boolean performWhenAllCommitted(@NotNull Runnable action) { throw new UnsupportedOperationException(); } }