Skip to content

Commit 850398d

Browse files
committed
Prototype filtering diagnostics by range suppressions
1 parent ef8f399 commit 850398d

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

crates/ruff_linter/src/linter.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,6 @@ pub fn check_path(
139139
let tokens = parsed.tokens();
140140
let comment_ranges = indexer.comment_ranges();
141141

142-
// Gather all ruff:directive suppressions
143-
let _suppressions = Suppressions::from_tokens(locator.contents(), tokens);
144-
145142
// Collect doc lines. This requires a rare mix of tokens (for comments) and AST
146143
// (for docstrings), which demands special-casing at this level.
147144
let use_doc_lines = context.is_rule_enabled(Rule::DocLineTooLong);
@@ -329,6 +326,14 @@ pub fn check_path(
329326
}
330327
}
331328

329+
// Apply range suppressions before noqa, so that #noqa on a line already covered by a range
330+
// will be reported as unused noqa rather than unused range.
331+
// TODO: check if enabled?
332+
{
333+
let suppressions = Suppressions::from_tokens(locator.contents(), tokens);
334+
suppressions.filter_diagnostics(&mut context);
335+
}
336+
332337
// Enforce `noqa` directives.
333338
if noqa.is_enabled()
334339
|| context

crates/ruff_linter/src/suppression.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use ruff_python_trivia::{Cursor, is_python_whitespace};
88
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize, TextSlice};
99
use smallvec::{SmallVec, smallvec};
1010

11+
use crate::checkers::ast::LintContext;
12+
1113
#[derive(Clone, Debug, Eq, PartialEq)]
1214
enum SuppressionAction {
1315
Disable,
@@ -101,6 +103,35 @@ impl Suppressions {
101103
let mut builder = SuppressionsBuilder::new(source);
102104
builder.load_from_tokens(tokens)
103105
}
106+
107+
/// Check reported diagnostics against the set of valid range suppressions, and remove any
108+
/// diagnostics from the context that should be suppressed by those ranges.
109+
pub(crate) fn filter_diagnostics(&self, context: &mut LintContext) {
110+
let mut ignored: Vec<usize> = vec![];
111+
112+
'outer: for (index, diagnostic) in context.iter().enumerate() {
113+
let Some(code) = diagnostic.secondary_code() else {
114+
continue;
115+
};
116+
let Some(span) = diagnostic.primary_span() else {
117+
continue;
118+
};
119+
let Some(range) = span.range() else {
120+
continue;
121+
};
122+
123+
for suppression in &self.valid {
124+
if *code == suppression.code.as_str() && suppression.range.contains_range(range) {
125+
ignored.push(index);
126+
continue 'outer;
127+
}
128+
}
129+
}
130+
131+
for index in ignored.iter().rev() {
132+
context.as_mut_vec().swap_remove(*index);
133+
}
134+
}
104135
}
105136

106137
#[derive(Default)]

0 commit comments

Comments
 (0)