From ccb85bd9e9ce6df6fb1f4471195cf4f187a564e9 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 10 Apr 2012 15:28:23 +0400 Subject: [PATCH 1/2] more thread safety --- .../openapi/vcs/changes/FilePathUnderVcs.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java index b5e0e447a739..f3bed0b0a416 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/FilePathUnderVcs.java @@ -20,11 +20,12 @@ import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.VcsRoot; +import org.jetbrains.annotations.NonNls; public class FilePathUnderVcs { private final FilePath myPath; private final AbstractVcs myVcs; - private int hashcode; + private int hashCode; public FilePathUnderVcs(final FilePath path, final AbstractVcs vcs) { myPath = path; @@ -59,13 +60,15 @@ public class FilePathUnderVcs { @Override public int hashCode() { - if (hashcode == 0) { - hashcode = myPath != null ? myPath.hashCode() : 0; - hashcode = 31 * hashcode + (myVcs != null ? myVcs.getName().hashCode() : 0); + if (hashCode == 0) { + int hc = myPath != null ? myPath.hashCode() : 0; + hc = 31 * hc + (myVcs != null ? myVcs.getName().hashCode() : 0); + hashCode = hc; } - return hashcode; + return hashCode; } + @NonNls @Override public String toString() { return "FilePathUnderVcs{" + From 3fd4a9900853e895eb89ceb22bc800334da6dd6e Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 11 Apr 2012 11:20:57 +0400 Subject: [PATCH 2/2] in case of floating editor, when intention popup opens, activeEditorsChanged(empty) called, causing intention popup to close --- .../daemon/impl/DaemonCodeAnalyzerImpl.java | 47 +++++++++++-------- .../daemon/impl/DaemonListeners.java | 24 ++++++---- .../editor/event/EditorFactoryAdapter.java | 2 + 3 files changed, 44 insertions(+), 29 deletions(-) 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 252b26675a03..b9e0f7d040af 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 @@ -114,7 +114,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private volatile boolean allowToInterrupt = true; private StatusBarUpdater myStatusBarUpdater; - public DaemonCodeAnalyzerImpl(Project project, DaemonCodeAnalyzerSettings daemonCodeAnalyzerSettings, EditorTracker editorTracker) { + public DaemonCodeAnalyzerImpl(@NotNull Project project, DaemonCodeAnalyzerSettings daemonCodeAnalyzerSettings, EditorTracker editorTracker) { myProject = project; mySettings = daemonCodeAnalyzerSettings; @@ -125,7 +125,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myPassExecutorService = new PassExecutorService(myProject) { @Override protected void afterApplyInformationToEditor(final TextEditorHighlightingPass pass, - final FileEditor fileEditor, + @NotNull final FileEditor fileEditor, final ProgressIndicator updateProgress) { if (fileEditor instanceof TextEditor) { log(updateProgress, pass, "Apply "); @@ -143,19 +143,20 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx Disposer.register(project, myFileStatusMap); } - static boolean hasErrors(Project project, Document document) { + static boolean hasErrors(@NotNull Project project, @NotNull Document document) { return !processHighlights(document, project, HighlightSeverity.ERROR, 0, document.getTextLength(), CommonProcessors.alwaysFalse()); } @NotNull @TestOnly - public static List getHighlights(Document document, HighlightSeverity minSeverity, Project project) { + public static List getHighlights(@NotNull Document document, HighlightSeverity minSeverity, @NotNull Project project) { List infos = new ArrayList(); processHighlights(document, project, minSeverity, 0, document.getTextLength(), new CommonProcessors.CollectProcessor(infos)); return infos; } + @NotNull public List runMainPasses(@NotNull PsiFile psiFile, @NotNull Document document, @NotNull final ProgressIndicator progress) { @@ -184,6 +185,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return result; } + @NotNull @TestOnly public List runPasses(@NotNull PsiFile file, @NotNull Document document, @@ -326,7 +328,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myLastSettings = null; } - void repaintErrorStripeRenderer(Editor editor) { + void repaintErrorStripeRenderer(@NotNull Editor editor) { if (!myProject.isInitialized()) return; final Document document = editor.getDocument(); final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document); @@ -349,7 +351,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx dependencyValidationManager.reloadRules(); } - private static void addScopesToList(final List> scopeList, final NamedScopesHolder holder) { + private static void addScopesToList(@NotNull final List> scopeList, @NotNull final NamedScopesHolder holder) { NamedScope[] scopes = holder.getScopes(); for (NamedScope scope : scopes) { scopeList.add(Pair.create(scope, holder)); @@ -416,7 +418,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Override - public boolean isHighlightingAvailable(PsiFile file) { + public boolean isHighlightingAvailable(@Nullable PsiFile file) { if (file == null || !file.isPhysical()) return false; if (myDisabledHighlightingFiles.contains(PsiUtilCore.getVirtualFile(file))) return false; @@ -453,6 +455,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx stopProcess(true); } + @NotNull public List getPassesToShowProgressFor(Document document) { List allPasses = myPassExecutorService.getAllSubmittedPasses(); List result = new ArrayList(allPasses.size()); @@ -472,7 +475,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap.allDirtyScopesAreNull(document); } - public boolean isErrorAnalyzingFinished(PsiFile file) { + public boolean isErrorAnalyzingFinished(@NotNull PsiFile file) { if (myDisposed) return false; Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(file); return document != null && @@ -480,6 +483,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL) == null; } + @NotNull public FileStatusMap getFileStatusMap() { return myFileStatusMap; } @@ -526,7 +530,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOverlappingWith(startOffset, endOffset, new Processor() { @Override - public boolean process(RangeHighlighterEx marker) { + public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; @@ -549,7 +553,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOutside(startOffset, endOffset, new Processor() { @Override - public boolean process(RangeHighlighterEx marker) { + public boolean process(@NotNull RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; HighlightInfo info = (HighlightInfo)tt; @@ -569,7 +573,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx @NotNull final Processor processor) { return processHighlights(document, project, null, 0, document.getTextLength(), new Processor() { @Override - public boolean process(HighlightInfo info) { + public boolean process(@NotNull HighlightInfo info) { if (!isOffsetInsideHighlightInfo(offset, info, includeFixRange)) return true; int compare = info.getSeverity().compareTo(minSeverity); @@ -579,11 +583,11 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Nullable - public HighlightInfo findHighlightByOffset(Document document, final int offset, final boolean includeFixRange) { + public HighlightInfo findHighlightByOffset(@NotNull Document document, final int offset, final boolean includeFixRange) { final List foundInfoList = new SmartList(); processHighlightsNearOffset(document, myProject, HighlightSeverity.INFORMATION, offset, includeFixRange, new Processor() { @Override - public boolean process(HighlightInfo info) { + public boolean process(@NotNull HighlightInfo info) { if (!foundInfoList.isEmpty()) { HighlightInfo foundInfo = foundInfoList.get(0); int compare = foundInfo.getSeverity().compareTo(info.getSeverity()); @@ -604,7 +608,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return new HighlightInfoComposite(foundInfoList); } - private static boolean isOffsetInsideHighlightInfo(int offset, HighlightInfo info, boolean includeFixRange) { + private static boolean isOffsetInsideHighlightInfo(int offset, @NotNull HighlightInfo info, boolean includeFixRange) { RangeHighlighterEx highlighter = info.highlighter; if (highlighter == null || !highlighter.isValid()) return false; int startOffset = highlighter.getStartOffset(); @@ -624,7 +628,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Nullable - public static List getLineMarkers(Document document, Project project) { + public static List getLineMarkers(@NotNull Document document, Project project) { ApplicationManager.getApplication().assertIsDispatchThread(); MarkupModel markup = DocumentMarkupModel.forDocument(document, project, true); return markup.getUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY); @@ -636,7 +640,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx markup.putUserData(MARKERS_IN_EDITOR_DOCUMENT_KEY, lineMarkers); } - public synchronized void setLastIntentionHint(Project project, PsiFile file, Editor editor, ShowIntentionsPass.IntentionsInfo intentions, boolean hasToRecreate) { + public synchronized void setLastIntentionHint(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor, @NotNull ShowIntentionsPass.IntentionsInfo intentions, boolean hasToRecreate) { ApplicationManager.getApplication().assertIsDispatchThread(); hideLastIntentionHint(); IntentionHintComponent hintComponent = IntentionHintComponent.showIntentionHint(project, file, editor, intentions, false); @@ -653,12 +657,13 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Nullable public synchronized IntentionHintComponent getLastIntentionHint() { return myLastIntentionHint; } @Override - public void writeExternal(Element parentNode) throws WriteExternalException { + public void writeExternal(@NotNull Element parentNode) throws WriteExternalException { Element disableHintsElement = new Element(DISABLE_HINTS_TAG); parentNode.addContent(disableHintsElement); @@ -678,7 +683,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } @Override - public void readExternal(Element parentNode) throws InvalidDataException { + public void readExternal(@NotNull Element parentNode) throws InvalidDataException { myDisabledHintsFiles.clear(); Element element = parentNode.getChild(DISABLE_HINTS_TAG); @@ -697,6 +702,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @NotNull private Runnable createUpdateRunnable() { return new Runnable() { @Override @@ -754,6 +760,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx }; } + @NotNull private synchronized DaemonProgressIndicator createUpdateProgress() { DaemonProgressIndicator progress = new DaemonProgressIndicator() { @Override @@ -767,7 +774,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return progress; } - public boolean canChangeFileSilently(PsiFileSystemItem file) { + public boolean canChangeFileSilently(@NotNull PsiFileSystemItem file) { return myDaemonListeners.canChangeFileSilently(file); } @@ -780,7 +787,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx @NotNull @TestOnly - public static List getFileLevelHighlights(Project project,PsiFile file ) { + public static List getFileLevelHighlights(@NotNull Project project, @NotNull PsiFile file ) { return UpdateHighlightersUtil.getFileLeveleHighlights(project, file); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java index 60d25f3665ed..61bced8f2d27 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonListeners.java @@ -148,20 +148,20 @@ class DaemonListeners implements Disposable { @Override public void activeEditorsChanged(@NotNull List editors) { List activeEditors = getActiveEditors(); - if (!myActiveEditors.equals(activeEditors)) { - myActiveEditors = activeEditors; - stopDaemon(true); // do not stop daemon if idea loses/gains focus - if (LaterInvocator.isInModalContext()) { - // editor appear in modal context, reenable the daemon - myDaemonCodeAnalyzer.setUpdateByTimerEnabled(true); - } - myDaemonCodeAnalyzer.hideLastIntentionHint(); // mem leak after closing last editor otherwise + if (myActiveEditors.equals(activeEditors)) { + return; + } + myActiveEditors = activeEditors; + stopDaemon(true); // do not stop daemon if idea loses/gains focus + if (LaterInvocator.isInModalContext()) { + // editor appear in modal context, re-enable the daemon + myDaemonCodeAnalyzer.setUpdateByTimerEnabled(true); } } }; myEditorTracker.addEditorTrackerListener(editorTrackerListener, this); - EditorFactoryListener editorFactoryListener = new EditorFactoryAdapter() { + EditorFactoryListener editorFactoryListener = new EditorFactoryListener() { @Override public void editorCreated(@NotNull EditorFactoryEvent event) { Editor editor = event.getEditor(); @@ -175,6 +175,12 @@ class DaemonListeners implements Disposable { } myDaemonCodeAnalyzer.repaintErrorStripeRenderer(editor); } + + @Override + public void editorReleased(@NotNull EditorFactoryEvent event) { + // mem leak after closing last editor otherwise + myDaemonCodeAnalyzer.hideLastIntentionHint(); + } }; EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, this); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java b/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java index 79c53b939203..3f3fb311ee8e 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/event/EditorFactoryAdapter.java @@ -21,9 +21,11 @@ import org.jetbrains.annotations.NotNull; * @author max */ public abstract class EditorFactoryAdapter implements EditorFactoryListener { + @Override public void editorCreated(@NotNull EditorFactoryEvent event) { } + @Override public void editorReleased(@NotNull EditorFactoryEvent event) { } }