Use highlight visitor instead of custom general like highlighting pass

#KTIJ-1760 Fixed
#KT-45254 Fixed
This commit is contained in:
Vladimir Dolzhenko
2021-03-04 07:11:58 +00:00
committed by Space
parent 5e173c9f83
commit cb92474af9
27 changed files with 335 additions and 367 deletions
@@ -1,64 +1,66 @@
/*
* 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 package org.jetbrains.kotlin.idea.highlighter
import com.intellij.codeInsight.daemon.impl.Divider import com.intellij.codeInsight.daemon.impl.Divider
import com.intellij.codeInsight.daemon.impl.HighlightInfo import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.HighlightVisitor
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.problems.ProblemImpl
import com.intellij.lang.annotation.Annotation
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Document
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.problems.Problem
import com.intellij.problems.WolfTheProblemSolver
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager import com.intellij.psi.PsiFile
import com.intellij.psi.PsiRecursiveElementVisitor
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.CommonProcessors import com.intellij.util.CommonProcessors
import com.intellij.util.containers.MultiMap import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.getJvmSignatureDiagnostics
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.rendering.RenderingContext import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.quickfix.QuickFixes import org.jetbrains.kotlin.idea.quickfix.QuickFixes
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import java.lang.reflect.* import java.lang.reflect.*
import java.util.* import java.util.*
import kotlin.collections.ArrayList
abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document) : abstract class AbstractKotlinHighlightVisitor : HighlightVisitor {
AbstractBindingContextAwareHighlightingPassBase(file, document) { private var afterAnalysisVisitor: Array<AfterAnalysisHighlightingVisitor>? = null
override val annotator: Annotator
get() = KotlinAfterAnalysisAnnotator()
private inner class KotlinAfterAnalysisAnnotator : Annotator { override fun suitableForFile(file: PsiFile) = file is KtFile
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
val bindingContext = bindingContext() override fun visit(element: PsiElement) {
getAfterAnalysisVisitor(holder, bindingContext).forEach { visitor -> element.accept(visitor) } afterAnalysisVisitor?.forEach(element::accept)
}
override fun analyze(psiFile: PsiFile, updateWholeFile: Boolean, holder: HighlightInfoHolder, action: Runnable): Boolean {
val file = psiFile as? KtFile ?: return false
try {
analyze(file, holder)
action.run()
} finally {
afterAnalysisVisitor = null
} }
return true
} }
override fun doApplyInformationToEditor() { private fun analyze(file: KtFile, holder: HighlightInfoHolder) {
super.doApplyInformationToEditor()
reportErrorsToWolf()
}
override fun buildBindingContext(holder: AnnotationHolder): BindingContext {
val dividedElements: List<Divider.DividedElements> = ArrayList() val dividedElements: List<Divider.DividedElements> = ArrayList()
Divider.divideInsideAndOutsideAllRoots( Divider.divideInsideAndOutsideAllRoots(
file, file.textRange, file.textRange, { true }, file, file.textRange, file.textRange, { true },
@@ -71,8 +73,8 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
// annotate diagnostics on fly: show diagnostics as soon as front-end reports them // annotate diagnostics on fly: show diagnostics as soon as front-end reports them
// don't create quick fixes as it could require some resolve // don't create quick fixes as it could require some resolve
val annotationByDiagnostic = mutableMapOf<Diagnostic, Annotation>() val highlightInfoByDiagnostic = mutableMapOf<Diagnostic, HighlightInfo>()
val annotationByTextRange = mutableMapOf<TextRange, Annotation>() val highlightInfoByTextRange = mutableMapOf<TextRange, HighlightInfo>()
// render of on-fly diagnostics with descriptors could lead to recursion // render of on-fly diagnostics with descriptors could lead to recursion
fun checkIfDescriptor(candidate: Any?): Boolean = fun checkIfDescriptor(candidate: Any?): Boolean =
@@ -82,61 +84,84 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
file.analyzeWithAllCompilerChecks({ file.analyzeWithAllCompilerChecks({
val element = it.psiElement val element = it.psiElement
if (element in elements && if (element in elements &&
it !in annotationByDiagnostic && it !in highlightInfoByDiagnostic &&
!RenderingContext.parameters(it).any(::checkIfDescriptor) !RenderingContext.parameters(it).any(::checkIfDescriptor)
) { ) {
annotateDiagnostic(element, holder, it, annotationByDiagnostic, annotationByTextRange) annotateDiagnostic(
file,
element,
holder,
it,
highlightInfoByDiagnostic,
highlightInfoByTextRange
)
} }
}).also { it.throwIfError() } }
).also { it.throwIfError() }
// resolve is done! // resolve is done!
val bindingContext = analysisResult.bindingContext val bindingContext = analysisResult.bindingContext
cleanUpCalculatingAnnotations(annotationByTextRange) afterAnalysisVisitor = getAfterAnalysisVisitor(holder, bindingContext)
// TODO: for some reasons it could be duplicated diagnostics for the same factory
// see [PsiCheckerTestGenerated$Checker.testRedeclaration]
val diagnostics = bindingContext.diagnostics.asSequence().filter { it.psiElement in elements }.toSet()
if (diagnostics.isNotEmpty()) { cleanUpCalculatingAnnotations(highlightInfoByTextRange)
// annotate diagnostics those were not possible to render on fly
diagnostics.asSequence().filterNot { it in annotationByDiagnostic }.forEach { annotateDuplicateJvmSignature(file, holder, bindingContext.diagnostics)
annotateDiagnostic(it.psiElement, holder, it, annotationByDiagnostic, calculatingInProgress = false)
} for (diagnostic in bindingContext.diagnostics) {
// apply quick fixes for all diagnostics grouping by element val psiElement = diagnostic.psiElement
diagnostics.groupBy(Diagnostic::psiElement).forEach { if (psiElement !in elements) continue
annotateQuickFixes(it.key, it.value, annotationByDiagnostic) // has been processed earlier e.g. on-fly or for some reasons it could be duplicated diagnostics for the same factory
} // see [PsiCheckerTestGenerated$Checker.testRedeclaration]
if (diagnostic in highlightInfoByDiagnostic) continue
// annotate diagnostics those were not possible to report (and therefore render) on fly
annotateDiagnostic(file, psiElement, holder, diagnostic, highlightInfoByDiagnostic, calculatingInProgress = false)
} }
return bindingContext
// apply quick fixes for all diagnostics grouping by element
highlightInfoByDiagnostic.keys.groupBy { it.psiElement }.forEach {
annotateQuickFixes(file, it.key, it.value, highlightInfoByDiagnostic)
}
}
private fun annotateDuplicateJvmSignature(file: KtFile, holder: HighlightInfoHolder, otherDiagnostics: Diagnostics) {
if (!(ProjectRootsUtil.isInProjectSource(file) && TargetPlatformDetector.getPlatform(file).isJvm())) return
val duplicateJvmSignatureAnnotator =
DuplicateJvmSignatureAnnotator(file, holder, otherDiagnostics, file.getModuleInfo().contentScope())
duplicateJvmSignatureAnnotator.visit()
} }
private fun annotateDiagnostic( private fun annotateDiagnostic(
file: KtFile,
element: PsiElement, element: PsiElement,
holder: AnnotationHolder, holder: HighlightInfoHolder,
diagnostic: Diagnostic, diagnostic: Diagnostic,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>? = null, highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>? = null, highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>? = null,
calculatingInProgress: Boolean = true calculatingInProgress: Boolean = true
) = annotateDiagnostics(element, holder, listOf(diagnostic), annotationByDiagnostic, annotationByTextRange, true, calculatingInProgress) ) = annotateDiagnostics(file, element, holder, listOf(diagnostic), highlightInfoByDiagnostic, highlightInfoByTextRange, true, calculatingInProgress)
private fun cleanUpCalculatingAnnotations(annotationByTextRange: Map<TextRange, Annotation>) { private fun cleanUpCalculatingAnnotations(highlightInfoByTextRange: Map<TextRange, HighlightInfo>) {
annotationByTextRange.values.forEach { annotation -> highlightInfoByTextRange.values.forEach { annotation ->
annotation.quickFixes?.removeIf { annotation.unregisterQuickFix {
it.quickFix is CalculatingIntentionAction it is CalculatingIntentionAction
} }
} }
} }
private fun annotateDiagnostics( private fun annotateDiagnostics(
file: KtFile,
element: PsiElement, element: PsiElement,
holder: AnnotationHolder, holder: HighlightInfoHolder,
diagnostics: List<Diagnostic>, diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>? = null, highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>? = null, highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>? = null,
noFixes: Boolean = false, noFixes: Boolean = false,
calculatingInProgress: Boolean = false calculatingInProgress: Boolean = false
) = annotateDiagnostics( ) = annotateDiagnostics(
file, element, holder, diagnostics, annotationByDiagnostic, annotationByTextRange, file, element, holder, diagnostics, highlightInfoByDiagnostic, highlightInfoByTextRange,
::shouldSuppressUnusedParameter, ::shouldSuppressUnusedParameter,
noFixes = noFixes, calculatingInProgress = calculatingInProgress noFixes = noFixes, calculatingInProgress = calculatingInProgress
) )
@@ -145,9 +170,10 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
* [diagnostics] has to belong to the same element * [diagnostics] has to belong to the same element
*/ */
private fun annotateQuickFixes( private fun annotateQuickFixes(
file: KtFile,
element: PsiElement, element: PsiElement,
diagnostics: List<Diagnostic>, diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation> highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>
) { ) {
if (diagnostics.isEmpty()) return if (diagnostics.isEmpty()) return
@@ -161,63 +187,64 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
if (shouldHighlightErrors) { if (shouldHighlightErrors) {
ElementAnnotator(element) { param -> ElementAnnotator(element) { param ->
shouldSuppressUnusedParameter(param) shouldSuppressUnusedParameter(param)
}.registerDiagnosticsQuickFixes(diagnostics, annotationByDiagnostic) }.registerDiagnosticsQuickFixes(diagnostics, highlightInfoByDiagnostic)
} }
} }
protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false
private fun reportErrorsToWolf() { private inner class DuplicateJvmSignatureAnnotator(
if (!file.viewProvider.isPhysical) return // e.g. errors in evaluate expression private val file: KtFile,
val project: Project = file.project private val holder: HighlightInfoHolder,
if (!PsiManager.getInstance(project).isInProject(file)) return // do not report problems in libraries private val otherDiagnostics: Diagnostics,
val file: VirtualFile = file.virtualFile ?: return private val moduleScope: GlobalSearchScope
) {
fun visit() {
file.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) {
annotate(element)
super.visitElement(element)
}
})
}
val wolf = WolfTheProblemSolver.getInstance(project) private fun annotate(element: PsiElement) {
if (element !is KtFile && element !is KtDeclaration) return
val hasSyntaxErrors = wolf.hasSyntaxErrors(file) val diagnostics = getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope) ?: return
val problemFile = wolf.isProblemFile(file)
// do nothing if file has already problems val diagnosticsForElement = diagnostics.forElement(element).toSet()
if (hasSyntaxErrors || problemFile) return
val problems = convertToProblems(infos, file) annotateDiagnostics(file, element, holder, diagnosticsForElement)
wolf.reportProblems(file, problems) }
} }
private fun convertToProblems(
infos: Collection<HighlightInfo>,
file: VirtualFile,
hasErrorElement: Boolean = true
): List<Problem> =
infos.filter { it.severity == HighlightSeverity.ERROR }.map { ProblemImpl(file, it, hasErrorElement) }
companion object { companion object {
fun createQuickFixes(diagnostic: Diagnostic): Collection<IntentionAction> = private val UNRESOLVED_KEY = Key<Unit>("KotlinHighlightVisitor.UNRESOLVED_KEY")
createQuickFixes(listOfNotNull(diagnostic))[diagnostic]
private val UNRESOLVED_KEY = Key<Unit>("KotlinHighlightingPass.UNRESOLVED_KEY") fun getAfterAnalysisVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) = arrayOf(
fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null
fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf(
PropertiesHighlightingVisitor(holder, bindingContext), PropertiesHighlightingVisitor(holder, bindingContext),
FunctionsHighlightingVisitor(holder, bindingContext), FunctionsHighlightingVisitor(holder, bindingContext),
VariablesHighlightingVisitor(holder, bindingContext), VariablesHighlightingVisitor(holder, bindingContext),
TypeKindHighlightingVisitor(holder, bindingContext) TypeKindHighlightingVisitor(holder, bindingContext)
) )
private fun assertBelongsToTheSameElement(element: PsiElement, diagnostics: Collection<Diagnostic>) { fun createQuickFixes(diagnostic: Diagnostic): Collection<IntentionAction> =
createQuickFixes(listOfNotNull(diagnostic))[diagnostic]
fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null
internal fun assertBelongsToTheSameElement(element: PsiElement, diagnostics: Collection<Diagnostic>) {
assert(diagnostics.all { it.psiElement == element }) assert(diagnostics.all { it.psiElement == element })
} }
fun annotateDiagnostics( fun annotateDiagnostics(
file: KtFile, file: KtFile,
element: PsiElement, element: PsiElement,
holder: AnnotationHolder, holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>, diagnostics: Collection<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>? = null, highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>? = null, highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>? = null,
shouldSuppressUnusedParameter: (KtParameter) -> Boolean = { false }, shouldSuppressUnusedParameter: (KtParameter) -> Boolean = { false },
noFixes: Boolean = false, noFixes: Boolean = false,
calculatingInProgress: Boolean = false calculatingInProgress: Boolean = false
@@ -241,16 +268,16 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
shouldSuppressUnusedParameter(param) shouldSuppressUnusedParameter(param)
} }
elementAnnotator.registerDiagnosticsAnnotations( elementAnnotator.registerDiagnosticsAnnotations(
holder, diagnostics, annotationByDiagnostic, holder, diagnostics, highlightInfoByDiagnostic,
annotationByTextRange, highlightInfoByTextRange,
noFixes = noFixes, calculatingInProgress = calculatingInProgress noFixes = noFixes, calculatingInProgress = calculatingInProgress
) )
} }
} }
} }
} }
internal fun createQuickFixes(similarDiagnostics: Collection<Diagnostic>): MultiMap<Diagnostic, IntentionAction> { internal fun createQuickFixes(similarDiagnostics: Collection<Diagnostic>): MultiMap<Diagnostic, IntentionAction> {
val first = similarDiagnostics.minByOrNull { it.toString() } val first = similarDiagnostics.minByOrNull { it.toString() }
val factory = similarDiagnostics.first().getRealDiagnosticFactory() val factory = similarDiagnostics.first().getRealDiagnosticFactory()
@@ -278,6 +305,7 @@ internal fun createQuickFixes(similarDiagnostics: Collection<Diagnostic>): Multi
return actions return actions
} }
private fun Diagnostic.getRealDiagnosticFactory(): DiagnosticFactory<*> = private fun Diagnostic.getRealDiagnosticFactory(): DiagnosticFactory<*> =
when (factory) { when (factory) {
Errors.PLUGIN_ERROR -> Errors.PLUGIN_ERROR.cast(this).a.factory Errors.PLUGIN_ERROR -> Errors.PLUGIN_ERROR.cast(this).a.factory
@@ -330,3 +358,4 @@ private object NoDeclarationDescriptorsChecker {
} }
} }
} }
@@ -16,7 +16,7 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.Extensions
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
@@ -28,8 +28,8 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
abstract class AfterAnalysisHighlightingVisitor protected constructor( abstract class AfterAnalysisHighlightingVisitor protected constructor(
holder: AnnotationHolder, protected var bindingContext: BindingContext holder: HighlightInfoHolder, protected var bindingContext: BindingContext
) : HighlightingVisitor(holder) { ) : AbstractHighlightInfoHolderHighlightingVisitor(holder) {
protected fun attributeKeyForDeclarationFromExtensions(element: PsiElement, descriptor: DeclarationDescriptor): TextAttributesKey? { protected fun attributeKeyForDeclarationFromExtensions(element: PsiElement, descriptor: DeclarationDescriptor): TextAttributesKey? {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@@ -5,12 +5,14 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.HighlightInfoType
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction
import com.intellij.codeInsight.intention.EmptyIntentionAction 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.openapi.editor.colors.CodeInsightColors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.util.containers.MultiMap import com.intellij.util.containers.MultiMap
@@ -30,23 +32,24 @@ class AnnotationPresentationInfo(
) { ) {
fun processDiagnostics( fun processDiagnostics(
holder: AnnotationHolder, holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>, diagnostics: Collection<Diagnostic>,
annotationBuilderByDiagnostic: MutableMap<Diagnostic, Annotation>? = null, highlightInfoBuilderByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>?, highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
fixesMap: MultiMap<Diagnostic, IntentionAction>?, fixesMap: MultiMap<Diagnostic, IntentionAction>?,
calculatingInProgress: Boolean calculatingInProgress: Boolean
) { ) {
for (range in ranges) { for (range in ranges) {
for (diagnostic in diagnostics) { for (diagnostic in diagnostics) {
create(diagnostic, range, holder) { annotation -> create(diagnostic, range) { info ->
annotationBuilderByDiagnostic?.put(diagnostic, annotation) holder.add(info)
highlightInfoBuilderByDiagnostic?.put(diagnostic, info)
if (fixesMap != null) { if (fixesMap != null) {
applyFixes(fixesMap, diagnostic, annotation) applyFixes(fixesMap, diagnostic, info)
} }
if (calculatingInProgress && annotationByTextRange?.containsKey(range) == false) { if (calculatingInProgress && highlightInfoByTextRange?.containsKey(range) == false) {
annotationByTextRange[range] = annotation highlightInfoByTextRange[range] = info
annotation.registerFix(CalculatingIntentionAction(), range) QuickFixAction.registerQuickFixAction(info, CalculatingIntentionAction())
} }
} }
} }
@@ -56,55 +59,36 @@ class AnnotationPresentationInfo(
internal fun applyFixes( internal fun applyFixes(
fixesMap: MultiMap<Diagnostic, IntentionAction>, fixesMap: MultiMap<Diagnostic, IntentionAction>,
diagnostic: Diagnostic, diagnostic: Diagnostic,
annotation: Annotation info: HighlightInfo
) { ) {
val fixes = fixesMap[diagnostic] val fixes = fixesMap[diagnostic]
val textRange = TextRange(annotation.startOffset, annotation.endOffset) fixes.filter { it is IntentionAction || it is KotlinUniversalQuickFix }.forEach {
fixes.forEach { QuickFixAction.registerQuickFixAction(info, it)
when (it) {
is KotlinUniversalQuickFix -> {
annotation.registerBatchFix(it, textRange, null)
annotation.registerFix(it, textRange)
}
is IntentionAction -> {
annotation.registerFix(it, textRange)
}
}
} }
if (diagnostic.severity == Severity.WARNING) { if (diagnostic.severity == Severity.WARNING) {
if (fixes.isEmpty()) { if (fixes.isEmpty()) {
// if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
//annotation.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix() QuickFixAction.registerQuickFixAction(info, EmptyIntentionAction(diagnostic.factory.name))
annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name), textRange)
} }
} }
} }
private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (Annotation) -> Unit) { private fun create(diagnostic: Diagnostic, range: TextRange, consumer: (HighlightInfo) -> 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
}
val message = nonDefaultMessage ?: getDefaultMessage(diagnostic) val message = nonDefaultMessage ?: getDefaultMessage(diagnostic)
holder.newAnnotation(severity, message) HighlightInfo
.newHighlightInfo(toHighlightInfoType(highlightType, diagnostic.severity))
.range(range) .range(range)
.tooltip(getMessage(diagnostic)) .description(message)
.also { builder -> highlightType?.let { builder.highlightType(it) } } .escapedToolTip(getMessage(diagnostic))
.also { builder -> textAttributes?.let { builder.textAttributes(it) } } .also { builder -> textAttributes?.let(builder::textAttributes) ?: convertSeverityTextAttributes(highlightType, diagnostic.severity)?.let(builder::textAttributes) }
.also { .also {
if (diagnostic.severity == Severity.WARNING) { if (diagnostic.severity == Severity.WARNING) {
it.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory)) it.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory))
} }
} }
.create() .createUnconditionally()
@Suppress("UNCHECKED_CAST") .also(consumer)
(holder as? List<Annotation>)?.last()?.let(consumer::invoke)
} }
private fun getMessage(diagnostic: Diagnostic): String { private fun getMessage(diagnostic: Diagnostic): String {
@@ -132,4 +116,42 @@ class AnnotationPresentationInfo(
} }
} }
private fun toHighlightInfoType(highlightType: ProblemHighlightType?, severity: Severity): HighlightInfoType =
when (highlightType) {
ProblemHighlightType.LIKE_UNUSED_SYMBOL -> HighlightInfoType.UNUSED_SYMBOL
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL -> HighlightInfoType.WRONG_REF
ProblemHighlightType.LIKE_DEPRECATED -> HighlightInfoType.DEPRECATED
ProblemHighlightType.LIKE_MARKED_FOR_REMOVAL -> HighlightInfoType.MARKED_FOR_REMOVAL
else -> convertSeverity(highlightType, severity)
}
private fun convertSeverity(highlightType: ProblemHighlightType?, severity: Severity): HighlightInfoType =
when (severity) {
Severity.ERROR -> HighlightInfoType.ERROR
Severity.WARNING -> {
if (highlightType == ProblemHighlightType.WEAK_WARNING) {
HighlightInfoType.WEAK_WARNING
} else HighlightInfoType.WARNING
}
Severity.INFO -> HighlightInfoType.WEAK_WARNING
else -> HighlightInfoType.INFORMATION
}
private fun convertSeverityTextAttributes(highlightType: ProblemHighlightType?, severity: Severity): TextAttributesKey? =
when (highlightType) {
null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING ->
when (severity) {
Severity.ERROR -> CodeInsightColors.ERRORS_ATTRIBUTES
Severity.WARNING -> {
if (highlightType == ProblemHighlightType.WEAK_WARNING) {
CodeInsightColors.WEAK_WARNING_ATTRIBUTES
} else CodeInsightColors.WARNINGS_ATTRIBUTES
}
Severity.INFO -> CodeInsightColors.WARNINGS_ATTRIBUTES
else -> null
}
ProblemHighlightType.GENERIC_ERROR -> CodeInsightColors.ERRORS_ATTRIBUTES
else -> null
}
} }
@@ -1,74 +0,0 @@
/*
* 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.codeHighlighting.*
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.asJava.getJvmSignatureDiagnostics
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass.Companion.annotateDiagnostics
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
class DuplicateJvmSignatureHighlightPass(file: KtFile, document: Document) :
AbstractBindingContextAwareHighlightingPassBase(file, document) {
override val annotator: Annotator
get() = DuplicateJvmSignatureAnnotator()
inner class DuplicateJvmSignatureAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
if (element !is KtFile && element !is KtDeclaration) return
val otherDiagnostics = when (element) {
is KtDeclaration -> element.analyzeWithContent()
is KtFile -> element.analyzeWithContent()
else -> throw AssertionError("DuplicateJvmSignatureAnnotator: should not get here! Element: ${element.text}")
}.diagnostics
val moduleScope = element.getModuleInfo().contentScope()
val diagnostics = getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope) ?: return
val diagnosticsForElement = diagnostics.forElement(element).toSet()
annotateDiagnostics(file, element, holder, diagnosticsForElement)
}
}
class Factory : TextEditorHighlightingPassFactory {
override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {
return if (file is KtFile &&
ProjectRootsUtil.isInProjectSource(file) &&
TargetPlatformDetector.getPlatform(file).isJvm()
) {
DuplicateJvmSignatureHighlightPass(file, editor.document)
} else {
null
}
}
}
class Registrar : TextEditorHighlightingPassFactoryRegistrar {
override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) {
registrar.registerTextEditorHighlightingPass(
Factory(),
/* runAfterCompletionOf = */ intArrayOf(Pass.UPDATE_ALL),
/* runAfterStartingOf = */ null,
/* runIntentionsPassAfter = */ false,
/* forcedPassId = */ -1
)
}
}
}
@@ -5,10 +5,11 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
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.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
@@ -31,10 +32,10 @@ internal class ElementAnnotator(
private val shouldSuppressUnusedParameter: (KtParameter) -> Boolean private val shouldSuppressUnusedParameter: (KtParameter) -> Boolean
) { ) {
fun registerDiagnosticsAnnotations( fun registerDiagnosticsAnnotations(
holder: AnnotationHolder, holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>, diagnostics: Collection<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>?, highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>?,
annotationByTextRange: MutableMap<TextRange, Annotation>?, highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
noFixes: Boolean, noFixes: Boolean,
calculatingInProgress: Boolean calculatingInProgress: Boolean
) = diagnostics.groupBy { it.factory } ) = diagnostics.groupBy { it.factory }
@@ -42,18 +43,18 @@ internal class ElementAnnotator(
registerSameFactoryDiagnosticsAnnotations( registerSameFactoryDiagnosticsAnnotations(
holder, holder,
it.value, it.value,
annotationByDiagnostic, highlightInfoByDiagnostic,
annotationByTextRange, highlightInfoByTextRange,
noFixes, noFixes,
calculatingInProgress calculatingInProgress
) )
} }
private fun registerSameFactoryDiagnosticsAnnotations( private fun registerSameFactoryDiagnosticsAnnotations(
holder: AnnotationHolder, holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>, diagnostics: Collection<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>?, highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>?,
annotationByTextRange: MutableMap<TextRange, Annotation>?, highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
noFixes: Boolean, noFixes: Boolean,
calculatingInProgress: Boolean calculatingInProgress: Boolean
) { ) {
@@ -62,8 +63,8 @@ internal class ElementAnnotator(
holder, holder,
diagnostics, diagnostics,
presentationInfo, presentationInfo,
annotationByDiagnostic, highlightInfoByDiagnostic,
annotationByTextRange, highlightInfoByTextRange,
noFixes, noFixes,
calculatingInProgress calculatingInProgress
) )
@@ -71,21 +72,21 @@ internal class ElementAnnotator(
fun registerDiagnosticsQuickFixes( fun registerDiagnosticsQuickFixes(
diagnostics: List<Diagnostic>, diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation> highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>
) = diagnostics.groupBy { it.factory } ) = diagnostics.groupBy { it.factory }
.forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, annotationByDiagnostic) } .forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, highlightInfoByDiagnostic) }
private fun registerDiagnosticsSameFactoryQuickFixes( private fun registerDiagnosticsSameFactoryQuickFixes(
diagnostics: List<Diagnostic>, diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation> highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>
) { ) {
val presentationInfo = presentationInfo(diagnostics) ?: return val presentationInfo = presentationInfo(diagnostics) ?: return
val fixesMap = createFixesMap(diagnostics) ?: return val fixesMap = createFixesMap(diagnostics) ?: return
diagnostics.forEach { diagnostics.forEach {
val annotation = annotationByDiagnostic[it] ?: return val highlightInfo = highlightInfoByDiagnostic[it] ?: return
presentationInfo.applyFixes(fixesMap, it, annotation) presentationInfo.applyFixes(fixesMap, it, highlightInfo)
} }
} }
@@ -161,18 +162,18 @@ internal class ElementAnnotator(
} }
private fun setUpAnnotations( private fun setUpAnnotations(
holder: AnnotationHolder, holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>, diagnostics: Collection<Diagnostic>,
data: AnnotationPresentationInfo, data: AnnotationPresentationInfo,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>?, highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>?,
annotationByTextRange: MutableMap<TextRange, Annotation>?, highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
noFixes: Boolean, noFixes: Boolean,
calculatingInProgress: Boolean calculatingInProgress: Boolean
) { ) {
val fixesMap = val fixesMap =
createFixesMap(diagnostics, noFixes) createFixesMap(diagnostics, noFixes)
data.processDiagnostics(holder, diagnostics, annotationByDiagnostic, annotationByTextRange, fixesMap, calculatingInProgress) data.processDiagnostics(holder, diagnostics, highlightInfoByDiagnostic, highlightInfoByTextRange, fixesMap, calculatingInProgress)
} }
private fun createFixesMap( private fun createFixesMap(
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.Extensions
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.serialization.deserialization.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME import org.jetbrains.kotlin.serialization.deserialization.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class FunctionsHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) : internal class FunctionsHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) { AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitBinaryExpression(expression: KtBinaryExpression) { override fun visitBinaryExpression(expression: KtBinaryExpression) {
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.Extensions
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized import org.jetbrains.kotlin.resolve.calls.tower.isSynthesized
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) : internal class PropertiesHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) { AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
internal class TypeKindHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) : internal class TypeKindHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) { AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.PsiNameIdentifierOwner
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.types.expressions.CaptureKind import org.jetbrains.kotlin.types.expressions.CaptureKind
internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) : internal class VariablesHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) { AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
@@ -9,8 +9,7 @@ import com.intellij.codeInsight.completion.PrefixMatcher
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightVisitor
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallExpression
@@ -29,7 +28,7 @@ class FromUnresolvedNamesCompletion(
scope.forEachDescendantOfType<KtNameReferenceExpression> { refExpr -> scope.forEachDescendantOfType<KtNameReferenceExpression> { refExpr ->
ProgressManager.checkCanceled() ProgressManager.checkCanceled()
if (AbstractKotlinHighlightingPass.wasUnresolved(refExpr)) { if (AbstractKotlinHighlightVisitor.wasUnresolved(refExpr)) {
val callTypeAndReceiver = CallTypeAndReceiver.detect(refExpr) val callTypeAndReceiver = CallTypeAndReceiver.detect(refExpr)
if (callTypeAndReceiver.receiver != null) return@forEachDescendantOfType if (callTypeAndReceiver.receiver != null) return@forEachDescendantOfType
if (sampleDescriptor != null) { if (sampleDescriptor != null) {
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class DeclarationHighlightingVisitor(holder: AnnotationHolder) : HighlightingVisitor(holder) { internal class DeclarationHighlightingVisitor(holder: AnnotationHolder) : AbstractAnnotationHolderHighlightingVisitor(holder) {
override fun visitTypeAlias(typeAlias: KtTypeAlias) { override fun visitTypeAlias(typeAlias: KtTypeAlias) {
highlightNamedDeclaration(typeAlias, Colors.TYPE_ALIAS) highlightNamedDeclaration(typeAlias, Colors.TYPE_ALIAS)
super.visitTypeAlias(typeAlias) super.visitTypeAlias(typeAlias)
@@ -56,6 +56,6 @@ internal class DeclarationHighlightingVisitor(holder: AnnotationHolder) : Highli
} }
class DeclarationHighlightingExtension : BeforeResolveHighlightingExtension { class DeclarationHighlightingExtension : BeforeResolveHighlightingExtension {
override fun createVisitor(holder: AnnotationHolder): HighlightingVisitor = override fun createVisitor(holder: AnnotationHolder): AbstractHighlightingVisitor =
DeclarationHighlightingVisitor(holder) DeclarationHighlightingVisitor(holder)
} }
@@ -9,12 +9,12 @@ import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.HighlightingVisitor import org.jetbrains.kotlin.idea.highlighter.AbstractAnnotationHolderHighlightingVisitor
abstract class FirAfterResolveHighlightingVisitor( abstract class FirAfterResolveHighlightingVisitor(
protected val analysisSession: KtAnalysisSession, protected val analysisSession: KtAnalysisSession,
protected val holder: AnnotationHolder protected val holder: AnnotationHolder
) : HighlightingVisitor(holder) { ) : AbstractAnnotationHolderHighlightingVisitor(holder) {
override fun createInfoAnnotation(textRange: TextRange, message: String?, textAttributes: TextAttributesKey?) { override fun createInfoAnnotation(textRange: TextRange, message: String?, textAttributes: TextAttributesKey?) {
// TODO: Temporary use deprecated for FIR plugin as it is supposes to be rewritten fully // TODO: Temporary use deprecated for FIR plugin as it is supposes to be rewritten fully
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2021 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.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange
abstract class AbstractAnnotationHolderHighlightingVisitor protected constructor(private val holder: AnnotationHolder): AbstractHighlightingVisitor() {
override fun createInfoAnnotation(textRange: TextRange, message: String?, textAttributes: TextAttributesKey?) {
(message?.let { holder.newAnnotation(HighlightSeverity.INFORMATION, it) }
?: holder.newSilentAnnotation(HighlightSeverity.INFORMATION))
.range(textRange)
.also { builder -> textAttributes?.let { builder.textAttributes(it) } }
.create()
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2021 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.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.HighlightInfoType
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange
abstract class AbstractHighlightInfoHolderHighlightingVisitor protected constructor(private val holder: HighlightInfoHolder) :
AbstractHighlightingVisitor() {
override fun createInfoAnnotation(textRange: TextRange, message: String?, textAttributes: TextAttributesKey?) {
HighlightInfo.newHighlightInfo(HighlightInfoType.INFORMATION)
.range(textRange)
.also { builder -> message?.let { builder.description(it) } }
.also { builder ->
textAttributes?.let {
builder.textAttributes(it)
}
}
.create()
.also { holder.add(it) }
}
}
@@ -5,17 +5,13 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtVisitorVoid import org.jetbrains.kotlin.psi.KtVisitorVoid
abstract class HighlightingVisitor protected constructor( abstract class AbstractHighlightingVisitor : KtVisitorVoid() {
private val holder: AnnotationHolder
) : KtVisitorVoid() {
protected fun createInfoAnnotation(element: PsiElement, message: String? = null, textAttributes: TextAttributesKey) { protected fun createInfoAnnotation(element: PsiElement, message: String? = null, textAttributes: TextAttributesKey) {
createInfoAnnotation(element.textRange, message, textAttributes) createInfoAnnotation(element.textRange, message, textAttributes)
@@ -24,17 +20,7 @@ abstract class HighlightingVisitor protected constructor(
protected fun createInfoAnnotation(element: PsiElement, message: String? = null) = protected fun createInfoAnnotation(element: PsiElement, message: String? = null) =
createInfoAnnotation(element.textRange, message) createInfoAnnotation(element.textRange, message)
protected open fun createInfoAnnotation(textRange: TextRange, message: String? = null, textAttributes: TextAttributesKey? = null) { protected abstract fun createInfoAnnotation(textRange: TextRange, message: String? = null, textAttributes: TextAttributesKey? = null)
(message?.let { holder.newAnnotation(HighlightSeverity.INFORMATION, it) }
?: holder.newSilentAnnotation(HighlightSeverity.INFORMATION))
.range(textRange)
.also { builder ->
textAttributes?.let {
builder.textAttributes(it)
}
}
.create()
}
protected fun highlightName(element: PsiElement, attributesKey: TextAttributesKey, message: String? = null) { protected fun highlightName(element: PsiElement, attributesKey: TextAttributesKey, message: String? = null) {
if (NameHighlighter.namesHighlightingEnabled && !element.textRange.isEmpty) { if (NameHighlighter.namesHighlightingEnabled && !element.textRange.isEmpty) {
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : HighlightingVisitor(holder) { internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : AbstractAnnotationHolderHighlightingVisitor(holder) {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
val elementType = element.node.elementType val elementType = element.node.elementType
@@ -56,5 +56,5 @@ class KotlinBeforeResolveHighlightingPass(file: KtFile, document: Document) : Ab
} }
interface BeforeResolveHighlightingExtension { interface BeforeResolveHighlightingExtension {
fun createVisitor(holder: AnnotationHolder): HighlightingVisitor fun createVisitor(holder: AnnotationHolder): AbstractHighlightingVisitor
} }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.perf
import com.intellij.codeHighlighting.* import com.intellij.codeHighlighting.*
import com.intellij.codeInsight.daemon.impl.HighlightInfo import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressIndicator
@@ -15,7 +16,7 @@ import com.intellij.psi.PsiFile
import com.intellij.testFramework.RunAll import com.intellij.testFramework.RunAll
import com.intellij.util.ThrowableRunnable import com.intellij.util.ThrowableRunnable
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightVisitor
import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
import org.jetbrains.kotlin.idea.perf.util.Metric import org.jetbrains.kotlin.idea.perf.util.Metric
@@ -379,8 +380,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
private fun replaceWithCustomHighlighter() { private fun replaceWithCustomHighlighter() {
org.jetbrains.kotlin.idea.testFramework.replaceWithCustomHighlighter( org.jetbrains.kotlin.idea.testFramework.replaceWithCustomHighlighter(
testRootDisposable, testRootDisposable,
KotlinHighlightingPass.Registrar::class.java.name, KotlinHighlightVisitor::class.java.name,
TestKotlinHighlightingPass.Registrar::class.java.name TestKotlinHighlightVisitor::class.java.name
) )
} }
@@ -434,38 +435,21 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
} }
class TestKotlinHighlightingPass(file: KtFile, document: Document) : KotlinHighlightingPass(file, document) { class TestKotlinHighlightVisitor : KotlinHighlightVisitor() {
override fun doCollectInformation(progress: ProgressIndicator) { override fun analyze(psiFile: PsiFile, updateWholeFile: Boolean, holder: HighlightInfoHolder, action: Runnable): Boolean {
annotationCallback { // TODO:
val nowNs = System.nanoTime() //annotationCallback {
diagnosticTimer.addAndGet(nowNs) // val nowNs = System.nanoTime()
resetAnnotationCallback() // diagnosticTimer.addAndGet(nowNs)
} // resetAnnotationCallback()
//}
try { try {
super.doCollectInformation(progress) return super.analyze(psiFile, updateWholeFile, holder, action)
} finally { } finally {
resetAnnotationCallback() //resetAnnotationCallback()
markTimestamp() markTimestamp()
} }
} }
class Factory : TextEditorHighlightingPassFactory {
override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {
if (file !is KtFile) return null
return TestKotlinHighlightingPass(file, editor.document)
}
}
class Registrar : TextEditorHighlightingPassFactoryRegistrar {
override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) {
registrar.registerTextEditorHighlightingPass(
Factory(),
null,
intArrayOf(Pass.UPDATE_ALL),
false,
-1
)
}
}
} }
} }
@@ -134,10 +134,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/>
<highlightVisitor implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightVisitor"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DuplicateJvmSignatureHighlightPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/>
@@ -134,10 +134,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/>
<highlightVisitor implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightVisitor"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DuplicateJvmSignatureHighlightPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/>
@@ -133,10 +133,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/>
<highlightVisitor implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightVisitor"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DuplicateJvmSignatureHighlightPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/>
@@ -114,10 +114,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.completion.LookupCancelService"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/> <projectService serviceImplementation="org.jetbrains.kotlin.idea.configuration.KotlinMigrationProjectService"/>
<highlightVisitor implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightVisitor"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinBeforeResolveHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DebugInfoHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.DuplicateJvmSignatureHighlightPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.highlighter.ScriptExternalHighlightingPass$Registrar"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/> <highlightingPassFactory implementation="org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsPassFactory$Registrar"/>
@@ -0,0 +1,23 @@
/*
* 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.daemon.impl.HighlightVisitor
import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection
import org.jetbrains.kotlin.idea.isMainFunction
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
open class KotlinHighlightVisitor : AbstractKotlinHighlightVisitor() {
override fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean {
val grandParent = parameter.parent.parent as? KtNamedFunction ?: return false
if (!UnusedSymbolInspection.isEntryPoint(grandParent)) return false
return !grandParent.isMainFunction()
}
override fun clone(): HighlightVisitor = KotlinHighlightVisitor()
}
@@ -1,45 +0,0 @@
/*
* 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.codeHighlighting.*
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection
import org.jetbrains.kotlin.idea.isMainFunction
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
open class KotlinHighlightingPass(file: KtFile, document: Document) : AbstractKotlinHighlightingPass(file, document) {
override fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean {
val grandParent = parameter.parent.parent as? KtNamedFunction ?: return false
if (!UnusedSymbolInspection.isEntryPoint(grandParent)) return false
return !grandParent.isMainFunction()
}
class Factory : TextEditorHighlightingPassFactory {
override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? {
if (file !is KtFile) return null
return KotlinHighlightingPass(file, editor.document)
}
}
class Registrar : TextEditorHighlightingPassFactoryRegistrar {
override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) {
registrar.registerTextEditorHighlightingPass(
Factory(),
/* runAfterCompletionOf = */ null,
/* runAfterStartingOf = */ intArrayOf(Pass.UPDATE_ALL),
/* runIntentionsPassAfter = */false,
/* forcedPassId = */-1
)
}
}
}
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightVisitor
import org.jetbrains.kotlin.idea.quickfix.CleanupFix import org.jetbrains.kotlin.idea.quickfix.CleanupFix
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.quickfix.ReplaceObsoleteLabelSyntaxFix import org.jetbrains.kotlin.idea.quickfix.ReplaceObsoleteLabelSyntaxFix
@@ -99,7 +99,7 @@ class KotlinCleanupInspection : LocalInspectionTool(), CleanupLocalInspectionToo
} }
private fun Diagnostic.toCleanupFixes(): Collection<CleanupFix> { private fun Diagnostic.toCleanupFixes(): Collection<CleanupFix> {
return AbstractKotlinHighlightingPass.createQuickFixes(this).filterIsInstance<CleanupFix>() return AbstractKotlinHighlightVisitor.createQuickFixes(this).filterIsInstance<CleanupFix>()
} }
private class Wrapper(val intention: IntentionAction, file: KtFile) : IntentionWrapper(intention, file) { private class Wrapper(val intention: IntentionAction, file: KtFile) : IntentionWrapper(intention, file) {
@@ -89,12 +89,12 @@ abstract class AbstractKotlinHighlightWolfPassTest : KotlinLightCodeInsightFixtu
// TODO: [VD] HAS TO BE UNCOMMENTED with 211 // TODO: [VD] HAS TO BE UNCOMMENTED with 211
// val hasWolfErrors = hasWolfErrors(myFixture) // val hasWolfErrors = hasWolfErrors(myFixture)
// assertEquals(hasWolfErrors, wolf.isProblemFile(virtualFile) || wolf.hasSyntaxErrors(virtualFile)) // assertEquals(hasWolfErrors, wolf.isProblemFile(virtualFile) || wolf.hasSyntaxErrors(virtualFile))
// if (hasWolfErrors) { // if (hasWolfErrors && !initialWolfErrors) {
// TestCase.assertTrue(problemsAppeared > 0) // TestCase.assertTrue(problemsAppeared > 0)
// } else { // } else {
// assertEquals(0, problemsAppeared) // assertEquals(0, problemsAppeared)
// } // }
// assertEquals(if (initialWolfErrors) 1 else 0, problemsDisappeared) // assertEquals(0, problemsDisappeared)
} }
companion object { companion object {
@@ -5,8 +5,7 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.lang.annotation.AnnotationSession
import com.intellij.psi.PsiComment import com.intellij.psi.PsiComment
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
import org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension import org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension
@@ -33,15 +32,14 @@ abstract class AbstractDslHighlighterTest : KotlinLightCodeInsightFixtureTestCas
val styleIdByComment = commentText?.replace("//", "")?.trim()?.toInt()?.let { DslHighlighterExtension.externalKeyName(it) } val styleIdByComment = commentText?.replace("//", "")?.trim()?.toInt()?.let { DslHighlighterExtension.externalKeyName(it) }
val styleIdByCall = extension.highlightCall(element, call)?.externalName val styleIdByCall = extension.highlightCall(element, call)?.externalName
if (styleIdByCall != null && styleIdByCall == styleIdByComment) { if (styleIdByCall != null && styleIdByCall == styleIdByComment) {
val annotationHolder = AnnotationHolderImpl(AnnotationSession(psiFile)) val holder = HighlightInfoHolder(psiFile)
annotationHolder.runAnnotatorWithContext(file) { _, _ -> val checkers = AbstractKotlinHighlightVisitor.getAfterAnalysisVisitor(holder, bindingContext)
val checkers = AbstractKotlinHighlightingPass.getAfterAnalysisVisitor(annotationHolder, bindingContext) checkers.forEach { call.call.callElement.accept(it) }
checkers.forEach { call.call.callElement.accept(it) }
}
assertTrue( assertTrue(
"KotlinHighlightingPass did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}", "KotlinHighlightingPass did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}",
annotationHolder.any { (0 until holder.size()).map { holder[it] }.any {
it.textAttributes.externalName == styleIdByComment it.forcedTextAttributesKey.externalName == styleIdByComment
} }
) )
} else if (styleIdByCall != styleIdByComment) { } else if (styleIdByCall != styleIdByComment) {