diff --git a/annotations/com/intellij/openapi/util/annotations.xml b/annotations/com/intellij/openapi/util/annotations.xml
new file mode 100644
index 00000000000..b11815b34e4
--- /dev/null
+++ b/annotations/com/intellij/openapi/util/annotations.xml
@@ -0,0 +1,5 @@
+
+ -
+
+
+
\ No newline at end of file
diff --git a/annotations/com/intellij/ui/annotations.xml b/annotations/com/intellij/ui/annotations.xml
new file mode 100644
index 00000000000..b911bc06f23
--- /dev/null
+++ b/annotations/com/intellij/ui/annotations.xml
@@ -0,0 +1,9 @@
+
+ -
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index b0a0704f61c..26460c45679 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -315,6 +315,7 @@
+
diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/ErrorDuringFileAnalyzeNotificationProvider.kt b/idea/src/org/jetbrains/jet/plugin/highlighter/ErrorDuringFileAnalyzeNotificationProvider.kt
new file mode 100644
index 00000000000..e30c84f475f
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/highlighter/ErrorDuringFileAnalyzeNotificationProvider.kt
@@ -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("kotlin.error.highlight.panel.key")
+private val HAS_ERRORS_IN_HIGHLIHTING_KEY = Key.create("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() {
+ 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
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java
index dcfc13246cf..027a7d92ba3 100644
--- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java
+++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetPsiChecker.java
@@ -16,7 +16,6 @@
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;
@@ -25,11 +24,14 @@ import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
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.Ref;
import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.*;
-import com.intellij.util.containers.MultiMap;
+import com.intellij.psi.MultiRangeReference;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -49,15 +51,10 @@ import org.jetbrains.jet.plugin.quickfix.QuickFixes;
import java.util.Collection;
import java.util.List;
-import java.util.Set;
public class JetPsiChecker implements Annotator, HighlightRangeExtension {
- private static final Logger LOG = Logger.getInstance(JetPsiChecker.class);
-
private static boolean isNamesHighlightingEnabled = true;
- private HighlightingPassCache passCache = null;
-
@TestOnly
public static void setNamesHighlightingEnabled(boolean namesHighlightingEnabled) {
isNamesHighlightingEnabled = namesHighlightingEnabled;
@@ -104,36 +101,41 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
JetFile file = (JetFile) element.getContainingFile();
- if (passCache == null || passCache.isOutdated(file)) {
- passCache = new HighlightingPassCache(AnalyzerFacadeWithCache.analyzeFileWithCache(file), file);
+ AnalyzeExhaust analyzeExhaust = AnalyzerFacadeWithCache.analyzeFileWithCache(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 = passCache.analyzeExhaust.getBindingContext();
- for (HighlightingVisitor visitor : getAfterAnalysisVisitor(holder, bindingContext)) {
- element.accept(visitor);
- }
+ BindingContext bindingContext = analyzeExhaust.getBindingContext();
+ for (HighlightingVisitor visitor : getAfterAnalysisVisitor(holder, bindingContext)) {
+ element.accept(visitor);
+ }
- if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false)) {
- for (Diagnostic diagnostic : passCache.elementToDiagnostic.get(element)) {
- registerDiagnosticAnnotations(diagnostic, passCache.redeclarations, holder);
- }
+ if (JetPluginUtil.isInSource(element, /* includeLibrarySources = */ false)) {
+ Ref isMarkedWithRedeclaration = Ref.create(false);
+ 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,
- @NotNull Set redeclarations,
- @NotNull AnnotationHolder holder) {
+ private static void registerDiagnosticAnnotations(
+ @NotNull PsiElement element, @NotNull Diagnostic diagnostic,
+ @NotNull AnnotationHolder holder, Ref isMarkedWithRedeclaration
+ ) {
if (!diagnostic.isValid()) return;
+
+ assert diagnostic.getPsiElement() == element;
+
List textRanges = diagnostic.getTextRanges();
if (diagnostic.getSeverity() == Severity.ERROR) {
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
@@ -144,9 +146,7 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
for (TextRange range : mrr.getRanges()) {
Annotation annotation = holder.createErrorAnnotation(range.shiftRight(referenceExpression.getTextOffset()), getDefaultMessage(diagnostic));
annotation.setTooltip(getMessage(diagnostic));
-
registerQuickFix(annotation, diagnostic);
-
annotation.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
}
@@ -171,8 +171,10 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
return;
}
- if (Errors.REDECLARATION_DIAGNOSTICS.contains(diagnostic.getFactory())) {
- registerQuickFix(markRedeclaration(redeclarations, diagnostic, holder), diagnostic);
+ if (!isMarkedWithRedeclaration.get() && Errors.REDECLARATION_DIAGNOSTICS.contains(diagnostic.getFactory())) {
+ isMarkedWithRedeclaration.set(true);
+ Annotation annotation = holder.createErrorAnnotation(diagnostic.getTextRanges().get(0), "");
+ annotation.setTooltip(getMessage(diagnostic));
return;
}
@@ -263,53 +265,8 @@ public class JetPsiChecker implements Annotator, HighlightRangeExtension {
return message;
}
- @Nullable
- private static Annotation markRedeclaration(@NotNull Set redeclarations,
- @NotNull Diagnostic redeclarationDiagnostic,
- @NotNull AnnotationHolder holder) {
- if (!redeclarations.add(redeclarationDiagnostic.getPsiElement())) return null;
- List textRanges = redeclarationDiagnostic.getTextRanges();
- if (!redeclarationDiagnostic.isValid()) return null;
- Annotation annotation = holder.createErrorAnnotation(textRanges.get(0), "");
- 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;
- }
- }
}