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
import com.intellij.codeInsight.daemon.impl.Divider
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.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.editor.Document
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
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.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.containers.MultiMap
import org.jetbrains.kotlin.asJava.getJvmSignatureDiagnostics
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.rendering.RenderingContext
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
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.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.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.types.KotlinType
import java.lang.reflect.*
import java.util.*
import kotlin.collections.ArrayList
abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document) :
AbstractBindingContextAwareHighlightingPassBase(file, document) {
override val annotator: Annotator
get() = KotlinAfterAnalysisAnnotator()
abstract class AbstractKotlinHighlightVisitor : HighlightVisitor {
private var afterAnalysisVisitor: Array<AfterAnalysisHighlightingVisitor>? = null
private inner class KotlinAfterAnalysisAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
val bindingContext = bindingContext()
getAfterAnalysisVisitor(holder, bindingContext).forEach { visitor -> element.accept(visitor) }
override fun suitableForFile(file: PsiFile) = file is KtFile
override fun visit(element: PsiElement) {
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() {
super.doApplyInformationToEditor()
reportErrorsToWolf()
}
override fun buildBindingContext(holder: AnnotationHolder): BindingContext {
private fun analyze(file: KtFile, holder: HighlightInfoHolder) {
val dividedElements: List<Divider.DividedElements> = ArrayList()
Divider.divideInsideAndOutsideAllRoots(
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
// don't create quick fixes as it could require some resolve
val annotationByDiagnostic = mutableMapOf<Diagnostic, Annotation>()
val annotationByTextRange = mutableMapOf<TextRange, Annotation>()
val highlightInfoByDiagnostic = mutableMapOf<Diagnostic, HighlightInfo>()
val highlightInfoByTextRange = mutableMapOf<TextRange, HighlightInfo>()
// render of on-fly diagnostics with descriptors could lead to recursion
fun checkIfDescriptor(candidate: Any?): Boolean =
@@ -82,61 +84,84 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
file.analyzeWithAllCompilerChecks({
val element = it.psiElement
if (element in elements &&
it !in annotationByDiagnostic &&
it !in highlightInfoByDiagnostic &&
!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!
val bindingContext = analysisResult.bindingContext
cleanUpCalculatingAnnotations(annotationByTextRange)
// 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()
afterAnalysisVisitor = getAfterAnalysisVisitor(holder, bindingContext)
if (diagnostics.isNotEmpty()) {
// annotate diagnostics those were not possible to render on fly
diagnostics.asSequence().filterNot { it in annotationByDiagnostic }.forEach {
annotateDiagnostic(it.psiElement, holder, it, annotationByDiagnostic, calculatingInProgress = false)
}
// apply quick fixes for all diagnostics grouping by element
diagnostics.groupBy(Diagnostic::psiElement).forEach {
annotateQuickFixes(it.key, it.value, annotationByDiagnostic)
}
cleanUpCalculatingAnnotations(highlightInfoByTextRange)
annotateDuplicateJvmSignature(file, holder, bindingContext.diagnostics)
for (diagnostic in bindingContext.diagnostics) {
val psiElement = diagnostic.psiElement
if (psiElement !in elements) continue
// 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(
file: KtFile,
element: PsiElement,
holder: AnnotationHolder,
holder: HighlightInfoHolder,
diagnostic: Diagnostic,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>? = null,
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>? = null,
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>) {
annotationByTextRange.values.forEach { annotation ->
annotation.quickFixes?.removeIf {
it.quickFix is CalculatingIntentionAction
private fun cleanUpCalculatingAnnotations(highlightInfoByTextRange: Map<TextRange, HighlightInfo>) {
highlightInfoByTextRange.values.forEach { annotation ->
annotation.unregisterQuickFix {
it is CalculatingIntentionAction
}
}
}
private fun annotateDiagnostics(
file: KtFile,
element: PsiElement,
holder: AnnotationHolder,
holder: HighlightInfoHolder,
diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>? = null,
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>? = null,
noFixes: Boolean = false,
calculatingInProgress: Boolean = false
) = annotateDiagnostics(
file, element, holder, diagnostics, annotationByDiagnostic, annotationByTextRange,
file, element, holder, diagnostics, highlightInfoByDiagnostic, highlightInfoByTextRange,
::shouldSuppressUnusedParameter,
noFixes = noFixes, calculatingInProgress = calculatingInProgress
)
@@ -145,9 +170,10 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
* [diagnostics] has to belong to the same element
*/
private fun annotateQuickFixes(
file: KtFile,
element: PsiElement,
diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>
) {
if (diagnostics.isEmpty()) return
@@ -161,63 +187,64 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
if (shouldHighlightErrors) {
ElementAnnotator(element) { param ->
shouldSuppressUnusedParameter(param)
}.registerDiagnosticsQuickFixes(diagnostics, annotationByDiagnostic)
}.registerDiagnosticsQuickFixes(diagnostics, highlightInfoByDiagnostic)
}
}
protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false
private fun reportErrorsToWolf() {
if (!file.viewProvider.isPhysical) return // e.g. errors in evaluate expression
val project: Project = file.project
if (!PsiManager.getInstance(project).isInProject(file)) return // do not report problems in libraries
val file: VirtualFile = file.virtualFile ?: return
private inner class DuplicateJvmSignatureAnnotator(
private val file: KtFile,
private val holder: HighlightInfoHolder,
private val otherDiagnostics: Diagnostics,
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 problemFile = wolf.isProblemFile(file)
val diagnostics = getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope) ?: return
// do nothing if file has already problems
if (hasSyntaxErrors || problemFile) return
val diagnosticsForElement = diagnostics.forElement(element).toSet()
val problems = convertToProblems(infos, file)
wolf.reportProblems(file, problems)
annotateDiagnostics(file, element, holder, diagnosticsForElement)
}
}
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 {
fun createQuickFixes(diagnostic: Diagnostic): Collection<IntentionAction> =
createQuickFixes(listOfNotNull(diagnostic))[diagnostic]
private val UNRESOLVED_KEY = Key<Unit>("KotlinHighlightVisitor.UNRESOLVED_KEY")
private val UNRESOLVED_KEY = Key<Unit>("KotlinHighlightingPass.UNRESOLVED_KEY")
fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null
fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf(
fun getAfterAnalysisVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) = arrayOf(
PropertiesHighlightingVisitor(holder, bindingContext),
FunctionsHighlightingVisitor(holder, bindingContext),
VariablesHighlightingVisitor(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 })
}
fun annotateDiagnostics(
file: KtFile,
element: PsiElement,
holder: AnnotationHolder,
holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>? = null,
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>? = null,
shouldSuppressUnusedParameter: (KtParameter) -> Boolean = { false },
noFixes: Boolean = false,
calculatingInProgress: Boolean = false
@@ -241,16 +268,16 @@ abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document)
shouldSuppressUnusedParameter(param)
}
elementAnnotator.registerDiagnosticsAnnotations(
holder, diagnostics, annotationByDiagnostic,
annotationByTextRange,
holder, diagnostics, highlightInfoByDiagnostic,
highlightInfoByTextRange,
noFixes = noFixes, calculatingInProgress = calculatingInProgress
)
}
}
}
}
internal fun createQuickFixes(similarDiagnostics: Collection<Diagnostic>): MultiMap<Diagnostic, IntentionAction> {
val first = similarDiagnostics.minByOrNull { it.toString() }
val factory = similarDiagnostics.first().getRealDiagnosticFactory()
@@ -278,6 +305,7 @@ internal fun createQuickFixes(similarDiagnostics: Collection<Diagnostic>): Multi
return actions
}
private fun Diagnostic.getRealDiagnosticFactory(): DiagnosticFactory<*> =
when (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
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.extensions.Extensions
import com.intellij.psi.PsiElement
@@ -28,8 +28,8 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
abstract class AfterAnalysisHighlightingVisitor protected constructor(
holder: AnnotationHolder, protected var bindingContext: BindingContext
) : HighlightingVisitor(holder) {
holder: HighlightInfoHolder, protected var bindingContext: BindingContext
) : AbstractHighlightInfoHolderHighlightingVisitor(holder) {
protected fun attributeKeyForDeclarationFromExtensions(element: PsiElement, descriptor: DeclarationDescriptor): TextAttributesKey? {
@Suppress("DEPRECATION")
@@ -5,12 +5,14 @@
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.IntentionAction
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.lang.annotation.Annotation
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.editor.colors.CodeInsightColors
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange
import com.intellij.util.containers.MultiMap
@@ -30,23 +32,24 @@ class AnnotationPresentationInfo(
) {
fun processDiagnostics(
holder: AnnotationHolder,
holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>,
annotationBuilderByDiagnostic: MutableMap<Diagnostic, Annotation>? = null,
annotationByTextRange: MutableMap<TextRange, Annotation>?,
highlightInfoBuilderByDiagnostic: MutableMap<Diagnostic, HighlightInfo>? = null,
highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
fixesMap: MultiMap<Diagnostic, IntentionAction>?,
calculatingInProgress: Boolean
) {
for (range in ranges) {
for (diagnostic in diagnostics) {
create(diagnostic, range, holder) { annotation ->
annotationBuilderByDiagnostic?.put(diagnostic, annotation)
create(diagnostic, range) { info ->
holder.add(info)
highlightInfoBuilderByDiagnostic?.put(diagnostic, info)
if (fixesMap != null) {
applyFixes(fixesMap, diagnostic, annotation)
applyFixes(fixesMap, diagnostic, info)
}
if (calculatingInProgress && annotationByTextRange?.containsKey(range) == false) {
annotationByTextRange[range] = annotation
annotation.registerFix(CalculatingIntentionAction(), range)
if (calculatingInProgress && highlightInfoByTextRange?.containsKey(range) == false) {
highlightInfoByTextRange[range] = info
QuickFixAction.registerQuickFixAction(info, CalculatingIntentionAction())
}
}
}
@@ -56,55 +59,36 @@ class AnnotationPresentationInfo(
internal fun applyFixes(
fixesMap: MultiMap<Diagnostic, IntentionAction>,
diagnostic: Diagnostic,
annotation: Annotation
info: HighlightInfo
) {
val fixes = fixesMap[diagnostic]
val textRange = TextRange(annotation.startOffset, annotation.endOffset)
fixes.forEach {
when (it) {
is KotlinUniversalQuickFix -> {
annotation.registerBatchFix(it, textRange, null)
annotation.registerFix(it, textRange)
}
is IntentionAction -> {
annotation.registerFix(it, textRange)
}
}
fixes.filter { it is IntentionAction || it is KotlinUniversalQuickFix }.forEach {
QuickFixAction.registerQuickFixAction(info, it)
}
if (diagnostic.severity == Severity.WARNING) {
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()
annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name), textRange)
QuickFixAction.registerQuickFixAction(info, EmptyIntentionAction(diagnostic.factory.name))
}
}
}
private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (Annotation) -> 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
}
private fun create(diagnostic: Diagnostic, range: TextRange, consumer: (HighlightInfo) -> Unit) {
val message = nonDefaultMessage ?: getDefaultMessage(diagnostic)
holder.newAnnotation(severity, message)
HighlightInfo
.newHighlightInfo(toHighlightInfoType(highlightType, diagnostic.severity))
.range(range)
.tooltip(getMessage(diagnostic))
.also { builder -> highlightType?.let { builder.highlightType(it) } }
.also { builder -> textAttributes?.let { builder.textAttributes(it) } }
.description(message)
.escapedToolTip(getMessage(diagnostic))
.also { builder -> textAttributes?.let(builder::textAttributes) ?: convertSeverityTextAttributes(highlightType, diagnostic.severity)?.let(builder::textAttributes) }
.also {
if (diagnostic.severity == Severity.WARNING) {
it.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory))
}
}
.create()
@Suppress("UNCHECKED_CAST")
(holder as? List<Annotation>)?.last()?.let(consumer::invoke)
.createUnconditionally()
.also(consumer)
}
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
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
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.diagnostic.ControlFlowException
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.colors.CodeInsightColors
@@ -31,10 +32,10 @@ internal class ElementAnnotator(
private val shouldSuppressUnusedParameter: (KtParameter) -> Boolean
) {
fun registerDiagnosticsAnnotations(
holder: AnnotationHolder,
holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>?,
annotationByTextRange: MutableMap<TextRange, Annotation>?,
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>?,
highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
noFixes: Boolean,
calculatingInProgress: Boolean
) = diagnostics.groupBy { it.factory }
@@ -42,18 +43,18 @@ internal class ElementAnnotator(
registerSameFactoryDiagnosticsAnnotations(
holder,
it.value,
annotationByDiagnostic,
annotationByTextRange,
highlightInfoByDiagnostic,
highlightInfoByTextRange,
noFixes,
calculatingInProgress
)
}
private fun registerSameFactoryDiagnosticsAnnotations(
holder: AnnotationHolder,
holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>?,
annotationByTextRange: MutableMap<TextRange, Annotation>?,
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>?,
highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
noFixes: Boolean,
calculatingInProgress: Boolean
) {
@@ -62,8 +63,8 @@ internal class ElementAnnotator(
holder,
diagnostics,
presentationInfo,
annotationByDiagnostic,
annotationByTextRange,
highlightInfoByDiagnostic,
highlightInfoByTextRange,
noFixes,
calculatingInProgress
)
@@ -71,21 +72,21 @@ internal class ElementAnnotator(
fun registerDiagnosticsQuickFixes(
diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>
) = diagnostics.groupBy { it.factory }
.forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, annotationByDiagnostic) }
.forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, highlightInfoByDiagnostic) }
private fun registerDiagnosticsSameFactoryQuickFixes(
diagnostics: List<Diagnostic>,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>
) {
val presentationInfo = presentationInfo(diagnostics) ?: return
val fixesMap = createFixesMap(diagnostics) ?: return
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(
holder: AnnotationHolder,
holder: HighlightInfoHolder,
diagnostics: Collection<Diagnostic>,
data: AnnotationPresentationInfo,
annotationByDiagnostic: MutableMap<Diagnostic, Annotation>?,
annotationByTextRange: MutableMap<TextRange, Annotation>?,
highlightInfoByDiagnostic: MutableMap<Diagnostic, HighlightInfo>?,
highlightInfoByTextRange: MutableMap<TextRange, HighlightInfo>?,
noFixes: Boolean,
calculatingInProgress: Boolean
) {
val fixesMap =
createFixesMap(diagnostics, noFixes)
data.processDiagnostics(holder, diagnostics, annotationByDiagnostic, annotationByTextRange, fixesMap, calculatingInProgress)
data.processDiagnostics(holder, diagnostics, highlightInfoByDiagnostic, highlightInfoByTextRange, fixesMap, calculatingInProgress)
}
private fun createFixesMap(
@@ -5,7 +5,7 @@
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.psi.PsiElement
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.utils.addToStdlib.firstNotNullResult
internal class FunctionsHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) :
internal class FunctionsHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitBinaryExpression(expression: KtBinaryExpression) {
@@ -5,7 +5,7 @@
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.extensions.Extensions
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.utils.addToStdlib.firstNotNullResult
internal class PropertiesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) :
internal class PropertiesHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
@@ -5,7 +5,7 @@
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.util.TextRange
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.util.FakeCallableDescriptorForObject
internal class TypeKindHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) :
internal class TypeKindHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
@@ -5,7 +5,7 @@
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.PsiNameIdentifierOwner
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.types.expressions.CaptureKind
internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) :
internal class VariablesHighlightingVisitor(holder: HighlightInfoHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
@@ -9,8 +9,7 @@ import com.intellij.codeInsight.completion.PrefixMatcher
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.progress.ProgressManager
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass
import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightVisitor
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.psi.KtCallExpression
@@ -29,7 +28,7 @@ class FromUnresolvedNamesCompletion(
scope.forEachDescendantOfType<KtNameReferenceExpression> { refExpr ->
ProgressManager.checkCanceled()
if (AbstractKotlinHighlightingPass.wasUnresolved(refExpr)) {
if (AbstractKotlinHighlightVisitor.wasUnresolved(refExpr)) {
val callTypeAndReceiver = CallTypeAndReceiver.detect(refExpr)
if (callTypeAndReceiver.receiver != null) return@forEachDescendantOfType
if (sampleDescriptor != null) {
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
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) {
highlightNamedDeclaration(typeAlias, Colors.TYPE_ALIAS)
super.visitTypeAlias(typeAlias)
@@ -56,6 +56,6 @@ internal class DeclarationHighlightingVisitor(holder: AnnotationHolder) : Highli
}
class DeclarationHighlightingExtension : BeforeResolveHighlightingExtension {
override fun createVisitor(holder: AnnotationHolder): HighlightingVisitor =
override fun createVisitor(holder: AnnotationHolder): AbstractHighlightingVisitor =
DeclarationHighlightingVisitor(holder)
}
@@ -9,12 +9,12 @@ import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange
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(
protected val analysisSession: KtAnalysisSession,
protected val holder: AnnotationHolder
) : HighlightingVisitor(holder) {
) : AbstractAnnotationHolderHighlightingVisitor(holder) {
override fun createInfoAnnotation(textRange: TextRange, message: String?, textAttributes: TextAttributesKey?) {
// 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
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
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtVisitorVoid
abstract class HighlightingVisitor protected constructor(
private val holder: AnnotationHolder
) : KtVisitorVoid() {
abstract class AbstractHighlightingVisitor : KtVisitorVoid() {
protected fun createInfoAnnotation(element: PsiElement, message: String? = null, textAttributes: TextAttributesKey) {
createInfoAnnotation(element.textRange, message, textAttributes)
@@ -24,17 +20,7 @@ abstract class HighlightingVisitor protected constructor(
protected fun createInfoAnnotation(element: PsiElement, message: String? = null) =
createInfoAnnotation(element.textRange, message)
protected open 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 abstract fun createInfoAnnotation(textRange: TextRange, message: String? = null, textAttributes: TextAttributesKey? = null)
protected fun highlightName(element: PsiElement, attributesKey: TextAttributesKey, message: String? = null) {
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.startOffset
internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : HighlightingVisitor(holder) {
internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : AbstractAnnotationHolderHighlightingVisitor(holder) {
override fun visitElement(element: PsiElement) {
val elementType = element.node.elementType
@@ -56,5 +56,5 @@ class KotlinBeforeResolveHighlightingPass(file: KtFile, document: Document) : Ab
}
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.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressIndicator
@@ -15,7 +16,7 @@ import com.intellij.psi.PsiFile
import com.intellij.testFramework.RunAll
import com.intellij.util.ThrowableRunnable
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.runAndMeasure
import org.jetbrains.kotlin.idea.perf.util.Metric
@@ -379,8 +380,8 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
private fun replaceWithCustomHighlighter() {
org.jetbrains.kotlin.idea.testFramework.replaceWithCustomHighlighter(
testRootDisposable,
KotlinHighlightingPass.Registrar::class.java.name,
TestKotlinHighlightingPass.Registrar::class.java.name
KotlinHighlightVisitor::class.java.name,
TestKotlinHighlightVisitor::class.java.name
)
}
@@ -434,38 +435,21 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
}
class TestKotlinHighlightingPass(file: KtFile, document: Document) : KotlinHighlightingPass(file, document) {
override fun doCollectInformation(progress: ProgressIndicator) {
annotationCallback {
val nowNs = System.nanoTime()
diagnosticTimer.addAndGet(nowNs)
resetAnnotationCallback()
}
class TestKotlinHighlightVisitor : KotlinHighlightVisitor() {
override fun analyze(psiFile: PsiFile, updateWholeFile: Boolean, holder: HighlightInfoHolder, action: Runnable): Boolean {
// TODO:
//annotationCallback {
// val nowNs = System.nanoTime()
// diagnosticTimer.addAndGet(nowNs)
// resetAnnotationCallback()
//}
try {
super.doCollectInformation(progress)
return super.analyze(psiFile, updateWholeFile, holder, action)
} finally {
resetAnnotationCallback()
//resetAnnotationCallback()
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.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.KotlinHighlightingPass$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.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.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.KotlinHighlightingPass$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.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.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.KotlinHighlightingPass$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.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.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.KotlinHighlightingPass$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.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.idea.KotlinBundle
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.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.quickfix.ReplaceObsoleteLabelSyntaxFix
@@ -99,7 +99,7 @@ class KotlinCleanupInspection : LocalInspectionTool(), CleanupLocalInspectionToo
}
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) {
@@ -89,12 +89,12 @@ abstract class AbstractKotlinHighlightWolfPassTest : KotlinLightCodeInsightFixtu
// TODO: [VD] HAS TO BE UNCOMMENTED with 211
// val hasWolfErrors = hasWolfErrors(myFixture)
// assertEquals(hasWolfErrors, wolf.isProblemFile(virtualFile) || wolf.hasSyntaxErrors(virtualFile))
// if (hasWolfErrors) {
// if (hasWolfErrors && !initialWolfErrors) {
// TestCase.assertTrue(problemsAppeared > 0)
// } else {
// assertEquals(0, problemsAppeared)
// }
// assertEquals(if (initialWolfErrors) 1 else 0, problemsDisappeared)
// assertEquals(0, problemsDisappeared)
}
companion object {
@@ -5,8 +5,7 @@
package org.jetbrains.kotlin.idea.highlighter
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl
import com.intellij.lang.annotation.AnnotationSession
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder
import com.intellij.psi.PsiComment
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
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 styleIdByCall = extension.highlightCall(element, call)?.externalName
if (styleIdByCall != null && styleIdByCall == styleIdByComment) {
val annotationHolder = AnnotationHolderImpl(AnnotationSession(psiFile))
annotationHolder.runAnnotatorWithContext(file) { _, _ ->
val checkers = AbstractKotlinHighlightingPass.getAfterAnalysisVisitor(annotationHolder, bindingContext)
checkers.forEach { call.call.callElement.accept(it) }
}
val holder = HighlightInfoHolder(psiFile)
val checkers = AbstractKotlinHighlightVisitor.getAfterAnalysisVisitor(holder, bindingContext)
checkers.forEach { call.call.callElement.accept(it) }
assertTrue(
"KotlinHighlightingPass did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}",
annotationHolder.any {
it.textAttributes.externalName == styleIdByComment
(0 until holder.size()).map { holder[it] }.any {
it.forcedTextAttributesKey.externalName == styleIdByComment
}
)
} else if (styleIdByCall != styleIdByComment) {