use std::fmt;
use rustc_hash::{FxHashMap, FxHashSet};
use line_index::LineIndex;
use rowan::TextRange;
use crate::{Ignore, Rule, ignore::IgnoreKind};
pub(crate) struct IgnoreIndex {
line_to_ignored: FxHashMap<u32, FxHashSet<Rule>>,
file_ignored: FxHashSet<Rule>,
ignore_all: bool,
line_index: LineIndex,
}
impl fmt::Debug for IgnoreIndex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "IgnoreIndex:")?;
let mut keys = self.line_to_ignored.keys().collect::<Vec<_>>();
keys.sort();
for line in keys {
if let Some(set) = &self.line_to_ignored.get(line) {
writeln!(f, " {line}: {set:?}")?;
}
}
Ok(())
}
}
impl IgnoreIndex {
pub(crate) fn new(text: &str, ignores: &[Ignore]) -> Self {
let line_index = LineIndex::new(text);
let mut line_to_ignored: FxHashMap<u32, FxHashSet<Rule>> = FxHashMap::default();
let mut file_ignored: FxHashSet<Rule> = FxHashSet::default();
let mut ignore_all = false;
for ignore in ignores {
match ignore.kind {
IgnoreKind::File => {
if ignore.ignore_all {
ignore_all = true;
} else {
file_ignored.extend(ignore.violation_names.clone());
}
}
IgnoreKind::Line => {
let line = line_index.line_col(ignore.range.start()).line;
line_to_ignored.insert(line, ignore.violation_names.clone());
}
}
}
Self {
line_to_ignored,
file_ignored,
ignore_all,
line_index,
}
}
pub(crate) fn contains(&self, range: TextRange, item: Rule) -> bool {
if self.ignore_all || self.file_ignored.contains(&item) {
return true;
}
let line = self.line_index.line_col(range.start()).line;
for line in [line, if line == 0 { 0 } else { line - 1 }] {
if let Some(set) = self.line_to_ignored.get(&line) {
if set.contains(&item) {
return true;
}
}
}
false
}
}