diff --git a/crates/ruff/src/noqa.rs b/crates/ruff/src/noqa.rs index 72ec698e7a6a9..b895a061ea3e4 100644 --- a/crates/ruff/src/noqa.rs +++ b/crates/ruff/src/noqa.rs @@ -68,12 +68,8 @@ impl<'a> Directive<'a> { // If the next character is `:`, then it's a list of codes. Otherwise, it's a directive // to ignore all rules. - return Ok(Some( - if text[noqa_literal_end..] - .chars() - .next() - .map_or(false, |c| c == ':') - { + let directive = match text[noqa_literal_end..].chars().next() { + Some(':') => { // E.g., `# noqa: F401, F841`. let mut codes_start = noqa_literal_end; @@ -120,8 +116,9 @@ impl<'a> Directive<'a> { range: range.add(offset), codes, }) - } else { - // E.g., `# noqa`. + } + None | Some('#') => { + // E.g., `# noqa` or `# noqa# ignore`. let range = TextRange::new( TextSize::try_from(comment_start).unwrap(), TextSize::try_from(noqa_literal_end).unwrap(), @@ -129,8 +126,21 @@ impl<'a> Directive<'a> { Self::All(All { range: range.add(offset), }) - }, - )); + } + Some(c) if c.is_whitespace() => { + // E.g., `# noqa # ignore`. + let range = TextRange::new( + TextSize::try_from(comment_start).unwrap(), + TextSize::try_from(noqa_literal_end).unwrap(), + ); + Self::All(All { + range: range.add(offset), + }) + } + _ => return Err(ParseError::InvalidSuffix), + }; + + return Ok(Some(directive)); } Ok(None) @@ -237,7 +247,7 @@ impl FileExemption { #[allow(deprecated)] let line = locator.compute_line_index(range.start()); let path_display = relativize_path(path); - warn!("Invalid `# noqa` directive on {path_display}:{line}: {err}"); + warn!("Invalid `# ruff: noqa` directive at {path_display}:{line}: {err}"); } Ok(Some(ParsedFileExemption::All)) => { return Some(Self::All); @@ -250,7 +260,8 @@ impl FileExemption { } else { #[allow(deprecated)] let line = locator.compute_line_index(range.start()); - warn!("Invalid code provided to `# ruff: noqa` on line {line}: {code}"); + let path_display = relativize_path(path); + warn!("Invalid code provided to `# ruff: noqa` at {path_display}:{line}: {code}"); None } })); @@ -904,6 +915,12 @@ mod tests { assert_debug_snapshot!(Directive::try_extract(source, TextSize::default())); } + #[test] + fn noqa_invalid_suffix() { + let source = "# noqa[F401]"; + assert_debug_snapshot!(Directive::try_extract(source, TextSize::default())); + } + #[test] fn flake8_exemption_all() { let source = "# flake8: noqa"; diff --git a/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs b/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs index bef3508e15bd0..84cb9577fc696 100644 --- a/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs +++ b/crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs @@ -13,7 +13,7 @@ use crate::registry::AsRule; /// Checks for f-strings that do not contain any placeholder expressions. /// /// ## Why is this bad? -/// F-strings are a convenient way to format strings, but they are not +/// f-strings are a convenient way to format strings, but they are not /// necessary if there are no placeholder expressions to format. In this /// case, a regular string should be used instead, as an f-string without /// placeholders can be confusing for readers, who may expect such a diff --git a/crates/ruff/src/snapshots/ruff__noqa__tests__noqa_invalid_suffix.snap b/crates/ruff/src/snapshots/ruff__noqa__tests__noqa_invalid_suffix.snap new file mode 100644 index 0000000000000..0e5602b9790f0 --- /dev/null +++ b/crates/ruff/src/snapshots/ruff__noqa__tests__noqa_invalid_suffix.snap @@ -0,0 +1,7 @@ +--- +source: crates/ruff/src/noqa.rs +expression: "Directive::try_extract(source, TextSize::default())" +--- +Err( + InvalidSuffix, +)