diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightVisitor.kt similarity index 58% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightVisitor.kt index f8924edc46c..924ba3d2e76 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightVisitor.kt @@ -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? = 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 = 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() - val annotationByTextRange = mutableMapOf() + val highlightInfoByDiagnostic = mutableMapOf() + val highlightInfoByTextRange = mutableMapOf() // 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? = null, - annotationByTextRange: MutableMap? = null, + highlightInfoByDiagnostic: MutableMap? = null, + highlightInfoByTextRange: MutableMap? = 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) { - annotationByTextRange.values.forEach { annotation -> - annotation.quickFixes?.removeIf { - it.quickFix is CalculatingIntentionAction + private fun cleanUpCalculatingAnnotations(highlightInfoByTextRange: Map) { + highlightInfoByTextRange.values.forEach { annotation -> + annotation.unregisterQuickFix { + it is CalculatingIntentionAction } } } private fun annotateDiagnostics( + file: KtFile, element: PsiElement, - holder: AnnotationHolder, + holder: HighlightInfoHolder, diagnostics: List, - annotationByDiagnostic: MutableMap? = null, - annotationByTextRange: MutableMap? = null, + highlightInfoByDiagnostic: MutableMap? = null, + highlightInfoByTextRange: MutableMap? = 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, - annotationByDiagnostic: MutableMap + highlightInfoByDiagnostic: MutableMap ) { 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, - file: VirtualFile, - hasErrorElement: Boolean = true - ): List = - infos.filter { it.severity == HighlightSeverity.ERROR }.map { ProblemImpl(file, it, hasErrorElement) } - companion object { - fun createQuickFixes(diagnostic: Diagnostic): Collection = - createQuickFixes(listOfNotNull(diagnostic))[diagnostic] + private val UNRESOLVED_KEY = Key("KotlinHighlightVisitor.UNRESOLVED_KEY") - private val UNRESOLVED_KEY = Key("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) { + fun createQuickFixes(diagnostic: Diagnostic): Collection = + createQuickFixes(listOfNotNull(diagnostic))[diagnostic] + + fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null + + internal fun assertBelongsToTheSameElement(element: PsiElement, diagnostics: Collection) { assert(diagnostics.all { it.psiElement == element }) } fun annotateDiagnostics( file: KtFile, element: PsiElement, - holder: AnnotationHolder, + holder: HighlightInfoHolder, diagnostics: Collection, - annotationByDiagnostic: MutableMap? = null, - annotationByTextRange: MutableMap? = null, + highlightInfoByDiagnostic: MutableMap? = null, + highlightInfoByTextRange: MutableMap? = 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): MultiMap { val first = similarDiagnostics.minByOrNull { it.toString() } val factory = similarDiagnostics.first().getRealDiagnosticFactory() @@ -278,6 +305,7 @@ internal fun createQuickFixes(similarDiagnostics: Collection): 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 { } } } + diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt index a49166e7e7f..2e28e24c0da 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AfterAnalysisHighlightingVisitor.kt @@ -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") diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt index 0c15bd0e46e..473b8112498 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt @@ -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, - annotationBuilderByDiagnostic: MutableMap? = null, - annotationByTextRange: MutableMap?, + highlightInfoBuilderByDiagnostic: MutableMap? = null, + highlightInfoByTextRange: MutableMap?, fixesMap: MultiMap?, 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: 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)?.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 + } + } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt deleted file mode 100644 index ca1bba3a9e8..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt +++ /dev/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 - ) - } - } -} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt index 82467f68b1f..c98ad400b42 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt @@ -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, - annotationByDiagnostic: MutableMap?, - annotationByTextRange: MutableMap?, + highlightInfoByDiagnostic: MutableMap?, + highlightInfoByTextRange: MutableMap?, 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, - annotationByDiagnostic: MutableMap?, - annotationByTextRange: MutableMap?, + highlightInfoByDiagnostic: MutableMap?, + highlightInfoByTextRange: MutableMap?, 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, - annotationByDiagnostic: MutableMap + highlightInfoByDiagnostic: MutableMap ) = diagnostics.groupBy { it.factory } - .forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, annotationByDiagnostic) } + .forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, highlightInfoByDiagnostic) } private fun registerDiagnosticsSameFactoryQuickFixes( diagnostics: List, - annotationByDiagnostic: MutableMap + highlightInfoByDiagnostic: MutableMap ) { 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, data: AnnotationPresentationInfo, - annotationByDiagnostic: MutableMap?, - annotationByTextRange: MutableMap?, + highlightInfoByDiagnostic: MutableMap?, + highlightInfoByTextRange: MutableMap?, 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( diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/FunctionsHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/FunctionsHighlightingVisitor.kt index b80c136bff6..b706434c715 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/FunctionsHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/FunctionsHighlightingVisitor.kt @@ -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) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt index 0482489f441..bf52183a5a7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/PropertiesHighlightingVisitor.kt @@ -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) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt index 57497d914be..b2276c81390 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/TypeKindHighlightingVisitor.kt @@ -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) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt index 5778f16260c..779f6773aa6 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt @@ -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) { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt index e9e3c7d3dd6..1495c4e878c 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt @@ -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 { 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) { diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/DeclarationHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/DeclarationHighlightingVisitor.kt index c797ec0b695..9766cbb5df8 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/DeclarationHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/DeclarationHighlightingVisitor.kt @@ -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) } \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt index 4a378ce9e37..0b832c896f3 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt @@ -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 diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractAnnotationHolderHighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractAnnotationHolderHighlightingVisitor.kt new file mode 100644 index 00000000000..fc4e0f8b799 --- /dev/null +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractAnnotationHolderHighlightingVisitor.kt @@ -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() + } +} \ No newline at end of file diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightInfoHolderHighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightInfoHolderHighlightingVisitor.kt new file mode 100644 index 00000000000..a5b6596ac5f --- /dev/null +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightInfoHolderHighlightingVisitor.kt @@ -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) } + } +} \ No newline at end of file diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingVisitor.kt similarity index 68% rename from idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt rename to idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingVisitor.kt index 597a009daf7..e2c138dc970 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingVisitor.kt @@ -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) { diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt index e59e13c300d..65978ecb838 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt @@ -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 diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt index 4d3e3c34af5..d17a0c1cff2 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt @@ -56,5 +56,5 @@ class KotlinBeforeResolveHighlightingPass(file: KtFile, document: Document) : Ab } interface BeforeResolveHighlightingExtension { - fun createVisitor(holder: AnnotationHolder): HighlightingVisitor + fun createVisitor(holder: AnnotationHolder): AbstractHighlightingVisitor } \ No newline at end of file diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt index 6faae1309a9..186576e6483 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt @@ -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 - ) - } - } } } \ No newline at end of file diff --git a/idea/resources-descriptors/META-INF/plugin.xml b/idea/resources-descriptors/META-INF/plugin.xml index a1befba5ea8..94e94fe77e1 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml +++ b/idea/resources-descriptors/META-INF/plugin.xml @@ -134,10 +134,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + - - diff --git a/idea/resources-descriptors/META-INF/plugin.xml.201 b/idea/resources-descriptors/META-INF/plugin.xml.201 index 3f4d5a4777b..85fbc959b3f 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.201 +++ b/idea/resources-descriptors/META-INF/plugin.xml.201 @@ -134,10 +134,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + - - diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as41 b/idea/resources-descriptors/META-INF/plugin.xml.as41 index 1948bf388de..deac8769498 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as41 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as41 @@ -133,10 +133,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + - - diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as42 b/idea/resources-descriptors/META-INF/plugin.xml.as42 index ffb67ecd6fd..b3efe09b41a 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as42 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as42 @@ -114,10 +114,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + - - diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightVisitor.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightVisitor.kt new file mode 100644 index 00000000000..c03682fdab3 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightVisitor.kt @@ -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() +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt deleted file mode 100644 index 30920e08a2e..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt +++ /dev/null @@ -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 - ) - } - } -} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt index 31388e0274b..d6e6baa062d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt @@ -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 { - return AbstractKotlinHighlightingPass.createQuickFixes(this).filterIsInstance() + return AbstractKotlinHighlightVisitor.createQuickFixes(this).filterIsInstance() } private class Wrapper(val intention: IntentionAction, file: KtFile) : IntentionWrapper(intention, file) { diff --git a/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightWolfPassTest.kt b/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightWolfPassTest.kt index d635c678b83..a1e6ba13b4b 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightWolfPassTest.kt +++ b/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightWolfPassTest.kt @@ -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 { diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt index 0487de53f2d..2766f930ddc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt @@ -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) {