diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/suppressions.py b/crates/ruff_linter/resources/test/fixtures/ruff/suppressions.py
index 7a70c4d548..f8a3c882aa 100644
--- a/crates/ruff_linter/resources/test/fixtures/ruff/suppressions.py
+++ b/crates/ruff_linter/resources/test/fixtures/ruff/suppressions.py
@@ -54,3 +54,35 @@ def f():
# ruff:disable[E741,F841]
I = 1 # noqa: E741,F841
# ruff:enable[E741,F841]
+
+
+def f():
+ # TODO: Duplicate codes should be counted as duplicate, not unused
+ # ruff: disable[F841, F841]
+ foo = 0
+
+
+def f():
+ # Overlapping range suppressions, one should be marked as used,
+ # and the other should trigger an unused suppression diagnostic
+ # ruff: disable[F841]
+ # ruff: disable[F841]
+ foo = 0
+
+
+def f():
+ # Multiple codes but only one is used
+ # ruff: disable[E741, F401, F841]
+ foo = 0
+
+
+def f():
+ # Multiple codes but only two are used
+ # ruff: disable[E741, F401, F841]
+ I = 0
+
+
+def f():
+ # Multiple codes but none are used
+ # ruff: disable[E741, F401, F841]
+ print("hello")
diff --git a/crates/ruff_linter/src/checkers/noqa.rs b/crates/ruff_linter/src/checkers/noqa.rs
index 2602adeeee..f984ef3576 100644
--- a/crates/ruff_linter/src/checkers/noqa.rs
+++ b/crates/ruff_linter/src/checkers/noqa.rs
@@ -119,6 +119,9 @@ pub(crate) fn check_noqa(
}
}
+ // Diagnostics for unused/invalid range suppressions
+ suppressions.check_suppressions(context, locator);
+
// Enforce that the noqa directive was actually used (RUF100), unless RUF100 was itself
// suppressed.
if context.is_rule_enabled(Rule::UnusedNOQA)
@@ -140,8 +143,13 @@ pub(crate) fn check_noqa(
Directive::All(directive) => {
if matches.is_empty() {
let edit = delete_comment(directive.range(), locator);
- let mut diagnostic = context
- .report_diagnostic(UnusedNOQA { codes: None }, directive.range());
+ let mut diagnostic = context.report_diagnostic(
+ UnusedNOQA {
+ codes: None,
+ kind: ruff::rules::UnusedNOQAKind::Noqa,
+ },
+ directive.range(),
+ );
diagnostic.add_primary_tag(ruff_db::diagnostic::DiagnosticTag::Unnecessary);
diagnostic.set_fix(Fix::safe_edit(edit));
}
@@ -236,6 +244,7 @@ pub(crate) fn check_noqa(
.map(|code| (*code).to_string())
.collect(),
}),
+ kind: ruff::rules::UnusedNOQAKind::Noqa,
},
directive.range(),
);
diff --git a/crates/ruff_linter/src/noqa.rs b/crates/ruff_linter/src/noqa.rs
index e8c3ada650..a3b5b6133d 100644
--- a/crates/ruff_linter/src/noqa.rs
+++ b/crates/ruff_linter/src/noqa.rs
@@ -879,7 +879,7 @@ fn find_noqa_comments<'a>(
exemption: &'a FileExemption,
directives: &'a NoqaDirectives,
noqa_line_for: &NoqaMapping,
- suppressions: &Suppressions,
+ suppressions: &'a Suppressions,
) -> Vec