From 2e597a3a3284488006dd5a1bf1335145807d48d7 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Fri, 14 Feb 2020 13:39:15 +0100 Subject: [PATCH] Use new annotation highlighting API Fixed #KT-36712 --- .../highlighter/AnnotationPresentationInfo.kt | 106 ++++++++++++++++++ .../AnnotationPresentationInfo.kt.201 | 97 ++++++++++++++++ .../idea/highlighter/KotlinPsiChecker.kt | 90 +-------------- 3 files changed, 204 insertions(+), 89 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.201 diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt new file mode 100644 index 00000000000..5ce99901391 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeInsight.intention.EmptyIntentionAction +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.util.TextRange +import com.intellij.util.containers.MultiMap +import com.intellij.xml.util.XmlStringUtil +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages +import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix + +class AnnotationPresentationInfo( + val ranges: List, + val nonDefaultMessage: String? = null, + val highlightType: ProblemHighlightType? = null, + val textAttributes: TextAttributesKey? = null +) { + + fun processDiagnostics(holder: AnnotationHolder, diagnostics: List, fixesMap: MultiMap) { + for (range in ranges) { + for (diagnostic in diagnostics) { + val fixes = fixesMap[diagnostic] + val annotation = create(diagnostic, range, holder) + + fixes.forEach { + when (it) { + is KotlinUniversalQuickFix -> annotation.registerUniversalFix(it, null, null) + is IntentionAction -> annotation.registerFix(it) + } + } + + if (diagnostic.severity == Severity.WARNING) { + annotation.problemGroup = KotlinSuppressableWarningProblemGroup(diagnostic.factory) + + if (fixes.isEmpty()) { + // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions + annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name)) + } + } + } + } + } + + private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation { + val defaultMessage = nonDefaultMessage ?: getDefaultMessage(diagnostic) + + val annotation = when (diagnostic.severity) { + Severity.ERROR -> holder.createErrorAnnotation(range, defaultMessage) + Severity.WARNING -> { + if (highlightType == ProblemHighlightType.WEAK_WARNING) { + holder.createWeakWarningAnnotation(range, defaultMessage) + } else { + holder.createWarningAnnotation(range, defaultMessage) + } + } + Severity.INFO -> holder.createInfoAnnotation(range, defaultMessage) + } + + annotation.tooltip = getMessage(diagnostic) + + if (highlightType != null) { + annotation.highlightType = highlightType + } + + if (textAttributes != null) { + annotation.textAttributes = textAttributes + } + + return annotation + } + + private fun getMessage(diagnostic: Diagnostic): String { + var message = IdeErrorMessages.render(diagnostic) + if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { + val factoryName = diagnostic.factory.name + message = if (message.startsWith("")) { + "[$factoryName] ${message.substring("".length)}" + } else { + "[$factoryName] $message" + } + } + if (!message.startsWith("")) { + message = "${XmlStringUtil.escapeString(message)}" + } + return message + } + + private fun getDefaultMessage(diagnostic: Diagnostic): String { + val message = DefaultErrorMessages.render(diagnostic) + if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { + return "[${diagnostic.factory.name}] $message" + } + return message + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.201 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.201 new file mode 100644 index 00000000000..4d5af14f4eb --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.201 @@ -0,0 +1,97 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeInsight.intention.EmptyIntentionAction +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.lang.annotation.AnnotationBuilder +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.util.TextRange +import com.intellij.util.containers.MultiMap +import com.intellij.xml.util.XmlStringUtil +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages +import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix + +class AnnotationPresentationInfo( + val ranges: List, + val nonDefaultMessage: String? = null, + val highlightType: ProblemHighlightType? = null, + val textAttributes: TextAttributesKey? = null +) { + + fun processDiagnostics(holder: AnnotationHolder, diagnostics: List, fixesMap: MultiMap) { + for (range in ranges) { + for (diagnostic in diagnostics) { + val fixes = fixesMap[diagnostic] + create(diagnostic, range, holder) { annotation -> + fixes.forEach { + when (it) { + is KotlinUniversalQuickFix -> annotation.newFix(it).universal().registerFix() + is IntentionAction -> annotation.newFix(it).registerFix() + } + } + + if (diagnostic.severity == Severity.WARNING) { + annotation.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory)) + + if (fixes.isEmpty()) { + // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions + annotation.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix() + } + } + } + } + } + } + + private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (AnnotationBuilder) -> Unit) { + val severity = when (diagnostic.severity) { + Severity.ERROR -> HighlightSeverity.ERROR + Severity.WARNING -> if (highlightType == ProblemHighlightType.WEAK_WARNING) { + HighlightSeverity.WEAK_WARNING + } else HighlightSeverity.WARNING + Severity.INFO -> HighlightSeverity.WEAK_WARNING + } + + holder.newAnnotation(severity, nonDefaultMessage ?: getDefaultMessage(diagnostic)) + .range(range) + .tooltip(getMessage(diagnostic)) + .also { builder -> highlightType?.let { builder.highlightType(it) } } + .also { builder -> textAttributes?.let { builder.textAttributes(it) } } + .also { consumer(it) } + } + + private fun getMessage(diagnostic: Diagnostic): String { + var message = IdeErrorMessages.render(diagnostic) + if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { + val factoryName = diagnostic.factory.name + message = if (message.startsWith("")) { + "[$factoryName] ${message.substring("".length)}" + } else { + "[$factoryName] $message" + } + } + if (!message.startsWith("")) { + message = "${XmlStringUtil.escapeString(message)}" + } + return message + } + + private fun getDefaultMessage(diagnostic: Diagnostic): String { + val message = DefaultErrorMessages.render(diagnostic) + if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { + return "[${diagnostic.factory.name}] $message" + } + return message + } + +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt index c4b90c2050a..0404143e6cd 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt @@ -17,36 +17,28 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension -import com.intellij.codeInsight.intention.EmptyIntentionAction import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInspection.ProblemHighlightType -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.ControlFlowException import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.colors.CodeInsightColors -import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.util.Key -import com.intellij.openapi.util.TextRange import com.intellij.psi.MultiRangeReference import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.util.containers.MultiMap -import com.intellij.xml.util.XmlStringUtil import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks import org.jetbrains.kotlin.idea.fir.FirResolution import org.jetbrains.kotlin.idea.fir.firResolveState import org.jetbrains.kotlin.idea.fir.getOrBuildFirWithDiagnostics -import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix import org.jetbrains.kotlin.idea.quickfix.QuickFixes import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.psi.* @@ -319,28 +311,7 @@ private class ElementAnnotator( MultiMap() } - for (range in data.ranges) { - for (diagnostic in diagnostics) { - val annotation = data.create(diagnostic, range, holder) - val fixes = fixesMap[diagnostic] - - fixes.forEach { - when (it) { - is KotlinUniversalQuickFix -> annotation.registerUniversalFix(it, null, null) - is IntentionAction -> annotation.registerFix(it) - } - } - - if (diagnostic.severity == Severity.WARNING) { - annotation.problemGroup = KotlinSuppressableWarningProblemGroup(diagnostic.factory) - - if (fixes.isEmpty()) { - // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions - annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name)) - } - } - } - } + data.processDiagnostics(holder, diagnostics, fixesMap) } companion object { @@ -348,62 +319,3 @@ private class ElementAnnotator( } } -private class AnnotationPresentationInfo( - val ranges: List, - val nonDefaultMessage: String? = null, - val highlightType: ProblemHighlightType? = null, - val textAttributes: TextAttributesKey? = null -) { - - fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation { - val defaultMessage = nonDefaultMessage ?: getDefaultMessage(diagnostic) - - val annotation = when (diagnostic.severity) { - Severity.ERROR -> holder.createErrorAnnotation(range, defaultMessage) - Severity.WARNING -> { - if (highlightType == ProblemHighlightType.WEAK_WARNING) { - holder.createWeakWarningAnnotation(range, defaultMessage) - } else { - holder.createWarningAnnotation(range, defaultMessage) - } - } - Severity.INFO -> holder.createInfoAnnotation(range, defaultMessage) - } - - annotation.tooltip = getMessage(diagnostic) - - if (highlightType != null) { - annotation.highlightType = highlightType - } - - if (textAttributes != null) { - annotation.textAttributes = textAttributes - } - - return annotation - } - - private fun getMessage(diagnostic: Diagnostic): String { - var message = IdeErrorMessages.render(diagnostic) - if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { - val factoryName = diagnostic.factory.name - message = if (message.startsWith("")) { - "[$factoryName] ${message.substring("".length)}" - } else { - "[$factoryName] $message" - } - } - if (!message.startsWith("")) { - message = "${XmlStringUtil.escapeString(message)}" - } - return message - } - - private fun getDefaultMessage(diagnostic: Diagnostic): String { - val message = DefaultErrorMessages.render(diagnostic) - if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { - return "[${diagnostic.factory.name}] $message" - } - return message - } -}