IJPL-161270 Semantic highlighting is still visible after disabling

GitOrigin-RevId: 0af6e1899921ffaf613240ce0865d13d607d86c5
This commit is contained in:
Alexey Kudravtsev
2024-09-02 14:10:21 +02:00
committed by intellij-monorepo-bot
parent 7e7dc37ecf
commit 121f917f61
5 changed files with 61 additions and 26 deletions

View File

@@ -1,6 +1,7 @@
// Copyright 2000-2024 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.codeHighlighting.RainbowHighlighter;
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightInfoHolder;
@@ -580,4 +581,22 @@ public class DaemonHighlightVisitorRespondToChangesTest extends DaemonAnalyzerTe
assertOneElement(ContainerUtil.filter(doHighlighting(HighlightSeverity.INFORMATION), h -> h.type.equals(HighlightInfoType.TODO)));
}
}
public void testHighlightingVisitorDisabledAtSomePointEgSemanticHighlightingBeingDisabledMustRemoveAllHighlightersOfOutdatedVisitors() {
@Language("JAVA")
String text = """
class X {
void foo(int wwwwwwwwwwwwwwwww) {
}
}
""";
configureByText(JavaFileType.INSTANCE, text);
assertEmpty(ContainerUtil.filter(doHighlighting(), info -> info.type == RainbowHighlighter.RAINBOW_ELEMENT));
CodeInsightTestFixtureImpl.runWithRainbowEnabled(true, () -> {
myDaemonCodeAnalyzer.restart();
assertNotEmpty(ContainerUtil.filter(doHighlighting(), info -> info.type == RainbowHighlighter.RAINBOW_ELEMENT));
});
myDaemonCodeAnalyzer.restart();
assertEmpty(ContainerUtil.filter(doHighlighting(), info -> info.type == RainbowHighlighter.RAINBOW_ELEMENT));
}
}

View File

@@ -40,6 +40,7 @@ import org.jetbrains.annotations.TestOnly;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -180,6 +181,11 @@ sealed class GeneralHighlightingPass extends ProgressableTextEditorHighlightingP
}
}
}
if (myHighlightInfoUpdater instanceof HighlightInfoUpdaterImpl impl) {
List<? extends Class<? extends HighlightVisitor>> liveVisitorClasses = ContainerUtil.map(filteredVisitors, v -> v.getClass());
BiPredicate<? super Object, ? super PsiFile> keepToolIdPredicate = (toolId, __) -> !HighlightInfoUpdaterImpl.isHighlightVisitorToolId(toolId) || liveVisitorClasses.contains(toolId);
impl.removeHighlightsForObsoleteTools(getHighlightingSession(), List.of(), keepToolIdPredicate);
}
boolean success = collectHighlights(allInsideElements, allInsideRanges, allOutsideElements, allOutsideRanges, filteredVisitors,
forceHighlightParents, (toolId, psiElement, newInfos) -> {
myHighlightInfoUpdater.psiElementVisited(toolId, psiElement, newInfos, getDocument(), getFile(), myProject, getHighlightingSession(), invalidPsiRecycler);

View File

@@ -56,6 +56,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -124,7 +125,8 @@ final class HighlightInfoUpdaterImpl extends HighlightInfoUpdater implements Dis
return getData(psiFile, hostDocument);
}
private static @NotNull Map<Object, ToolHighlights> getData(@NotNull PsiFile psiFile, @NotNull Document hostDocument) {
@NotNull
private static Map<Object, ToolHighlights> getData(@NotNull PsiFile psiFile, @NotNull Document hostDocument) {
Map<PsiFile, Map<Object, ToolHighlights>> map = getOrCreateHostMap(hostDocument);
Map<Object, ToolHighlights> result = map.get(psiFile);
if (result == null) {
@@ -133,7 +135,8 @@ final class HighlightInfoUpdaterImpl extends HighlightInfoUpdater implements Dis
return result;
}
private static @NotNull Map<PsiFile, Map<Object, ToolHighlights>> getOrCreateHostMap(@NotNull Document hostDocument) {
@NotNull
private static Map<PsiFile, Map<Object, ToolHighlights>> getOrCreateHostMap(@NotNull Document hostDocument) {
Map<PsiFile, Map<Object, ToolHighlights>> map = hostDocument.getUserData(VISITED_PSI_ELEMENTS);
if (map == null) {
map = ((UserDataHolderEx)hostDocument).putUserDataIfAbsent(VISITED_PSI_ELEMENTS, CollectionFactory.createConcurrentSoftMap((__, oldMap) -> {
@@ -478,28 +481,20 @@ final class HighlightInfoUpdaterImpl extends HighlightInfoUpdater implements Dis
}
// remove all highlight infos from `data` generated by tools absent in 'actualToolsRun'
synchronized void removeHighlightsForObsoleteTools(@NotNull PsiFile containingFile,
@NotNull Document hostDocument,
synchronized void removeHighlightsForObsoleteTools(@NotNull HighlightingSession highlightingSession,
@NotNull List<? extends PsiFile> injectedFragments,
@NotNull Set<? extends Pair<Object, PsiFile>> actualToolsRun,
@NotNull HighlightingSession highlightingSession,
@NotNull Set<String> inactiveSmartOnlyToolIds) {
for (PsiFile psiFile: ContainerUtil.append(injectedFragments, containingFile)) {
getData(psiFile, hostDocument).entrySet().removeIf(entry -> {
@NotNull BiPredicate<? super Object, ? super PsiFile> keepToolIdPredicate) {
for (PsiFile psiFile: ContainerUtil.append(injectedFragments, highlightingSession.getPsiFile())) {
Map<Object, ToolHighlights> data = getData(psiFile, highlightingSession.getDocument());
data.entrySet().removeIf(entry -> {
Object toolId = entry.getKey();
if (UNKNOWN_ID.equals(toolId)) {
return false;
}
if (keepToolIdPredicate.test(toolId, psiFile)) {
return false;
}
ToolHighlights toolHighlights = entry.getValue();
if (UNKNOWN_ID.equals(toolId) || !isInspectionToolId(toolId)) {
return false;
}
if (actualToolsRun.contains(Pair.create(toolId, psiFile))) {
return false;
}
if (inactiveSmartOnlyToolIds.contains(toolId)) {
// keep highlights from smart-only inspections in dumb mode
return false;
}
for (List<? extends HighlightInfo> highlights : toolHighlights.elementHighlights.values()) {
for (HighlightInfo info : highlights) {
RangeHighlighterEx highlighter = info.highlighter;

View File

@@ -721,9 +721,7 @@ public final class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx
@Override
public void settingsChanged() {
if (mySettings.isCodeHighlightingChanged(myLastSettings)) {
restart();
}
restart();
myLastSettings = ((DaemonCodeAnalyzerSettingsImpl)mySettings).clone();
}

View File

@@ -50,6 +50,7 @@ import org.jetbrains.annotations.TestOnly;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -165,8 +166,24 @@ final class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass
}
if (myHighlightInfoUpdater instanceof HighlightInfoUpdaterImpl impl) {
Set<Pair<Object, PsiFile>> pairs = ContainerUtil.map2Set(result.resultContexts, context -> Pair.create(context.tool().getShortName(), context.psiFile()));
impl.removeHighlightsForObsoleteTools(getFile(), getDocument(), result.injectedFragments, pairs, getHighlightingSession(), dumbToolWrapperCondition.getInactiveToolWrapperIds());
Set<Pair<Object, PsiFile>> actualToolsRun = ContainerUtil.map2Set(result.resultContexts, context -> Pair.create(context.tool().getShortName(), context.psiFile()));
Set<String> inactiveSmartOnlyToolIds = dumbToolWrapperCondition.getInactiveToolWrapperIds();
BiPredicate<? super Object, ? super PsiFile> keepToolIdPredicate = (toolId, psiFile) -> {
if (!HighlightInfoUpdaterImpl.isInspectionToolId(toolId)) {
return true;
}
if (actualToolsRun.contains(Pair.create(toolId, psiFile))) {
return true;
}
if (inactiveSmartOnlyToolIds.contains(toolId)) {
// keep highlights from smart-only inspections in dumb mode
return true;
}
return false;
};
impl.removeHighlightsForObsoleteTools(getHighlightingSession(), result.injectedFragments, keepToolIdPredicate);
impl.removeWarningsInsideErrors(result.injectedFragments, getDocument(), getHighlightingSession()); // must be the last
}
}