void (@NotNull List<? extends HighlightInfo> infos, @NotNull TextRange restrictedRange, @NotNull TextRange priorityRange, int group, @NotNull HighlightingSession session) { ApplicationManager.getApplication().assertIsNonDispatchThread(); ApplicationManager.getApplication().assertReadAccessAllowed(); PsiFile psiFile = session.getPsiFile(); Project project = session.getProject(); List<HighlightInfo> filteredInfos = UpdateHighlightersUtil.HighlightInfoPostFilters.applyPostFilter(project, infos); Document document = session.getDocument(); MarkupModel markup = DocumentMarkupModel.forDocument(document, project, true); SeverityRegistrar severityRegistrar = SeverityRegistrar.getSeverityRegistrar(project); HighlightersRecycler toReuse = new HighlightersRecycler(); ContainerUtil.quickSort(filteredInfos, UpdateHighlightersUtil.BY_ACTUAL_START_OFFSET_NO_DUPS); Set<HighlightInfo> infoSet = new HashSet<>(filteredInfos); Processor<HighlightInfo> processor = info -> { if (info.getGroup() == group) { RangeHighlighterEx highlighter = info.getHighlighter(); int hiStart = highlighter.getStartOffset(); int hiEnd = highlighter.getEndOffset(); if (!info.isFromInjection() && hiEnd < document.getTextLength() && !restrictedRange.contains(highlighter) && hiEnd != 0) { return true; // injections are oblivious to restricting range } boolean toRemove = infoSet.contains(info) || !priorityRange.containsRange(hiStart, hiEnd) && (hiEnd != document.getTextLength() || priorityRange.getEndOffset() != document.getTextLength()); if (toRemove) { toReuse.recycleHighlighter(highlighter); } } return true; }; Long2ObjectMap<RangeMarker> range2markerCache = new Long2ObjectOpenHashMap<>(10); boolean[] changed = {false}; SweepProcessor.Generator<HighlightInfo> generator = proc -> ContainerUtil.process(filteredInfos, proc); List<HighlightInfo> fileLevelHighlights = new ArrayList<>(); List<HighlightInfo> infosToCreateHighlightersFor = new ArrayList<>(filteredInfos.size()); try { DaemonCodeAnalyzerEx.processHighlightsOverlappingOutside(document, project, priorityRange.getStartOffset(), priorityRange.getEndOffset(), processor); SweepProcessor.sweep(generator, (offset, info, atStart, overlappingIntervals) -> { if (!atStart) return true; if (!info.isFromInjection() && info.getEndOffset() < document.getTextLength() && !restrictedRange.contains(info)) { return true; // injections are oblivious to restricting range } if (info.isFileLevelAnnotation()) { fileLevelHighlights.add(info); changed[0] = true; return true; } if (UpdateHighlightersUtil.isWarningCoveredByError(info, severityRegistrar, overlappingIntervals)) { return true; } if (info.getStartOffset() < priorityRange.getStartOffset() || info.getEndOffset() > priorityRange.getEndOffset()) { // have to create RangeHighlighter later, to avoid exposing them to the markup model immediately, // thus messing the HighlightInfo.getStartOffset() leading to "sweep generator supplied infos in a wrong order" exception infosToCreateHighlightersFor.add(info); changed[0] = true; } return true; }); for (HighlightInfo info : infosToCreateHighlightersFor) { createOrReuseHighlighterFor(info, session.getColorsScheme(), document, group, psiFile, (MarkupModelEx)markup, toReuse, range2markerCache, severityRegistrar); } boolean shouldClean = restrictedRange.getStartOffset() == 0 && restrictedRange.getEndOffset() == document.getTextLength(); session.updateFileLevelHighlights(fileLevelHighlights, group, shouldClean); changed[0] |= UpdateHighlightersUtil.incinerateObsoleteHighlighters(toReuse, session); } finally { toReuse.releaseHighlighters(); } if (changed[0]) { UpdateHighlightersUtil.clearWhiteSpaceOptimizationFlag(document); } }