From cfb7d9af765c961103ce847fc50befb253231cc3 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Mon, 5 Sep 2016 18:32:24 +0300 Subject: [PATCH 01/12] [vcs-log] cancel all progresses on dispose and throw PCE from disposed log storage It is bad to work with VcsLogStorage after dispose. This can happen if some refreshing/filtering processes are still in progress when log is disposed. So: 1. All processes are cancelled in VcsLogProgress. 2. VcsLogStorage throws PCE if accessed when disposed. --- .../com/intellij/vcs/log/data/VcsLogData.java | 2 +- .../intellij/vcs/log/data/VcsLogProgress.java | 32 ++++++++++++------- .../vcs/log/data/VcsLogRefresherImpl.java | 6 +++- .../vcs/log/data/VcsLogStorageImpl.java | 13 ++++++++ .../vcs/log/data/VcsLogRefresherTest.java | 3 +- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java index 32a5024fe858..3f39e50df904 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogData.java @@ -93,7 +93,7 @@ public class VcsLogData implements Disposable, VcsLogDataProvider { if (!(e instanceof ProcessCanceledException)) { LOG.error(e); } - }, RECENT_COMMITS_COUNT); + }, RECENT_COMMITS_COUNT, this); myContainingBranchesGetter = new ContainingBranchesGetter(this, this); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java index b208e68f6088..fb8f9f0a704b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogProgress.java @@ -26,12 +26,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Set; import java.util.function.Consumer; -public class VcsLogProgress { +public class VcsLogProgress implements Disposable { @NotNull private final Object myLock = new Object(); @NotNull private final List myListeners = ContainerUtil.newArrayList(); - private int myRunningTasksCount = 0; + @NotNull private Set myRunningTasks = ContainerUtil.newHashSet(); @NotNull public ProgressIndicator createProgressIndicator() { @@ -59,21 +60,21 @@ public class VcsLogProgress { public boolean isRunning() { synchronized (myLock) { - return myRunningTasksCount > 0; + return !myRunningTasks.isEmpty(); } } - private void started() { + private void started(@NotNull ProgressIndicator indicator) { synchronized (myLock) { - myRunningTasksCount++; - if (myRunningTasksCount == 1) fireNotification(ProgressListener::progressStarted); + myRunningTasks.add(indicator); + if (myRunningTasks.size() == 1) fireNotification(ProgressListener::progressStarted); } } - private void stopped() { + private void stopped(@NotNull ProgressIndicator indicator) { synchronized (myLock) { - myRunningTasksCount--; - if (myRunningTasksCount == 0) fireNotification(ProgressListener::progressStopped); + myRunningTasks.remove(indicator); + if (myRunningTasks.isEmpty()) fireNotification(ProgressListener::progressStopped); } } @@ -84,17 +85,26 @@ public class VcsLogProgress { } } + @Override + public void dispose() { + synchronized (myLock) { + for (ProgressIndicator indicator : myRunningTasks) { + indicator.cancel(); + } + } + } + private class VcsLogProgressIndicator extends AbstractProgressIndicatorBase { @Override public synchronized void start() { super.start(); - started(); + started(this); } @Override public synchronized void stop() { super.stop(); - stopped(); + stopped(this); } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java index 01666e67682e..8dbbf2562d4c 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java @@ -15,11 +15,13 @@ */ package com.intellij.vcs.log.data; +import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; @@ -65,7 +67,8 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { @NotNull TopCommitsCache topCommitsDetailsCache, @NotNull Consumer dataPackUpdateHandler, @NotNull Consumer exceptionHandler, - int recentCommitsCount) { + int recentCommitsCount, + @NotNull Disposable parentDisposable) { myProject = project; myHashMap = hashMap; myProviders = providers; @@ -74,6 +77,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher { myExceptionHandler = exceptionHandler; myRecentCommitCount = recentCommitsCount; myProgress = new VcsLogProgress(); + Disposer.register(parentDisposable, myProgress); mySingleTaskController = new SingleTaskController(dataPack -> { myDataPack = dataPack; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStorageImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStorageImpl.java index 507a646184a3..a1921a9fda7b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStorageImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogStorageImpl.java @@ -17,6 +17,7 @@ package com.intellij.vcs.log.data; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; @@ -60,6 +61,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { @NotNull private final PersistentEnumeratorBase myCommitIdEnumerator; @NotNull private final PersistentEnumeratorBase myRefsEnumerator; @NotNull private final Consumer myExceptionReporter; + private volatile boolean myDisposed = false; public VcsLogStorageImpl(@NotNull Project project, @NotNull Map logProviders, @@ -94,6 +96,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { @Override public int getCommitIndex(@NotNull Hash hash, @NotNull VirtualFile root) { + checkDisposed(); try { return getOrPut(hash, root); } @@ -106,6 +109,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { @Override @Nullable public CommitId getCommitId(int commitIndex) { + checkDisposed(); try { CommitId commitId = doGetCommitId(commitIndex); if (commitId == null) { @@ -122,6 +126,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { @Override @Nullable public CommitId findCommitId(@NotNull final Condition condition) { + checkDisposed(); try { final Ref hashRef = Ref.create(); myCommitIdEnumerator.iterateData(new CommonProcessors.FindProcessor() { @@ -144,6 +149,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { @Override public int getRefIndex(@NotNull VcsRef ref) { + checkDisposed(); try { return myRefsEnumerator.enumerate(ref); } @@ -156,6 +162,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { @Nullable @Override public VcsRef getVcsRef(int refIndex) { + checkDisposed(); try { return myRefsEnumerator.valueOf(refIndex); } @@ -166,6 +173,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { } public void flush() { + checkDisposed(); myCommitIdEnumerator.force(); myRefsEnumerator.force(); } @@ -173,6 +181,7 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { @Override public void dispose() { try { + myDisposed = true; myCommitIdEnumerator.close(); myRefsEnumerator.close(); } @@ -181,6 +190,10 @@ public class VcsLogStorageImpl implements Disposable, VcsLogStorage { } } + private void checkDisposed() { + if (myDisposed) throw new ProcessCanceledException(); + } + private static class MyCommitIdKeyDescriptor implements KeyDescriptor { @NotNull private final List myRoots; @NotNull private final TObjectIntHashMap myRootsReversed; diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java index 65da9a2516e3..780e1f55b759 100644 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java @@ -202,7 +202,8 @@ public class VcsLogRefresherTest extends VcsPlatformTest { myLogData = new VcsLogData(myProject, myLogProviders, LOG::error); Disposer.register(myProject, myLogData); return new VcsLogRefresherImpl(myProject, myLogData.getHashMap(), myLogProviders, myLogData.getUserRegistry(), - myLogData.getTopCommitsCache(), dataPackConsumer, FAILING_EXCEPTION_HANDLER, RECENT_COMMITS_COUNT) { + myLogData.getTopCommitsCache(), dataPackConsumer, FAILING_EXCEPTION_HANDLER, RECENT_COMMITS_COUNT, + myLogData) { @Override protected void startNewBackgroundTask(@NotNull final Task.Backgroundable refreshTask) { LOG.debug("Starting a background task..."); From 73273f7e5871428e81db897adfb99ba73a4fbbfb Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Mon, 12 Sep 2016 17:24:18 +0300 Subject: [PATCH 02/12] IDEA-35480 Per project/frame modality (Commit and Push dialog) Use ide.perProjectModality registry key to enable --- .../src/com/intellij/dvcs/push/ui/VcsPushDialog.java | 4 +++- .../src/com/intellij/openapi/wm/impl/CommandProcessor.java | 2 +- .../openapi/vcs/changes/ui/CommitChangeListDialog.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java index 6c2d26242346..2249f0fe23d1 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java @@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.OptionAction; import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.openapi.util.registry.Registry; import com.intellij.ui.components.labels.ActionLink; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.components.BorderLayoutPanel; @@ -52,7 +53,8 @@ public class VcsPushDialog extends DialogWrapper { public VcsPushDialog(@NotNull Project project, @NotNull List selectedRepositories, @Nullable Repository currentRepo) { - super(project); + super(project, true, (Registry.is("ide.perProjectModality")) ? IdeModalityType.PROJECT : IdeModalityType.IDE); + myController = new PushController(project, this, selectedRepositories, currentRepo); myAdditionalPanels = myController.createAdditionalPanels(); myListPanel = myController.getPushPanelLog(); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java index 476ff706b325..13276cc1f59a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java @@ -80,7 +80,7 @@ public final class CommandProcessor implements Runnable { // definitely have some since runnables in command list may (and do) request some PSI activity final boolean queueNext = myCommandCount > 0; Application application = ApplicationManager.getApplication(); - ModalityState modalityState = Registry.is("ide.perProjectModality") ? ModalityState.defaultModalityState() : ModalityState.NON_MODAL; + ModalityState modalityState = ModalityState.NON_MODAL; application.getInvokator().invokeLater(command, modalityState, expire == null ? application.getDisposed() : expire).doWhenDone(() -> { if (queueNext) { this.run(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java index a299a0ee2092..19de6eb510c9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java @@ -271,7 +271,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj final boolean isAlien, final String comment, @Nullable CommitResultHandler customResultHandler) { - super(project, true); + super(project, true, (Registry.is("ide.perProjectModality")) ? IdeModalityType.PROJECT : IdeModalityType.IDE); myCommitContext = new CommitContext(); myProject = project; myVcsConfiguration = ObjectUtils.assertNotNull(VcsConfiguration.getInstance(myProject)); From 0257ebc26a23f9cfc983e9740d9262a1381fd67c Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Mon, 12 Sep 2016 17:28:45 +0300 Subject: [PATCH 03/12] Python Console is broken for Remote interpreter with IPython 5 (PY-20732) Don't override this method here, call the original method of `sys.stdin` --- python/helpers/pydev/_pydev_bundle/pydev_console_utils.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py index 9d612005e9f3..4ad420baea9a 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py @@ -70,9 +70,6 @@ class BaseStdIn: # which is not something we want. return '\n' - def isatty(self): - return False # not really a file - def write(self, *args, **kwargs): pass # not available StdIn (but it can be expected to be in the stream interface) From 757087b8c50970593289b7725504e59a55d135e0 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 15:54:24 +0200 Subject: [PATCH 04/12] PsiFileImpl.rebuildStub invokeLater can happen after project disposal (EA-88282 - assert: MessageBusImpl.checkNotDisposed) --- .../src/com/intellij/psi/impl/source/PsiFileImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 8bcc97ab568e..9f0101a5b551 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -1112,7 +1112,9 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - myManager.dropResolveCaches(); + if (!myManager.isDisposed()) { + myManager.dropResolveCaches(); + } final VirtualFile vFile = getVirtualFile(); if (vFile != null && vFile.isValid()) { From 17f204ca6602da434f91b50714ffaee1d5f4331c Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 15:59:49 +0200 Subject: [PATCH 05/12] handle jb protocol commands in write-safe context (EA-88277 - assert: FileDocumentManagerImpl.saveAllDocuments) --- .../src/com/intellij/ide/CommandLineProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java b/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java index 035135934acc..04ec2228340e 100644 --- a/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java +++ b/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java @@ -151,7 +151,7 @@ public class CommandLineProcessor { try { final String url = URLDecoder.decode(command, "UTF-8"); JetBrainsProtocolHandler.processJetBrainsLauncherParameters(url); - ApplicationManager.getApplication().invokeLater(() -> JBProtocolCommand.handleCurrentCommand(), ModalityState.any()); + ApplicationManager.getApplication().invokeLater(() -> JBProtocolCommand.handleCurrentCommand()); } catch (UnsupportedEncodingException e) { LOG.error(e); From 1e71f0ace45e0654ae3c69cfc7d3a5efd6e653f1 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 16:10:21 +0200 Subject: [PATCH 06/12] settings-repository: reload schemes in a write-safe context --- plugins/settings-repository/src/sync.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/plugins/settings-repository/src/sync.kt b/plugins/settings-repository/src/sync.kt index 500591c3fb67..decfaf44585e 100644 --- a/plugins/settings-repository/src/sync.kt +++ b/plugins/settings-repository/src/sync.kt @@ -17,6 +17,7 @@ package org.jetbrains.settingsRepository import com.intellij.configurationStore.* import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.impl.ApplicationImpl import com.intellij.openapi.components.StateStorage import com.intellij.openapi.components.stateStore @@ -24,10 +25,9 @@ import com.intellij.openapi.options.SchemeManagerFactory import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.runModalTask import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Computable +import com.intellij.openapi.util.Ref import com.intellij.util.SmartList import com.intellij.util.messages.MessageBus -import com.intellij.util.ui.UIUtil import gnu.trove.THashSet import org.eclipse.jgit.errors.NoRemoteRepositoryException import java.util.* @@ -168,7 +168,8 @@ internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateR return false } - return UIUtil.invokeAndWaitIfNeeded(Computable { + val result = Ref.create(false) + ApplicationManager.getApplication().invokeAndWait(Runnable { val notReloadableComponents: Collection updateStateStorage(changedComponentNames, changed, false) updateStateStorage(changedComponentNames, deleted, true) @@ -178,7 +179,7 @@ internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateR } if (changedComponentNames.isEmpty()) { - return@Computable false + return@Runnable } notReloadableComponents = store.getNotReloadableComponents(changedComponentNames) @@ -189,8 +190,9 @@ internal fun updateStoragesFromStreamProvider(store: ComponentStoreImpl, updateR store.reinitComponents(changedComponentNames, changedStorageSet, notReloadableComponents) } - !notReloadableComponents.isEmpty() && askToRestart(store, notReloadableComponents, null, true) - }) + result.set(!notReloadableComponents.isEmpty() && askToRestart(store, notReloadableComponents, null, true)) + }, ModalityState.defaultModalityState()) + return result.get() } private fun updateStateStorage(changedComponentNames: MutableSet, stateStorages: Collection, deleted: Boolean) { From e2bac6dacd4ccb95cf1ffdd3c748aa1642fef14b Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 16:18:01 +0200 Subject: [PATCH 07/12] let scope view work with last committed PSI (EA-88240 - assert: PsiDocumentManagerBase.commitDocument) --- .../ide/scopeView/ClassesScopeTreeStructureExpander.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java b/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java index 76038f999439..ef0105d641e5 100644 --- a/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java +++ b/java/java-impl/src/com/intellij/ide/scopeView/ClassesScopeTreeStructureExpander.java @@ -20,14 +20,12 @@ import com.intellij.ide.projectView.PsiClassChildrenSource; import com.intellij.ide.scopeView.nodes.ClassNode; import com.intellij.ide.scopeView.nodes.FieldNode; import com.intellij.ide.scopeView.nodes.MethodNode; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.packageDependencies.ui.DependencyNodeComparator; import com.intellij.packageDependencies.ui.DirectoryNode; import com.intellij.packageDependencies.ui.FileNode; -import com.intellij.packageDependencies.ui.PackageDependenciesNode; import com.intellij.psi.*; import com.intellij.util.ui.tree.TreeUtil; @@ -74,7 +72,7 @@ public class ClassesScopeTreeStructureExpander implements ScopeTreeStructureExpa if (classNodes == null) { classNodes = new HashSet<>(); } - commitDocument((PsiFile)file); + for (final PsiClass psiClass : psiClasses) { if (psiClass != null && psiClass.isValid()) { final ClassNode classNode = new ClassNode(psiClass); @@ -155,9 +153,4 @@ public class ClassesScopeTreeStructureExpander implements ScopeTreeStructureExpa return new DependencyNodeComparator(ProjectView.getInstance(myProject).isSortByType(ScopeViewPane.ID)); } - private void commitDocument(final PsiFile file) { - final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); - final Document document = documentManager.getDocument(file); - documentManager.commitDocument(document); - } } From 5acbb515c20684df78bb1a6b3f16a2c38fe8858c Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 16:21:29 +0200 Subject: [PATCH 08/12] LanguageConsoleImpl: save documents in a transaction on focus gain (EA-88232 - assert: FileDocumentManagerImpl.saveAllDocuments) --- .../com/intellij/execution/console/LanguageConsoleImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index 3ed2ae188039..5a1cefeae19e 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -27,6 +27,7 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.editor.*; @@ -108,7 +109,7 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons public void focusGained(Editor editor) { myCurrentEditor = (EditorEx)editor; if (GeneralSettings.getInstance().isSaveOnFrameDeactivation()) { - FileDocumentManager.getInstance().saveAllDocuments(); // PY-12487 + TransactionGuard.submitTransaction(LanguageConsoleImpl.this, () -> FileDocumentManager.getInstance().saveAllDocuments()); // PY-12487 } } From ed650f151dc3cd6e4efe22ce7842042f0dd5152c Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 16:25:07 +0200 Subject: [PATCH 09/12] goto action: update actions to show, not to perform immediately (EA-88206 - assert: PsiDocumentManagerBase.commitAllDocuments) --- .../src/com/intellij/ide/util/gotoByName/GotoActionModel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index 56659a81074a..077630d4ea69 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -259,7 +259,6 @@ public class GotoActionModel implements ChooseByNameModel, Comparator, E public static AnActionEvent updateActionBeforeShow(@NotNull AnAction anAction, @NotNull DataContext dataContext) { AnActionEvent event = AnActionEvent.createFromDataContext(ActionPlaces.ACTION_SEARCH, null, dataContext); ActionUtil.performDumbAwareUpdate(anAction, event, false); - ActionUtil.performDumbAwareUpdate(anAction, event, true); return event; } From 83e006b1c17a9b92e5291131ae2451b2feaaa0c4 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 17:01:15 +0200 Subject: [PATCH 10/12] IDEA-161070 Memory leaks of LightVirtualFiles --- .../BaseExternalAnnotationsManager.java | 2 +- .../psi/LightVirtualFileLeaksTest.java | 90 +++++++++++++++++++ .../psi/impl/file/impl/FileManagerImpl.java | 8 +- .../file/impl/ResolveScopeManagerImpl.java | 11 ++- 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 java/java-tests/testSrc/com/intellij/psi/LightVirtualFileLeaksTest.java diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java b/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java index 431e046fe308..13ca286944bf 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java @@ -61,7 +61,7 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations protected final PsiManager myPsiManager; - private final ConcurrentMap> myExternalAnnotations = ContainerUtil.createConcurrentSoftValueMap(); + private final ConcurrentMap> myExternalAnnotations = ContainerUtil.createConcurrentWeakKeySoftValueMap(); private final Map myAnnotationDataCache = new WeakKeyWeakValueHashMap(); private final ConcurrentMap, Long>> myAnnotationFileToDataAndModStamp = ContainerUtil.createConcurrentSoftMap(); diff --git a/java/java-tests/testSrc/com/intellij/psi/LightVirtualFileLeaksTest.java b/java/java-tests/testSrc/com/intellij/psi/LightVirtualFileLeaksTest.java new file mode 100644 index 000000000000..4d5111197f6c --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/psi/LightVirtualFileLeaksTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2000-2016 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.psi; + +import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.util.Key; +import com.intellij.testFramework.LeakHunter; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.LightVirtualFile; +import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.intellij.util.GCUtil; +import org.jetbrains.annotations.NotNull; + +/** + * @author peter + */ +public class LightVirtualFileLeaksTest extends LightCodeInsightFixtureTestCase { + private Key myKey; + private static final DefaultLightProjectDescriptor PROJECT_DESCRIPTOR = new DefaultLightProjectDescriptor() { + @Override + public Sdk getSdk() { + return PsiTestUtil.addJdkAnnotations(super.getSdk()); + } + }; + + @Override + protected void setUp() throws Exception { + super.setUp(); + myKey = Key.create(getName()); + } + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return PROJECT_DESCRIPTOR; + } + + public void testDoNotLeakViaDocument() { + createFileWithDocument(); + checkLeak(); + } + + private void createFileWithDocument() { + Document document = FileDocumentManager.getInstance().getDocument(createLightFile()); + assertNotNull(document); + PsiJavaFile psiFile = (PsiJavaFile)PsiDocumentManager.getInstance(getProject()).getPsiFile(document); + assertSame(document, PsiDocumentManager.getInstance(getProject()).getDocument(psiFile)); + } + + private void checkLeak() { + GCUtil.tryGcSoftlyReachableObjects(); + LeakHunter.checkLeak(getProject(), LightVirtualFile.class, vf -> vf.getUserData(myKey) == Boolean.TRUE); + } + + public void testDoNotLeakViaExternalAnnotations() { + queryExternalAnnotations(); + checkLeak(); + } + + private void queryExternalAnnotations() { + LightVirtualFile vFile = createLightFile(); + assertEmpty(AnnotationUtil.getAllAnnotations(((PsiJavaFile)getPsiManager().findFile(vFile)).getClasses()[0], true, null)); + } + + @NotNull + private LightVirtualFile createLightFile() { + LightVirtualFile vFile = new LightVirtualFile(getName() + ".java", JavaFileType.INSTANCE, "class Foo {}"); + vFile.putUserData(myKey, Boolean.TRUE); + return vFile; + } +} diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java index a115ef0aa2f6..5bdc230599db 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java @@ -220,8 +220,12 @@ public class FileManagerImpl implements FileManager { assert !file.isDirectory(); FileViewProvider viewProvider = findCachedViewProvider(file); if (viewProvider != null) return viewProvider; - viewProvider = ConcurrencyUtil.cacheOrGet(myVFileToViewProviderMap, file, createFileViewProvider(file, true)); - return viewProvider; + + viewProvider = createFileViewProvider(file, true); + if (file instanceof LightVirtualFile) { + return file.putUserDataIfAbsent(myPsiHardRefKey, viewProvider); + } + return ConcurrencyUtil.cacheOrGet(myVFileToViewProviderMap, file, viewProvider); } @Override diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java b/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java index a6d381a73da9..63d408517103 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/file/impl/ResolveScopeManagerImpl.java @@ -31,7 +31,8 @@ import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.ResolveScopeManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; -import com.intellij.util.containers.ConcurrentFactoryMap; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.FactoryMap; import com.intellij.util.indexing.AdditionalIndexableFileSet; import org.jetbrains.annotations.NotNull; @@ -43,7 +44,13 @@ public class ResolveScopeManagerImpl extends ResolveScopeManager { private final ProjectRootManager myProjectRootManager; private final PsiManager myManager; - private final Map myDefaultResolveScopesCache = new ConcurrentFactoryMap() { + private final Map myDefaultResolveScopesCache = new FactoryMap() { + + @Override + protected Map createMap() { + return ContainerUtil.createConcurrentWeakKeySoftValueMap(); + } + @Override protected GlobalSearchScope create(@NotNull VirtualFile key) { GlobalSearchScope scope = null; From b141cbe9dd1f23e25becbced80fbf3a698ee82b6 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Mon, 12 Sep 2016 11:57:13 +0300 Subject: [PATCH 11/12] [Reporting] annotate with @JvmField to prevent from obfuscation and proper gson deserialization --- platform/platform-impl/src/com/intellij/reporting/Reporter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/reporting/Reporter.kt b/platform/platform-impl/src/com/intellij/reporting/Reporter.kt index 728f1bed7ca3..10117bd1d4d8 100644 --- a/platform/platform-impl/src/com/intellij/reporting/Reporter.kt +++ b/platform/platform-impl/src/com/intellij/reporting/Reporter.kt @@ -22,7 +22,7 @@ import org.apache.http.client.fluent.Request import org.apache.http.entity.ContentType -private class StatsServerInfo(var status: String, var url: String) { +private class StatsServerInfo(@JvmField var status: String, @JvmField var url: String) { fun isServiceAlive() = "ok" == status } From 9a1107d5b4bde741642e5d6d4d172c90d9b6f108 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 12 Sep 2016 20:12:04 +0300 Subject: [PATCH 12/12] junit: don't include dependent modules in scope for one class/method, corresponding classes won't appear on the classpath (IDEA-160633) --- plugins/junit/src/com/intellij/execution/junit/TestObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 55bcec425a19..0352361fde03 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -130,7 +130,7 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState