From 6fcbe8efb43d0225617946dffa2278282b43cd8b Mon Sep 17 00:00:00 2001
From: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
Date: Wed, 27 Nov 2024 12:25:47 -0500
Subject: [PATCH] [`ruff`] Detect redirected-noqa in file-level comments
(`RUF101`) (#14635)
---
.../fixtures/ruff/{RUF101.py => RUF101_0.py} | 0
.../resources/test/fixtures/ruff/RUF101_1.py | 13 ++++
crates/ruff_linter/src/checkers/noqa.rs | 1 +
crates/ruff_linter/src/noqa.rs | 73 ++++++++++++++-----
crates/ruff_linter/src/rules/ruff/mod.rs | 3 +-
.../src/rules/ruff/rules/redirected_noqa.rs | 53 +++++++++-----
...les__ruff__tests__RUF101_RUF101_0.py.snap} | 14 ++--
...ules__ruff__tests__RUF101_RUF101_1.py.snap | 24 ++++++
...er__noqa__tests__flake8_exemption_all.snap | 2 +-
...flake8_exemption_all_case_insensitive.snap | 2 +-
..._tests__flake8_exemption_all_no_space.snap | 2 +-
...__noqa__tests__flake8_exemption_codes.snap | 19 +++--
...nter__noqa__tests__ruff_exemption_all.snap | 2 +-
...__ruff_exemption_all_case_insensitive.snap | 2 +-
...a__tests__ruff_exemption_all_no_space.snap | 2 +-
...er__noqa__tests__ruff_exemption_codes.snap | 19 +++--
16 files changed, 173 insertions(+), 58 deletions(-)
rename crates/ruff_linter/resources/test/fixtures/ruff/{RUF101.py => RUF101_0.py} (100%)
create mode 100644 crates/ruff_linter/resources/test/fixtures/ruff/RUF101_1.py
rename crates/ruff_linter/src/rules/ruff/snapshots/{ruff_linter__rules__ruff__tests__RUF101_RUF101.py.snap => ruff_linter__rules__ruff__tests__RUF101_RUF101_0.py.snap} (89%)
create mode 100644 crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF101_RUF101_1.py.snap
diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF101.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF101_0.py
similarity index 100%
rename from crates/ruff_linter/resources/test/fixtures/ruff/RUF101.py
rename to crates/ruff_linter/resources/test/fixtures/ruff/RUF101_0.py
diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF101_1.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF101_1.py
new file mode 100644
index 0000000000000..7d620f9c6e8a2
--- /dev/null
+++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF101_1.py
@@ -0,0 +1,13 @@
+"""Regression test for #14531.
+
+RUF101 should trigger here because the TCH rules have been recoded to TC.
+"""
+# ruff: noqa: TCH002
+
+from __future__ import annotations
+
+import local_module
+
+
+def func(sized: local_module.Container) -> int:
+ return len(sized)
diff --git a/crates/ruff_linter/src/checkers/noqa.rs b/crates/ruff_linter/src/checkers/noqa.rs
index a2ecc7a34161f..c48ab99ad57e1 100644
--- a/crates/ruff_linter/src/checkers/noqa.rs
+++ b/crates/ruff_linter/src/checkers/noqa.rs
@@ -211,6 +211,7 @@ pub(crate) fn check_noqa(
&& !exemption.includes(Rule::RedirectedNOQA)
{
ruff::rules::redirected_noqa(diagnostics, &noqa_directives);
+ ruff::rules::redirected_file_noqa(diagnostics, &file_noqa_directives);
}
if settings.rules.enabled(Rule::BlanketNOQA)
diff --git a/crates/ruff_linter/src/noqa.rs b/crates/ruff_linter/src/noqa.rs
index 0b51ac3008df4..ce670225b89c9 100644
--- a/crates/ruff_linter/src/noqa.rs
+++ b/crates/ruff_linter/src/noqa.rs
@@ -319,7 +319,7 @@ impl<'a> From<&'a FileNoqaDirectives<'a>> for FileExemption<'a> {
if directives
.lines()
.iter()
- .any(|line| ParsedFileExemption::All == line.parsed_file_exemption)
+ .any(|line| matches!(line.parsed_file_exemption, ParsedFileExemption::All))
{
FileExemption::All(codes)
} else {
@@ -362,7 +362,7 @@ impl<'a> FileNoqaDirectives<'a> {
let mut lines = vec![];
for range in comment_ranges {
- match ParsedFileExemption::try_extract(&locator.contents()[range]) {
+ match ParsedFileExemption::try_extract(range, locator.contents()) {
Err(err) => {
#[allow(deprecated)]
let line = locator.compute_line_index(range.start());
@@ -384,6 +384,7 @@ impl<'a> FileNoqaDirectives<'a> {
}
ParsedFileExemption::Codes(codes) => {
codes.iter().filter_map(|code| {
+ let code = code.as_str();
// Ignore externally-defined rules.
if external.iter().any(|external| code.starts_with(external)) {
return None;
@@ -424,21 +425,26 @@ impl<'a> FileNoqaDirectives<'a> {
/// An individual file-level exemption (e.g., `# ruff: noqa` or `# ruff: noqa: F401, F841`). Like
/// [`FileNoqaDirectives`], but only for a single line, as opposed to an aggregated set of exemptions
/// across a source file.
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug)]
pub(crate) enum ParsedFileExemption<'a> {
/// The file-level exemption ignores all rules (e.g., `# ruff: noqa`).
All,
/// The file-level exemption ignores specific rules (e.g., `# ruff: noqa: F401, F841`).
- Codes(Vec<&'a str>),
+ Codes(Codes<'a>),
}
impl<'a> ParsedFileExemption<'a> {
- /// Return a [`ParsedFileExemption`] for a given comment line.
- fn try_extract(line: &'a str) -> Result