Report RUF104 unmatched suppression diagnostics

This commit is contained in:
Amethyst Reese 2025-12-10 15:17:11 -08:00
parent af80f3126e
commit 5de905120e
2 changed files with 96 additions and 2 deletions

View File

@ -7,7 +7,7 @@ source: crates/ruff_linter/src/rules/ruff/mod.rs
--- Summary ---
Removed: 14
Added: 11
Added: 18
--- Removed ---
E741 Ambiguous variable name: `I`
@ -240,6 +240,17 @@ note: This is an unsafe fix and may change runtime behavior
--- Added ---
RUF104 Unmatched suppression comment
--> suppressions.py:11:5
|
9 | # These should both be ignored by the implicit range suppression.
10 | # Should also generate an "unmatched suppression" warning.
11 | # ruff:disable[E741,F841]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12 | I = 1
|
RUF100 [*] Unused suppression (non-enabled: `E501`)
--> suppressions.py:46:5
|
@ -298,6 +309,17 @@ help: Remove unused `noqa` directive
58 |
RUF104 Unmatched suppression comment
--> suppressions.py:61:5
|
59 | def f():
60 | # TODO: Duplicate codes should be counted as duplicate, not unused
61 | # ruff: disable[F841, F841]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
62 | foo = 0
|
RUF100 [*] Unused suppression (unused: `F841`)
--> suppressions.py:61:21
|
@ -318,6 +340,18 @@ help: Remove unused suppression
64 |
RUF104 Unmatched suppression comment
--> suppressions.py:68:5
|
66 | # Overlapping range suppressions, one should be marked as used,
67 | # and the other should trigger an unused suppression diagnostic
68 | # ruff: disable[F841]
| ^^^^^^^^^^^^^^^^^^^^^
69 | # ruff: disable[F841]
70 | foo = 0
|
RUF100 [*] Unused suppression (unused: `F841`)
--> suppressions.py:69:5
|
@ -337,6 +371,28 @@ help: Remove unused suppression
71 |
RUF104 Unmatched suppression comment
--> suppressions.py:69:5
|
67 | # and the other should trigger an unused suppression diagnostic
68 | # ruff: disable[F841]
69 | # ruff: disable[F841]
| ^^^^^^^^^^^^^^^^^^^^^
70 | foo = 0
|
RUF104 Unmatched suppression comment
--> suppressions.py:75:5
|
73 | def f():
74 | # Multiple codes but only one is used
75 | # ruff: disable[E741, F401, F841]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76 | foo = 0
|
RUF100 [*] Unused suppression (unused: `E741`)
--> suppressions.py:75:21
|
@ -377,6 +433,17 @@ help: Remove unused suppression
78 |
RUF104 Unmatched suppression comment
--> suppressions.py:81:5
|
79 | def f():
80 | # Multiple codes but only two are used
81 | # ruff: disable[E741, F401, F841]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82 | I = 0
|
RUF100 [*] Unused suppression (non-enabled: `F401`)
--> suppressions.py:81:27
|
@ -397,6 +464,17 @@ help: Remove unused suppression
84 |
RUF104 Unmatched suppression comment
--> suppressions.py:87:5
|
85 | def f():
86 | # Multiple codes but none are used
87 | # ruff: disable[E741, F401, F841]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
88 | print("hello")
|
RUF100 [*] Unused suppression (unused: `E741`)
--> suppressions.py:87:21
|

View File

@ -4,6 +4,7 @@ use ruff_db::diagnostic::Diagnostic;
use ruff_diagnostics::{Edit, Fix};
use ruff_python_ast::token::{TokenKind, Tokens};
use ruff_python_ast::whitespace::indentation;
use rustc_hash::FxHashSet;
use std::cell::Cell;
use std::{error::Error, fmt::Formatter};
use thiserror::Error;
@ -17,7 +18,9 @@ use crate::checkers::ast::LintContext;
use crate::codes::Rule;
use crate::fix::edits::delete_comment;
use crate::preview::is_range_suppressions_enabled;
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA, UnusedNOQAKind};
use crate::rules::ruff::rules::{
UnmatchedSuppressionComment, UnusedCodes, UnusedNOQA, UnusedNOQAKind,
};
use crate::settings::LinterSettings;
#[derive(Clone, Debug, Eq, PartialEq)]
@ -220,6 +223,19 @@ impl Suppressions {
}
}
let unmatched = self
.valid
.iter()
.filter(|suppression| {
suppression.comments.len() == 1
&& suppression.comments[0].action == SuppressionAction::Disable
})
.map(|suppression| suppression.comments[0].range)
.collect::<FxHashSet<TextRange>>();
for range in unmatched {
context.report_diagnostic(UnmatchedSuppressionComment {}, range);
}
for error in self
.errors
.iter()