From 314333e4e9b376ed883fd7ca6222f17481e2eecc Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Wed, 28 Dec 2016 18:41:32 +0300 Subject: [PATCH] avoid editor (and project) leaking in tests (from pending task to be executed in EDT in AsyncEditorLoader) also makes sure editor asynchronous loading always 'finishes' (as reported by AsyncEditorLoader.isEditorLoaded) even if exception occurred during loading --- .../impl/text/AsyncEditorLoader.java | 34 +++++++++++-------- .../fileEditor/NonProjectFileAccessTest.java | 5 ++- .../testFramework/EditorTestUtil.java | 13 +++++++ .../impl/CodeInsightTestFixtureImpl.java | 1 + 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java index 559d9dd049b6..9f2166425e61 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/text/AsyncEditorLoader.java @@ -91,23 +91,27 @@ public class AsyncEditorLoader { long startStamp = myEditor.getDocument().getModificationStamp(); return ourExecutor.submit(() -> { Ref ref = new Ref<>(); - while (!myEditorComponent.isDisposed()) { - ProgressIndicatorUtils.runWithWriteActionPriority( - () -> ref.set(psiDocumentManager.commitAndRunReadAction(() -> myProject.isDisposed() ? EmptyRunnable.INSTANCE - : myTextEditor.loadEditorInBackground())), - new ProgressIndicatorBase() - ); - Runnable continuation = ref.get(); - if (continuation != null) { - invokeLater(() -> { - if (startStamp == myEditor.getDocument().getModificationStamp()) loadingFinished(continuation); - else if (!myProject.isDisposed() && !myEditorComponent.isDisposed()) scheduleLoading(); - }); - return continuation; + try { + while (!myEditorComponent.isDisposed()) { + ProgressIndicatorUtils.runWithWriteActionPriority( + () -> ref.set(psiDocumentManager.commitAndRunReadAction(() -> myProject.isDisposed() ? EmptyRunnable.INSTANCE + : myTextEditor.loadEditorInBackground())), + new ProgressIndicatorBase() + ); + Runnable continuation = ref.get(); + if (continuation != null) { + invokeLater(() -> { + if (startStamp == myEditor.getDocument().getModificationStamp()) loadingFinished(continuation); + else if (!myProject.isDisposed() && !myEditorComponent.isDisposed()) scheduleLoading(); + }); + return continuation; + } + TimeUnit.MILLISECONDS.sleep(RETRY_TIME_MS); } - TimeUnit.MILLISECONDS.sleep(RETRY_TIME_MS); } - invokeLater(() -> loadingFinished(null)); + finally { + if (ref.isNull()) invokeLater(() -> loadingFinished(null)); + } return null; }); } diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/NonProjectFileAccessTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/NonProjectFileAccessTest.java index ae9e1795fbbd..cab8c8f3a88d 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/NonProjectFileAccessTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/fileEditor/NonProjectFileAccessTest.java @@ -38,6 +38,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.WritingAccessProvider; +import com.intellij.testFramework.EditorTestUtil; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.ui.EditorNotifications; import com.intellij.ui.EditorNotificationsImpl; @@ -393,7 +394,9 @@ public class NonProjectFileAccessTest extends HeavyFileEditorManagerTestCase { private Editor getEditor(VirtualFile file) { myOpenedFiles.add(file); - return FileEditorManager.getInstance(getProject()).openTextEditor(new OpenFileDescriptor(getProject(), file, 0), false); + Editor editor = FileEditorManager.getInstance(getProject()).openTextEditor(new OpenFileDescriptor(getProject(), file, 0), false); + EditorTestUtil.waitForLoading(editor); + return editor; } protected void typeInChar(Editor e, char c) { diff --git a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java index 1c59198cceec..cc46819bc025 100644 --- a/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/EditorTestUtil.java @@ -20,6 +20,7 @@ import com.intellij.injected.editor.EditorWindow; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.impl.SimpleDataContext; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.*; @@ -34,12 +35,14 @@ import com.intellij.openapi.editor.impl.SoftWrapModelImpl; import com.intellij.openapi.editor.impl.softwrap.SoftWrapDrawingType; import com.intellij.openapi.editor.impl.softwrap.SoftWrapPainter; import com.intellij.openapi.editor.impl.softwrap.mapping.SoftWrapApplianceManager; +import com.intellij.openapi.fileEditor.impl.text.AsyncEditorLoader; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.tree.IElementType; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -49,6 +52,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.concurrent.locks.LockSupport; import static org.junit.Assert.*; @@ -466,6 +470,15 @@ public class EditorTestUtil { }); } + public static void waitForLoading(Editor editor) { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (editor == null) return; + while (!AsyncEditorLoader.isEditorLoaded(editor)) { + LockSupport.parkNanos(100_000_000); + UIUtil.dispatchAllInvocationEvents(); + } + } + public static class CaretAndSelectionState { public final List carets; public final TextRange blockSelection; diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 5f687e698ddb..f26bc1786ef8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1377,6 +1377,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig PsiDocumentManager.getInstance(getProject()).commitAllDocuments(); Editor editor = instance.openTextEditor(new OpenFileDescriptor(project, file), false); + EditorTestUtil.waitForLoading(editor); if (editor != null) { DaemonCodeAnalyzer.getInstance(getProject()).restart(); }