Define rule codes RUF103/104 for invalid/unmatched suppression comments

This commit is contained in:
Amethyst Reese 2025-12-10 12:53:40 -08:00
parent 3f63ea4b50
commit af80f3126e
5 changed files with 85 additions and 0 deletions

View File

@ -1063,6 +1063,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "100") => rules::ruff::rules::UnusedNOQA,
(Ruff, "101") => rules::ruff::rules::RedirectedNOQA,
(Ruff, "102") => rules::ruff::rules::InvalidRuleCode,
(Ruff, "103") => rules::ruff::rules::InvalidSuppressionComment,
(Ruff, "104") => rules::ruff::rules::UnmatchedSuppressionComment,
(Ruff, "200") => rules::ruff::rules::InvalidPyprojectToml,
#[cfg(any(feature = "test-rules", test))]

View File

@ -0,0 +1,39 @@
use ruff_macros::{ViolationMetadata, derive_message_formats};
use crate::AlwaysFixableViolation;
/// ## What it does
/// Checks for invalid suppression comments
///
/// ## Why is this bad?
/// Invalid suppression comments are ignored by Ruff, and should either
/// be fixed or removed to avoid confusion.
///
/// ## Example
/// ```python
/// ruff: disable # missing codes
/// ```
///
/// Use instead:
/// ```python
/// # ruff: disable[E501]
/// ```
///
/// Or delete the invalid suppression comment.
///
/// ## References
/// - [Ruff error suppression](https://docs.astral.sh/ruff/linter/#error-suppression)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "0.14.9")]
pub(crate) struct InvalidSuppressionComment;
impl AlwaysFixableViolation for InvalidSuppressionComment {
#[derive_message_formats]
fn message(&self) -> String {
"Invalid suppression comment".to_string()
}
fn fix_title(&self) -> String {
"Remove invalid suppression comment".to_string()
}
}

View File

@ -22,6 +22,7 @@ pub(crate) use invalid_formatter_suppression_comment::*;
pub(crate) use invalid_index_type::*;
pub(crate) use invalid_pyproject_toml::*;
pub(crate) use invalid_rule_code::*;
pub(crate) use invalid_suppression_comment::*;
pub(crate) use legacy_form_pytest_raises::*;
pub(crate) use logging_eager_conversion::*;
pub(crate) use map_int_version_parsing::*;
@ -46,6 +47,7 @@ pub(crate) use starmap_zip::*;
pub(crate) use static_key_dict_comprehension::*;
#[cfg(any(feature = "test-rules", test))]
pub(crate) use test_rules::*;
pub(crate) use unmatched_suppression_comment::*;
pub(crate) use unnecessary_cast_to_int::*;
pub(crate) use unnecessary_iterable_allocation_for_first_element::*;
pub(crate) use unnecessary_key_check::*;
@ -87,6 +89,7 @@ mod invalid_formatter_suppression_comment;
mod invalid_index_type;
mod invalid_pyproject_toml;
mod invalid_rule_code;
mod invalid_suppression_comment;
mod legacy_form_pytest_raises;
mod logging_eager_conversion;
mod map_int_version_parsing;
@ -113,6 +116,7 @@ mod static_key_dict_comprehension;
mod suppression_comment_visitor;
#[cfg(any(feature = "test-rules", test))]
pub(crate) mod test_rules;
mod unmatched_suppression_comment;
mod unnecessary_cast_to_int;
mod unnecessary_iterable_allocation_for_first_element;
mod unnecessary_key_check;

View File

@ -0,0 +1,38 @@
use ruff_macros::{ViolationMetadata, derive_message_formats};
use crate::Violation;
/// ## What it does
/// Checks for unmatched range suppression comments
///
/// ## Why is this bad?
/// Unmatched range suppression comments can inadvertently suppress violations
/// over larger sections of code than intended, particularly at module scope.
///
/// ## Example
/// ```python
/// def foo():
/// ruff: disable[E501] # unmatched
/// ...
/// ```
///
/// Use instead:
/// ```python
/// def foo():
/// # ruff: disable[E501]
/// ...
/// # ruff: enable[E501]
/// ```
///
/// ## References
/// - [Ruff error suppression](https://docs.astral.sh/ruff/linter/#error-suppression)
#[derive(ViolationMetadata)]
#[violation_metadata(preview_since = "0.14.9")]
pub(crate) struct UnmatchedSuppressionComment;
impl Violation for UnmatchedSuppressionComment {
#[derive_message_formats]
fn message(&self) -> String {
"Unmatched suppression comment".to_string()
}
}

2
ruff.schema.json generated
View File

@ -4050,6 +4050,8 @@
"RUF100",
"RUF101",
"RUF102",
"RUF103",
"RUF104",
"RUF2",
"RUF20",
"RUF200",