Fix memory leak by removing storing analyze result from annotators
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
<root>
|
||||||
|
<item name='com.intellij.openapi.util.Key com.intellij.openapi.util.Key<T> create(java.lang.String)'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<root>
|
||||||
|
<item name='com.intellij.ui.EditorNotificationPanel myLabel'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
name='com.intellij.ui.EditorNotifications.Provider T createNotificationPanel(com.intellij.openapi.vfs.VirtualFile, com.intellij.openapi.fileEditor.FileEditor) 0'>
|
||||||
|
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||||
|
</item>
|
||||||
|
</root>
|
||||||
@@ -315,6 +315,7 @@
|
|||||||
|
|
||||||
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.quickfix.IncorrectSourceRootNameNotification"/>
|
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.quickfix.IncorrectSourceRootNameNotification"/>
|
||||||
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.versions.UnsupportedAbiVersionNotificationPanelProvider"/>
|
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.versions.UnsupportedAbiVersionNotificationPanelProvider"/>
|
||||||
|
<editorNotificationProvider implementation="org.jetbrains.jet.plugin.highlighter.ErrorDuringFileAnalyzeNotificationProvider"/>
|
||||||
|
|
||||||
<psi.treeChangePreprocessor implementation="org.jetbrains.jet.asJava.JetCodeBlockModificationListener"/>
|
<psi.treeChangePreprocessor implementation="org.jetbrains.jet.asJava.JetCodeBlockModificationListener"/>
|
||||||
|
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 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 org.jetbrains.jet.plugin.highlighter
|
||||||
|
|
||||||
|
import com.intellij.ui.EditorNotifications
|
||||||
|
import com.intellij.ui.EditorNotificationPanel
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditor
|
||||||
|
import org.jetbrains.jet.plugin.JetFileType
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.jet.lang.psi.JetFile
|
||||||
|
import com.intellij.icons.AllIcons
|
||||||
|
import com.intellij.ide.actions.ActivateToolWindowAction
|
||||||
|
import com.intellij.notification.EventLog
|
||||||
|
|
||||||
|
private val ERROR_HIGHLIGHT_PANEL_KEY = Key.create<EditorNotificationPanel>("kotlin.error.highlight.panel.key")
|
||||||
|
private val HAS_ERRORS_IN_HIGHLIHTING_KEY = Key.create<Boolean>("kotlin.has.errors.in.higlighting.key")
|
||||||
|
|
||||||
|
fun updateHighlightingResult(file: JetFile, hasErrors: Boolean) {
|
||||||
|
if (hasErrors != file.getUserData(HAS_ERRORS_IN_HIGHLIHTING_KEY)) {
|
||||||
|
file.putUserData(HAS_ERRORS_IN_HIGHLIHTING_KEY, hasErrors)
|
||||||
|
|
||||||
|
val vFile = file.getVirtualFile()
|
||||||
|
if (vFile != null) {
|
||||||
|
EditorNotifications.getInstance(file.getProject())?.updateNotifications(vFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ErrorDuringFileAnalyzeNotificationProvider(val project: Project) : EditorNotifications.Provider<EditorNotificationPanel>() {
|
||||||
|
private class HighlightingErrorNotificationPanel : EditorNotificationPanel() {
|
||||||
|
{
|
||||||
|
setText("Kotlin internal error occurred in this file. Highlighting may be inadequate.")
|
||||||
|
myLabel.setIcon(AllIcons.General.Error)
|
||||||
|
createActionLabel("Open Event Log", ActivateToolWindowAction.getActionIdForToolWindow(EventLog.LOG_TOOL_WINDOW_ID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getKey() = ERROR_HIGHLIGHT_PANEL_KEY
|
||||||
|
|
||||||
|
override fun createNotificationPanel(file: VirtualFile, fileEditor: FileEditor?): EditorNotificationPanel? {
|
||||||
|
if (file.getFileType() != JetFileType.INSTANCE) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val psiFile = PsiManager.getInstance(project).findFile(file) ?: return null
|
||||||
|
|
||||||
|
if (psiFile !is JetFile) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasErrors = psiFile.getUserData(HAS_ERRORS_IN_HIGHLIHTING_KEY) ?: false
|
||||||
|
|
||||||
|
return if (hasErrors) HighlightingErrorNotificationPanel() else null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.highlighter;
|
package org.jetbrains.jet.plugin.highlighter;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension;
|
import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension;
|
||||||
import com.intellij.codeInsight.intention.EmptyIntentionAction;
|
import com.intellij.codeInsight.intention.EmptyIntentionAction;
|
||||||
import com.intellij.codeInsight.intention.IntentionAction;
|
import com.intellij.codeInsight.intention.IntentionAction;
|
||||||
@@ -25,11 +24,14 @@ import com.intellij.lang.annotation.Annotation;
|
|||||||
import com.intellij.lang.annotation.AnnotationHolder;
|
import com.intellij.lang.annotation.AnnotationHolder;
|
||||||
import com.intellij.lang.annotation.Annotator;
|
import com.intellij.lang.annotation.Annotator;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.diagnostic.Logger;
|
|
||||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||||
|
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||||
|
import com.intellij.openapi.util.Ref;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.MultiRangeReference;
|
||||||
import com.intellij.util.containers.MultiMap;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
import com.intellij.xml.util.XmlStringUtil;
|
import com.intellij.xml.util.XmlStringUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -49,15 +51,10 @@ import org.jetbrains.jet.plugin.quickfix.QuickFixes;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
||||||
private static final Logger LOG = Logger.getInstance(JetPsiChecker.class);
|
|
||||||
|
|
||||||
private static boolean isNamesHighlightingEnabled = true;
|
private static boolean isNamesHighlightingEnabled = true;
|
||||||
|
|
||||||
private HighlightingPassCache passCache = null;
|
|
||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
public static void setNamesHighlightingEnabled(boolean namesHighlightingEnabled) {
|
public static void setNamesHighlightingEnabled(boolean namesHighlightingEnabled) {
|
||||||
isNamesHighlightingEnabled = namesHighlightingEnabled;
|
isNamesHighlightingEnabled = namesHighlightingEnabled;
|
||||||
@@ -104,36 +101,41 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
|||||||
|
|
||||||
JetFile file = (JetFile) element.getContainingFile();
|
JetFile file = (JetFile) element.getContainingFile();
|
||||||
|
|
||||||
if (passCache == null || passCache.isOutdated(file)) {
|
AnalyzeExhaust analyzeExhaust = AnalyzerFacadeWithCache.analyzeFileWithCache(file);
|
||||||
passCache = new HighlightingPassCache(AnalyzerFacadeWithCache.analyzeFileWithCache(file), file);
|
if (analyzeExhaust.isError()) {
|
||||||
|
//noinspection StaticMethodReferencedViaSubclass
|
||||||
|
HighlighterPackage.updateHighlightingResult(file, true);
|
||||||
|
|
||||||
|
// Force stop highlighting annotate cycle
|
||||||
|
throw new ProcessCanceledException(analyzeExhaust.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!passCache.analyzeExhaust.isError()) {
|
BindingContext bindingContext = analyzeExhaust.getBindingContext();
|
||||||
BindingContext bindingContext = passCache.analyzeExhaust.getBindingContext();
|
for (HighlightingVisitor visitor : getAfterAnalysisVisitor(holder, bindingContext)) {
|
||||||
for (HighlightingVisitor visitor : getAfterAnalysisVisitor(holder, bindingContext)) {
|
element.accept(visitor);
|
||||||
element.accept(visitor);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false)) {
|
if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false)) {
|
||||||
for (Diagnostic diagnostic : passCache.elementToDiagnostic.get(element)) {
|
Ref<Boolean> isMarkedWithRedeclaration = Ref.create(false);
|
||||||
registerDiagnosticAnnotations(diagnostic, passCache.redeclarations, holder);
|
for (Diagnostic diagnostic : bindingContext.getDiagnostics().forElement(element)) {
|
||||||
}
|
registerDiagnosticAnnotations(element, diagnostic, holder, isMarkedWithRedeclaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (element instanceof JetFile) {
|
|
||||||
Throwable error = passCache.analyzeExhaust.getError();
|
|
||||||
if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false)) {
|
|
||||||
holder.createErrorAnnotation(file, error.getClass().getCanonicalName() + ": " + error.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG.error(error);
|
if (element instanceof JetFile) {
|
||||||
|
//noinspection StaticMethodReferencedViaSubclass
|
||||||
|
HighlighterPackage.updateHighlightingResult(file, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerDiagnosticAnnotations(@NotNull Diagnostic diagnostic,
|
private static void registerDiagnosticAnnotations(
|
||||||
@NotNull Set<PsiElement> redeclarations,
|
@NotNull PsiElement element, @NotNull Diagnostic diagnostic,
|
||||||
@NotNull AnnotationHolder holder) {
|
@NotNull AnnotationHolder holder, Ref<Boolean> isMarkedWithRedeclaration
|
||||||
|
) {
|
||||||
if (!diagnostic.isValid()) return;
|
if (!diagnostic.isValid()) return;
|
||||||
|
|
||||||
|
assert diagnostic.getPsiElement() == element;
|
||||||
|
|
||||||
List<TextRange> textRanges = diagnostic.getTextRanges();
|
List<TextRange> textRanges = diagnostic.getTextRanges();
|
||||||
if (diagnostic.getSeverity() == Severity.ERROR) {
|
if (diagnostic.getSeverity() == Severity.ERROR) {
|
||||||
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
|
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
|
||||||
@@ -144,9 +146,7 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
|||||||
for (TextRange range : mrr.getRanges()) {
|
for (TextRange range : mrr.getRanges()) {
|
||||||
Annotation annotation = holder.createErrorAnnotation(range.shiftRight(referenceExpression.getTextOffset()), getDefaultMessage(diagnostic));
|
Annotation annotation = holder.createErrorAnnotation(range.shiftRight(referenceExpression.getTextOffset()), getDefaultMessage(diagnostic));
|
||||||
annotation.setTooltip(getMessage(diagnostic));
|
annotation.setTooltip(getMessage(diagnostic));
|
||||||
|
|
||||||
registerQuickFix(annotation, diagnostic);
|
registerQuickFix(annotation, diagnostic);
|
||||||
|
|
||||||
annotation.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
annotation.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,8 +171,10 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Errors.REDECLARATION_DIAGNOSTICS.contains(diagnostic.getFactory())) {
|
if (!isMarkedWithRedeclaration.get() && Errors.REDECLARATION_DIAGNOSTICS.contains(diagnostic.getFactory())) {
|
||||||
registerQuickFix(markRedeclaration(redeclarations, diagnostic, holder), diagnostic);
|
isMarkedWithRedeclaration.set(true);
|
||||||
|
Annotation annotation = holder.createErrorAnnotation(diagnostic.getTextRanges().get(0), "");
|
||||||
|
annotation.setTooltip(getMessage(diagnostic));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,53 +265,8 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Annotation markRedeclaration(@NotNull Set<PsiElement> redeclarations,
|
|
||||||
@NotNull Diagnostic redeclarationDiagnostic,
|
|
||||||
@NotNull AnnotationHolder holder) {
|
|
||||||
if (!redeclarations.add(redeclarationDiagnostic.getPsiElement())) return null;
|
|
||||||
List<TextRange> textRanges = redeclarationDiagnostic.getTextRanges();
|
|
||||||
if (!redeclarationDiagnostic.isValid()) return null;
|
|
||||||
Annotation annotation = holder.createErrorAnnotation(textRanges.get(0), "");
|
|
||||||
annotation.setTooltip(getMessage(redeclarationDiagnostic));
|
|
||||||
return annotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isForceHighlightParents(@NotNull PsiFile file) {
|
public boolean isForceHighlightParents(@NotNull PsiFile file) {
|
||||||
return file instanceof JetFile;
|
return file instanceof JetFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class HighlightingPassCache {
|
|
||||||
private final AnalyzeExhaust analyzeExhaust;
|
|
||||||
private final MultiMap<PsiElement, Diagnostic> elementToDiagnostic;
|
|
||||||
|
|
||||||
private final Set<PsiElement> redeclarations = Sets.newHashSet();
|
|
||||||
private final JetFile jetFile;
|
|
||||||
private final long modificationCount;
|
|
||||||
|
|
||||||
public HighlightingPassCache(AnalyzeExhaust analyzeExhaust, JetFile jetFile) {
|
|
||||||
this.analyzeExhaust = analyzeExhaust;
|
|
||||||
this.jetFile = jetFile;
|
|
||||||
this.elementToDiagnostic = buildElementToDiagnosticCache(analyzeExhaust, jetFile);
|
|
||||||
this.modificationCount = PsiManager.getInstance(jetFile.getProject()).getModificationTracker().getModificationCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOutdated(JetFile jetFile) {
|
|
||||||
return this.jetFile != jetFile || PsiManager.getInstance(jetFile.getProject()).getModificationTracker().getModificationCount() != modificationCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MultiMap<PsiElement, Diagnostic> buildElementToDiagnosticCache(AnalyzeExhaust analyzeExhaust, JetFile jetFile) {
|
|
||||||
MultiMap<PsiElement, Diagnostic> elementToDiagnostic = MultiMap.create();
|
|
||||||
Collection<Diagnostic> diagnostics = Sets.newLinkedHashSet(analyzeExhaust.getBindingContext().getDiagnostics());
|
|
||||||
|
|
||||||
for (Diagnostic diagnostic : diagnostics) {
|
|
||||||
if (diagnostic.getPsiFile() == jetFile) {
|
|
||||||
elementToDiagnostic.putValue(diagnostic.getPsiElement(), diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return elementToDiagnostic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user