From 62be09df872cb32bc9e80ea7e04b3f2ee0fe2228 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 26 Sep 2013 22:16:04 +0400 Subject: [PATCH] KT-4017 Syntax highlighting drops constantly for ~0.5s with every little change in the source #KT-4017 Fixed --- idea/src/META-INF/plugin.xml | 2 + .../AfterAnalysisHighlightingVisitor.java | 6 -- .../jet/plugin/highlighter/JetPsiChecker.java | 96 +++++++++++++------ 3 files changed, 67 insertions(+), 37 deletions(-) diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 47b11c1ee18..2580c46deab 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -214,6 +214,8 @@ + + diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/AfterAnalysisHighlightingVisitor.java b/idea/src/org/jetbrains/jet/plugin/highlighter/AfterAnalysisHighlightingVisitor.java index d2b5ee5b9b1..b8cc793f1da 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/AfterAnalysisHighlightingVisitor.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/AfterAnalysisHighlightingVisitor.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.plugin.highlighter; import com.intellij.lang.annotation.AnnotationHolder; -import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.resolve.BindingContext; abstract class AfterAnalysisHighlightingVisitor extends HighlightingVisitor { @@ -27,9 +26,4 @@ abstract class AfterAnalysisHighlightingVisitor extends HighlightingVisitor { super(holder); this.bindingContext = bindingContext; } - - @Override - public void visitJetElement(JetElement element) { - element.acceptChildren(this); - } } diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java index d655e1673df..b43dcea92b4 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.plugin.highlighter; import com.google.common.collect.Sets; +import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension; import com.intellij.codeInsight.intention.EmptyIntentionAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.ProblemHighlightType; @@ -26,15 +27,14 @@ import com.intellij.lang.annotation.Annotator; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.TextAttributesKey; -import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.TextRange; -import com.intellij.psi.MultiRangeReference; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReference; +import com.intellij.psi.*; +import com.intellij.util.containers.MultiMap; import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.Severity; @@ -51,11 +51,12 @@ import java.util.Collection; import java.util.List; import java.util.Set; -public class JetPsiChecker implements Annotator { +public class JetPsiChecker implements Annotator, HighlightRangeExtension { private static boolean namesHighlightingTest; - private static final Logger LOG = Logger.getInstance(JetPsiChecker.class); + private HighlightingPassCache passCache = null; + @TestOnly public static void setNamesHighlightingTest(boolean namesHighlightingTest) { JetPsiChecker.namesHighlightingTest = namesHighlightingTest; @@ -92,8 +93,7 @@ public class JetPsiChecker implements Annotator { @Override public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { - if (!JetPluginUtil.isInSource(element) || - JetPluginUtil.isKtFileInGradleProjectInWrongFolder(element)) { + if (!JetPluginUtil.isInSource(element) || JetPluginUtil.isKtFileInGradleProjectInWrongFolder(element)) { return; } @@ -101,35 +101,31 @@ public class JetPsiChecker implements Annotator { element.accept(visitor); } - if (element instanceof JetFile) { - JetFile file = (JetFile) element; + JetFile file = (JetFile) element.getContainingFile(); - try { - BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(file).getBindingContext(); + if (passCache == null || passCache.isOutdated(file)) { + passCache = new HighlightingPassCache(AnalyzerFacadeWithCache.analyzeFileWithCache(file), file); + } - if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false)) { - Collection diagnostics = Sets.newLinkedHashSet(bindingContext.getDiagnostics()); - Set redeclarations = Sets.newHashSet(); - for (Diagnostic diagnostic : diagnostics) { - // This is needed because we have the same context for all files - if (diagnostic.getPsiFile() != file) continue; + if (!passCache.analyzeExhaust.isError()) { + BindingContext bindingContext = passCache.analyzeExhaust.getBindingContext(); + for (HighlightingVisitor visitor : getAfterAnalysisVisitor(holder, bindingContext)) { + element.accept(visitor); + } - registerDiagnosticAnnotations(diagnostic, redeclarations, holder); - } - } - - for (HighlightingVisitor visitor : getAfterAnalysisVisitor(holder, bindingContext)) { - file.acceptChildren(visitor); + if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false)) { + for (Diagnostic diagnostic : passCache.elementToDiagnostic.get(element)) { + registerDiagnosticAnnotations(diagnostic, passCache.redeclarations, holder); } } - catch (ProcessCanceledException e) { - throw e; - } - catch (Throwable e) { - // For failing tests and to notify about idea internal error in -ea mode - holder.createErrorAnnotation(element, e.getClass().getCanonicalName() + ": " + e.getMessage()); - LOG.error(e); + } + 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); } } @@ -277,4 +273,42 @@ public class JetPsiChecker implements Annotator { annotation.setTooltip(getMessage(redeclarationDiagnostic)); return annotation; } + + @Override + public boolean isForceHighlightParents(@NotNull PsiFile file) { + return file instanceof JetFile; + } + + private static class HighlightingPassCache { + private final AnalyzeExhaust analyzeExhaust; + private final MultiMap elementToDiagnostic; + + private final Set 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 buildElementToDiagnosticCache(AnalyzeExhaust analyzeExhaust, JetFile jetFile) { + MultiMap elementToDiagnostic = MultiMap.create(); + Collection diagnostics = Sets.newLinkedHashSet(analyzeExhaust.getBindingContext().getDiagnostics()); + + for (Diagnostic diagnostic : diagnostics) { + if (diagnostic.getPsiFile() == jetFile) { + elementToDiagnostic.putValue(diagnostic.getPsiElement(), diagnostic); + } + } + + return elementToDiagnostic; + } + } }