From 06888834045224a7ae6bf423f5f64eff8450520f Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Wed, 23 Aug 2023 12:00:06 -0500 Subject: [PATCH] Fix `uncessary-coding-comment` fix when there's leading content (#6775) Closes https://github.com/astral-sh/ruff/issues/6756 Including whitespace, code, and continuations. --- .../test/fixtures/pyupgrade/UP009_10.py | 7 ++++ .../test/fixtures/pyupgrade/UP009_6.py | 7 ++++ .../test/fixtures/pyupgrade/UP009_7.py | 7 ++++ .../test/fixtures/pyupgrade/UP009_8.py | 6 +++ .../test/fixtures/pyupgrade/UP009_9.py | 7 ++++ crates/ruff/src/rules/pyupgrade/mod.rs | 5 +++ .../rules/unnecessary_coding_comment.rs | 42 +++++++++++++++---- ..._rules__pyupgrade__tests__UP009_10.py.snap | 4 ++ ...__rules__pyupgrade__tests__UP009_6.py.snap | 18 ++++++++ ...__rules__pyupgrade__tests__UP009_7.py.snap | 18 ++++++++ ...__rules__pyupgrade__tests__UP009_8.py.snap | 4 ++ ...__rules__pyupgrade__tests__UP009_9.py.snap | 4 ++ 12 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 crates/ruff/resources/test/fixtures/pyupgrade/UP009_10.py create mode 100644 crates/ruff/resources/test/fixtures/pyupgrade/UP009_6.py create mode 100644 crates/ruff/resources/test/fixtures/pyupgrade/UP009_7.py create mode 100644 crates/ruff/resources/test/fixtures/pyupgrade/UP009_8.py create mode 100644 crates/ruff/resources/test/fixtures/pyupgrade/UP009_9.py create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_10.py.snap create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_6.py.snap create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_7.py.snap create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_8.py.snap create mode 100644 crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_9.py.snap diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP009_10.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_10.py new file mode 100644 index 0000000000000..bfb26d1717ab9 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_10.py @@ -0,0 +1,7 @@ +""" +# coding=utf8""" # empty comment + +""" +Invalid coding declaration since it is nested inside a docstring +The following empty comment tests for false positives as our implementation visits comments +""" diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP009_6.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_6.py new file mode 100644 index 0000000000000..d1900e39bbbc9 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_6.py @@ -0,0 +1,7 @@ + # coding=utf8 +print("Hello world") + +""" +Regression test for https://github.com/astral-sh/ruff/issues/6756 +The leading space must be removed to prevent invalid syntax. +""" diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP009_7.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_7.py new file mode 100644 index 0000000000000..5433482dd8912 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_7.py @@ -0,0 +1,7 @@ + # coding=utf8 +print("Hello world") + +""" +Regression test for https://github.com/astral-sh/ruff/issues/6756 +The leading tab must be removed to prevent invalid syntax. +""" diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP009_8.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_8.py new file mode 100644 index 0000000000000..e0e48475bf907 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_8.py @@ -0,0 +1,6 @@ +print("foo") # coding=utf8 +print("Hello world") + +""" +Invalid coding declaration due to a statement before the comment +""" diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP009_9.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_9.py new file mode 100644 index 0000000000000..b88d6cb794c08 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP009_9.py @@ -0,0 +1,7 @@ +x = 1 \ + # coding=utf8 +x = 2 + +""" +Invalid coding declaration due to continuation on preceding line +""" diff --git a/crates/ruff/src/rules/pyupgrade/mod.rs b/crates/ruff/src/rules/pyupgrade/mod.rs index 3e75dc8550c68..416972454fcc4 100644 --- a/crates/ruff/src/rules/pyupgrade/mod.rs +++ b/crates/ruff/src/rules/pyupgrade/mod.rs @@ -67,6 +67,11 @@ mod tests { #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_3.py"))] #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_4.py"))] #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_5.py"))] + #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_6.py"))] + #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_7.py"))] + #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_8.py"))] + #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_9.py"))] + #[test_case(Rule::UTF8EncodingDeclaration, Path::new("UP009_10.py"))] #[test_case(Rule::UnicodeKindPrefix, Path::new("UP025.py"))] #[test_case(Rule::UnnecessaryBuiltinImport, Path::new("UP029.py"))] #[test_case(Rule::UnnecessaryClassParentheses, Path::new("UP039.py"))] diff --git a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_coding_comment.rs b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_coding_comment.rs index cd0cdf213e8e5..72e55a6b11ab6 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_coding_comment.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_coding_comment.rs @@ -5,6 +5,7 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_index::Indexer; use ruff_source_file::Locator; +use ruff_text_size::TextRange; use crate::registry::AsRule; use crate::settings::Settings; @@ -55,20 +56,45 @@ pub(crate) fn unnecessary_coding_comment( ) { // The coding comment must be on one of the first two lines. Since each comment spans at least // one line, we only need to check the first two comments at most. - for range in indexer.comment_ranges().iter().take(2) { - let line = locator.slice(*range); - if CODING_COMMENT_REGEX.is_match(line) { + for comment_range in indexer.comment_ranges().iter().take(2) { + // If leading content is not whitespace then it's not a valid coding comment e.g. + // ``` + // print(x) # coding=utf8 + // ``` + let line_range = locator.full_line_range(comment_range.start()); + if !locator + .slice(TextRange::new(line_range.start(), comment_range.start())) + .trim() + .is_empty() + { + continue; + } + + // If the line is after a continuation then it's not a valid coding comment e.g. + // ``` + // x = 1 \ + // # coding=utf8 + // x = 2 + // ``` + if indexer + .preceded_by_continuations(line_range.start(), locator) + .is_some() + { + continue; + } + + if CODING_COMMENT_REGEX.is_match(locator.slice(line_range)) { #[allow(deprecated)] - let line = locator.compute_line_index(range.start()); - if line.to_zero_indexed() > 1 { + let index = locator.compute_line_index(line_range.start()); + if index.to_zero_indexed() > 1 { continue; } - let mut diagnostic = Diagnostic::new(UTF8EncodingDeclaration, *range); + let mut diagnostic = Diagnostic::new(UTF8EncodingDeclaration, *comment_range); if settings.rules.should_fix(diagnostic.kind.rule()) { diagnostic.set_fix(Fix::automatic(Edit::deletion( - range.start(), - locator.full_line_end(range.end()), + line_range.start(), + line_range.end(), ))); } diagnostics.push(diagnostic); diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_10.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_10.py.snap new file mode 100644 index 0000000000000..870ad3bf5d625 --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_10.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- + diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_6.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_6.py.snap new file mode 100644 index 0000000000000..faf65dd7cc43a --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_6.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- +UP009_6.py:1:2: UP009 [*] UTF-8 encoding declaration is unnecessary + | +1 | # coding=utf8 + | ^^^^^^^^^^^^^ UP009 +2 | print("Hello world") + | + = help: Remove unnecessary coding comment + +ℹ Fix +1 |- # coding=utf8 +2 1 | print("Hello world") +3 2 | +4 3 | """ + + diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_7.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_7.py.snap new file mode 100644 index 0000000000000..8e7962330df15 --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_7.py.snap @@ -0,0 +1,18 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- +UP009_7.py:1:2: UP009 [*] UTF-8 encoding declaration is unnecessary + | +1 | # coding=utf8 + | ^^^^^^^^^^^^^ UP009 +2 | print("Hello world") + | + = help: Remove unnecessary coding comment + +ℹ Fix +1 |- # coding=utf8 +2 1 | print("Hello world") +3 2 | +4 3 | """ + + diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_8.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_8.py.snap new file mode 100644 index 0000000000000..870ad3bf5d625 --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_8.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- + diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_9.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_9.py.snap new file mode 100644 index 0000000000000..870ad3bf5d625 --- /dev/null +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP009_9.py.snap @@ -0,0 +1,4 @@ +--- +source: crates/ruff/src/rules/pyupgrade/mod.rs +--- +