diff --git a/resources/test/fixtures/M001.py b/resources/test/fixtures/M001.py index 1c592e3142..6cd9346c9a 100644 --- a/resources/test/fixtures/M001.py +++ b/resources/test/fixtures/M001.py @@ -18,6 +18,14 @@ def f() -> None: # Invalid (and unimplemented) d = 1 # noqa: F841, W191 + # fmt: off + # Invalid - no space before # + d = 1# noqa: E501 + + # Invalid - many spaces before # + d = 1 # noqa: E501 + # fmt: on + # Valid _ = """Lorem ipsum dolor sit amet. diff --git a/src/check_lines.rs b/src/check_lines.rs index ceb95cdce7..73d0ea9ea8 100644 --- a/src/check_lines.rs +++ b/src/check_lines.rs @@ -103,7 +103,7 @@ pub fn check_lines( matches.push(check.kind.code().as_ref()); ignored.push(index) } - (Directive::Codes(_, _, codes), matches) => { + (Directive::Codes(.., codes), matches) => { if codes.contains(&check.kind.code().as_ref()) { matches.push(check.kind.code().as_ref()); ignored.push(index); @@ -133,7 +133,7 @@ pub fn check_lines( (Directive::All(..), matches) => { matches.push(check.kind.code().as_ref()); } - (Directive::Codes(_, _, codes), matches) => { + (Directive::Codes(.., codes), matches) => { if codes.contains(&check.kind.code().as_ref()) { matches.push(check.kind.code().as_ref()); } else { @@ -170,7 +170,7 @@ pub fn check_lines( (Directive::All(..), matches) => { matches.push(check.kind.code().as_ref()); } - (Directive::Codes(_, _, codes), matches) => { + (Directive::Codes(.., codes), matches) => { if codes.contains(&check.kind.code().as_ref()) { matches.push(check.kind.code().as_ref()); } else { @@ -186,7 +186,7 @@ pub fn check_lines( if enforce_noqa { for (row, (directive, matches)) in noqa_directives { match directive { - Directive::All(start, end) => { + Directive::All(spaces, start, end) => { if matches.is_empty() { let mut check = Check::new( CheckKind::UnusedNOQA(None), @@ -197,14 +197,14 @@ pub fn check_lines( ); if autofix.patch() && settings.fixable.contains(check.kind.code()) { check.amend(Fix::deletion( - Location::new(row + 1, start), + Location::new(row + 1, start - spaces), Location::new(row + 1, lines[row].chars().count()), )); } line_checks.push(check); } } - Directive::Codes(start, end, codes) => { + Directive::Codes(spaces, start, end, codes) => { let mut invalid_codes = vec![]; let mut valid_codes = vec![]; for code in codes { @@ -226,12 +226,12 @@ pub fn check_lines( if autofix.patch() && settings.fixable.contains(check.kind.code()) { if valid_codes.is_empty() { check.amend(Fix::deletion( - Location::new(row + 1, start), + Location::new(row + 1, start - spaces), Location::new(row + 1, lines[row].chars().count()), )); } else { check.amend(Fix::replacement( - format!(" # noqa: {}", valid_codes.join(", ")), + format!("# noqa: {}", valid_codes.join(", ")), Location::new(row + 1, start), Location::new(row + 1, lines[row].chars().count()), )); diff --git a/src/noqa.rs b/src/noqa.rs index 20735b4c90..9ea34f8319 100644 --- a/src/noqa.rs +++ b/src/noqa.rs @@ -10,32 +10,40 @@ use regex::Regex; use crate::checks::{Check, CheckCode}; static NO_QA_REGEX: Lazy = Lazy::new(|| { - Regex::new(r"(?P\s*(?i:# noqa)(?::\s?(?P([A-Z]+[0-9]+(?:[,\s]+)?)+))?)") - .expect("Invalid regex") + Regex::new( + r"(?P\s*)(?P(?i:# noqa)(?::\s?(?P([A-Z]+[0-9]+(?:[,\s]+)?)+))?)", + ) + .expect("Invalid regex") }); static SPLIT_COMMA_REGEX: Lazy = Lazy::new(|| Regex::new(r"[,\s]").expect("Invalid regex")); #[derive(Debug)] pub enum Directive<'a> { None, - All(usize, usize), - Codes(usize, usize, Vec<&'a str>), + All(usize, usize, usize), + Codes(usize, usize, usize, Vec<&'a str>), } pub fn extract_noqa_directive(line: &str) -> Directive { match NO_QA_REGEX.captures(line) { - Some(caps) => match caps.name("noqa") { - Some(noqa) => match caps.name("codes") { - Some(codes) => Directive::Codes( - noqa.start(), - noqa.end(), - SPLIT_COMMA_REGEX - .split(codes.as_str()) - .map(|code| code.trim()) - .filter(|code| !code.is_empty()) - .collect(), - ), - None => Directive::All(noqa.start(), noqa.end()), + Some(caps) => match caps.name("spaces") { + Some(spaces) => match caps.name("noqa") { + Some(noqa) => match caps.name("codes") { + Some(codes) => Directive::Codes( + spaces.as_str().chars().count(), + noqa.start(), + noqa.end(), + SPLIT_COMMA_REGEX + .split(codes.as_str()) + .map(|code| code.trim()) + .filter(|code| !code.is_empty()) + .collect(), + ), + None => { + Directive::All(spaces.as_str().chars().count(), noqa.start(), noqa.end()) + } + }, + None => Directive::None, }, None => Directive::None, }, @@ -92,12 +100,14 @@ fn add_noqa_inner( match extract_noqa_directive(line) { Directive::None => { output.push_str(line); + output.push_str(" # noqa: "); + } + Directive::All(_, start, _) | Directive::Codes(_, start, ..) => { + output.push_str(&line[..start]); + output.push_str("# noqa: "); } - Directive::All(start, _) => output.push_str(&line[..start]), - Directive::Codes(start, ..) => output.push_str(&line[..start]), }; let codes: Vec<&str> = codes.iter().map(|code| code.as_ref()).collect(); - output.push_str(" # noqa: "); output.push_str(&codes.join(", ")); output.push('\n'); count += 1; diff --git a/src/snapshots/ruff__linter__tests__m001.snap b/src/snapshots/ruff__linter__tests__m001.snap index 7b8bd2a877..a0c3b85b89 100644 --- a/src/snapshots/ruff__linter__tests__m001.snap +++ b/src/snapshots/ruff__linter__tests__m001.snap @@ -6,7 +6,7 @@ expression: checks UnusedNOQA: ~ location: row: 9 - column: 9 + column: 11 end_location: row: 9 column: 17 @@ -25,7 +25,7 @@ expression: checks - E501 location: row: 13 - column: 9 + column: 11 end_location: row: 13 column: 23 @@ -45,7 +45,7 @@ expression: checks - E501 location: row: 16 - column: 9 + column: 11 end_location: row: 16 column: 29 @@ -61,16 +61,17 @@ expression: checks applied: false - kind: UnusedNOQA: + - F841 - W191 location: row: 19 - column: 9 + column: 11 end_location: row: 19 column: 29 fix: patch: - content: " # noqa: F841" + content: "" location: row: 19 column: 9 @@ -78,60 +79,107 @@ expression: checks row: 19 column: 29 applied: false +- kind: + UnusedNOQA: + - E501 + location: + row: 23 + column: 9 + end_location: + row: 23 + column: 21 + fix: + patch: + content: "" + location: + row: 23 + column: 9 + end_location: + row: 23 + column: 21 + applied: false +- kind: + UnusedVariable: d + location: + row: 26 + column: 4 + end_location: + row: 26 + column: 5 + fix: ~ +- kind: + UnusedNOQA: + - E501 + location: + row: 26 + column: 32 + end_location: + row: 26 + column: 44 + fix: + patch: + content: "" + location: + row: 26 + column: 9 + end_location: + row: 26 + column: 44 + applied: false - kind: UnusedNOQA: - F841 location: - row: 44 - column: 3 + row: 52 + column: 5 end_location: - row: 44 + row: 52 column: 23 fix: patch: - content: " # noqa: E501" + content: "# noqa: E501" location: - row: 44 - column: 3 + row: 52 + column: 5 end_location: - row: 44 + row: 52 column: 23 applied: false - kind: UnusedNOQA: - E501 location: - row: 52 - column: 3 + row: 60 + column: 5 end_location: - row: 52 + row: 60 column: 17 fix: patch: content: "" location: - row: 52 + row: 60 column: 3 end_location: - row: 52 + row: 60 column: 17 applied: false - kind: UnusedNOQA: ~ location: - row: 60 - column: 3 + row: 68 + column: 5 end_location: - row: 60 + row: 68 column: 11 fix: patch: content: "" location: - row: 60 + row: 68 column: 3 end_location: - row: 60 + row: 68 column: 11 applied: false