Use new annotation highlighting API
Fixed #KT-36712
This commit is contained in:
+106
@@ -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<TextRange>,
|
||||||
|
val nonDefaultMessage: String? = null,
|
||||||
|
val highlightType: ProblemHighlightType? = null,
|
||||||
|
val textAttributes: TextAttributesKey? = null
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun processDiagnostics(holder: AnnotationHolder, diagnostics: List<Diagnostic>, fixesMap: MultiMap<Diagnostic, IntentionAction>) {
|
||||||
|
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("<html>")) {
|
||||||
|
"<html>[$factoryName] ${message.substring("<html>".length)}"
|
||||||
|
} else {
|
||||||
|
"[$factoryName] $message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!message.startsWith("<html>")) {
|
||||||
|
message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
+97
@@ -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<TextRange>,
|
||||||
|
val nonDefaultMessage: String? = null,
|
||||||
|
val highlightType: ProblemHighlightType? = null,
|
||||||
|
val textAttributes: TextAttributesKey? = null
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun processDiagnostics(holder: AnnotationHolder, diagnostics: List<Diagnostic>, fixesMap: MultiMap<Diagnostic, IntentionAction>) {
|
||||||
|
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("<html>")) {
|
||||||
|
"<html>[$factoryName] ${message.substring("<html>".length)}"
|
||||||
|
} else {
|
||||||
|
"[$factoryName] $message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!message.startsWith("<html>")) {
|
||||||
|
message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,36 +17,28 @@
|
|||||||
package org.jetbrains.kotlin.idea.highlighter
|
package org.jetbrains.kotlin.idea.highlighter
|
||||||
|
|
||||||
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.IntentionAction
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.codeInspection.ProblemHighlightType
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
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.diagnostic.ControlFlowException
|
import com.intellij.openapi.diagnostic.ControlFlowException
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.editor.colors.CodeInsightColors
|
import com.intellij.openapi.editor.colors.CodeInsightColors
|
||||||
import com.intellij.openapi.editor.colors.TextAttributesKey
|
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException
|
import com.intellij.openapi.progress.ProcessCanceledException
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.util.TextRange
|
|
||||||
import com.intellij.psi.MultiRangeReference
|
import com.intellij.psi.MultiRangeReference
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.util.containers.MultiMap
|
import com.intellij.util.containers.MultiMap
|
||||||
import com.intellij.xml.util.XmlStringUtil
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
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.caches.resolve.analyzeWithAllCompilerChecks
|
||||||
import org.jetbrains.kotlin.idea.fir.FirResolution
|
import org.jetbrains.kotlin.idea.fir.FirResolution
|
||||||
import org.jetbrains.kotlin.idea.fir.firResolveState
|
import org.jetbrains.kotlin.idea.fir.firResolveState
|
||||||
import org.jetbrains.kotlin.idea.fir.getOrBuildFirWithDiagnostics
|
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.quickfix.QuickFixes
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -319,28 +311,7 @@ private class ElementAnnotator(
|
|||||||
MultiMap<Diagnostic, IntentionAction>()
|
MultiMap<Diagnostic, IntentionAction>()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (range in data.ranges) {
|
data.processDiagnostics(holder, diagnostics, fixesMap)
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -348,62 +319,3 @@ private class ElementAnnotator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AnnotationPresentationInfo(
|
|
||||||
val ranges: List<TextRange>,
|
|
||||||
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("<html>")) {
|
|
||||||
"<html>[$factoryName] ${message.substring("<html>".length)}"
|
|
||||||
} else {
|
|
||||||
"[$factoryName] $message"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!message.startsWith("<html>")) {
|
|
||||||
message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user