diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/TrafficLightTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/TrafficLightTest.kt index fab89dd4cf34..4492c03d9626 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/TrafficLightTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/TrafficLightTest.kt @@ -1,11 +1,19 @@ -// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.daemon.impl import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase import com.intellij.ide.highlighter.JavaFileType +import com.intellij.ide.plugins.PluginManagerCore +import com.intellij.lang.LanguageAnnotators +import com.intellij.lang.LanguageExtensionPoint +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.openapi.application.readAction import com.intellij.openapi.editor.ex.EditorMarkupModel +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.util.application import kotlinx.coroutines.runBlocking import org.intellij.lang.annotations.Language @@ -41,11 +49,42 @@ class TrafficLightTest : DaemonAnalyzerTestCase() { ) } + fun `test error counter after adding and removing file level annotation`() { + class AnnotatorRegisteringFileLevelErrorIfEmptyFile : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + if (element is PsiFile && element.textLength == 0) { + holder.newAnnotation(HighlightSeverity.ERROR, "Empty file").fileLevel().create() + } + } + } + val annotator = AnnotatorRegisteringFileLevelErrorIfEmptyFile() + val keyedLazyInstance = LanguageExtensionPoint("JAVA", annotator.javaClass.name, PluginManagerCore.getPlugin(PluginManagerCore.CORE_ID)!!) + LanguageAnnotators.EP_NAME.point.registerExtension(keyedLazyInstance, testRootDisposable) + + doTrafficRendererTest( + listOf( + "class Main {}", // no error + "", // file level error is added by AnnotatorRegisteringFileLevelErrorIfEmptyFile + "class Main {}" // no error again + ), + listOf(HighlightSeverity.ERROR to 0), + ) + } + private fun doTrafficRendererTest( @Language("JAVA") text: String, vararg expectedSeverities: SeverityValue, ) { - configureByText(JavaFileType.INSTANCE, text) + doTrafficRendererTest(listOf(text), listOf(*expectedSeverities)) + } + + private fun doTrafficRendererTest( + fileTextSnapshots: List, + expectedSeverities: List, + ) { + require(fileTextSnapshots.isNotEmpty()) + + configureByText(JavaFileType.INSTANCE, fileTextSnapshots.first()) val editorMarkupModel = editor.markupModel as EditorMarkupModel @@ -53,6 +92,13 @@ class TrafficLightTest : DaemonAnalyzerTestCase() { doHighlighting() + fileTextSnapshots.drop(1).forEach { + application.runWriteAction { + editor.document.setText(it) + } + doHighlighting() + } + val trafficLightRenderer = editorMarkupModel.errorStripeRenderer as TrafficLightRenderer val status = runBlocking { readAction { diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdaterImpl.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdaterImpl.java index 8d1a08f59db2..42963132f016 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdaterImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfoUpdaterImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.multiverse.CodeInsightContext; @@ -1516,11 +1516,13 @@ public final class HighlightInfoUpdaterImpl extends HighlightInfoUpdater impleme if (toReuse != null && toReuse.isValid()) { highlighter = toReuse; BackgroundUpdateHighlightersUtil.associateInfoAndHighlighter(info, highlighter); + CodeInsightContextHighlightingUtil.installCodeInsightContext(highlighter, project, context); } else { highlighter = markupModel.addRangeHighlighterAndChangeAttributes(null, 0, document.getTextLength(), FILE_LEVEL_FAKE_LAYER, HighlighterTargetArea.EXACT_RANGE, false, ex -> { BackgroundUpdateHighlightersUtil.associateInfoAndHighlighter(info, ex); + CodeInsightContextHighlightingUtil.installCodeInsightContext(ex, project, context); }); } highlighter.setGreedyToLeft(true); @@ -1529,9 +1531,6 @@ public final class HighlightInfoUpdaterImpl extends HighlightInfoUpdater impleme // create a fake whole-file highlighter which will track the document size changes // and which will make possible to calculate correct `info.getActualEndOffset()` info.setGroup(group); - if (context != null) { - CodeInsightContextHighlightingUtil.installCodeInsightContext(highlighter, project, context); - } return highlighter; } } diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/multiverse/CodeInsightContextHighlightingUtil.kt b/platform/analysis-impl/src/com/intellij/codeInsight/multiverse/CodeInsightContextHighlightingUtil.kt index 06f8d391503d..d472b754fa40 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/multiverse/CodeInsightContextHighlightingUtil.kt +++ b/platform/analysis-impl/src/com/intellij/codeInsight/multiverse/CodeInsightContextHighlightingUtil.kt @@ -1,4 +1,4 @@ -// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. @file:ApiStatus.Experimental @file:JvmName("CodeInsightContextHighlightingUtil") @@ -10,7 +10,7 @@ import com.intellij.openapi.util.Key import org.jetbrains.annotations.ApiStatus @ApiStatus.Experimental -fun RangeHighlighter.installCodeInsightContext(project: Project, context: CodeInsightContext) { +fun RangeHighlighter.installCodeInsightContext(project: Project, context: CodeInsightContext?) { if (isSharedSourceSupportEnabled(project)) { putUserData(highlighterContextKey, context) }