use std::{collections::HashMap, path::Path};
use gobject_ast::model::FileModel;
pub fn parse_ignore_directives(file_model: &FileModel) -> HashMap<usize, Vec<String>> {
let mut ignores: HashMap<usize, Vec<String>> = HashMap::new();
if let Ok(source_str) = std::str::from_utf8(&file_model.source) {
let lines: Vec<&str> = source_str.lines().collect();
for (line_idx, line) in lines.iter().enumerate() {
let line_num = line_idx + 1;
if let Some(rules) = parse_ignore_comment(line, false) {
ignores.entry(line_num).or_default().extend(rules);
}
if let Some(rules) = parse_ignore_comment(line, true) {
let next_line = line_num + 1;
ignores.entry(next_line).or_default().extend(rules);
}
}
}
ignores
}
fn parse_ignore_comment(line: &str, next_line: bool) -> Option<Vec<String>> {
let directives: &[&str] = if next_line {
&[
"gobject-linter-ignore-next-line:",
"goblint-ignore-next-line:",
]
} else {
&["gobject-linter-ignore:", "goblint-ignore:"]
};
let (directive, idx) = directives
.iter()
.find_map(|d| line.find(d).map(|i| (*d, i)))?;
let rest = line[idx + directive.len()..]
.trim()
.trim_end_matches("*/")
.trim();
let rules: Vec<String> = rest
.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect();
if !rules.is_empty() { Some(rules) } else { None }
}
pub fn should_ignore_violation(
file_path: &Path,
line: usize,
rule: &str,
ignore_map: &HashMap<&Path, HashMap<usize, Vec<String>>>,
) -> bool {
if let Some(file_ignores) = ignore_map.get(file_path)
&& let Some(ignored_rules) = file_ignores.get(&line)
&& ignored_rules
.iter()
.any(|r| r == rule || r == "all" || r == "*")
{
return true;
}
false
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_ignore_comment() {
assert_eq!(
parse_ignore_comment(" /* gobject-linter-ignore: rule_name */", false),
Some(vec!["rule_name".to_string()])
);
assert_eq!(
parse_ignore_comment(" /* gobject-linter-ignore: rule1, rule2 */", false),
Some(vec!["rule1".to_string(), "rule2".to_string()])
);
assert_eq!(
parse_ignore_comment(" /* gobject-linter-ignore-next-line: rule_name */", true),
Some(vec!["rule_name".to_string()])
);
assert_eq!(
parse_ignore_comment(" // gobject-linter-ignore: rule_name", false),
Some(vec!["rule_name".to_string()])
);
assert_eq!(parse_ignore_comment(" /* regular comment */", false), None);
}
}