diff --git a/crates/ruff/resources/test/fixtures/pyupgrade/UP012.py b/crates/ruff/resources/test/fixtures/pyupgrade/UP012.py index af589f15f5..266e8431cc 100644 --- a/crates/ruff/resources/test/fixtures/pyupgrade/UP012.py +++ b/crates/ruff/resources/test/fixtures/pyupgrade/UP012.py @@ -59,3 +59,14 @@ u"foo".encode("utf-8") # b"foo" R"foo\o".encode("utf-8") # br"foo\o" U"foo".encode("utf-8") # b"foo" print("foo".encode()) # print(b"foo") + +# `encode` on parenthesized strings. +( + "abc" + "def" +).encode() + +(( + "abc" + "def" +)).encode() diff --git a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs index f80d01e828..5b7613bdda 100644 --- a/crates/ruff/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs +++ b/crates/ruff/src/rules/pyupgrade/rules/unnecessary_encode_utf8.rs @@ -107,27 +107,27 @@ fn match_encoding_arg<'a>(args: &'a [Expr], kwargs: &'a [Keyword]) -> Option Fix { +fn replace_with_bytes_literal(locator: &Locator, expr: &Expr) -> Fix { // Build up a replacement string by prefixing all string tokens with `b`. - let contents = locator.slice(constant.range()); + let contents = locator.slice(expr.range()); let mut replacement = String::with_capacity(contents.len() + 1); - let mut prev = None; - for (tok, range) in lexer::lex_located(contents, Mode::Module, constant.start()).flatten() { - if matches!(tok, Tok::String { .. }) { - if let Some(prev) = prev { + let mut prev = expr.start(); + for (tok, range) in lexer::lex_located(contents, Mode::Module, expr.start()).flatten() { + match tok { + Tok::Dot => break, + Tok::String { .. } => { replacement.push_str(locator.slice(TextRange::new(prev, range.start()))); + let string = locator.slice(range); + replacement.push_str(&format!( + "b{}", + &string.trim_start_matches('u').trim_start_matches('U') + )); } - let string = locator.slice(range); - replacement.push_str(&format!( - "b{}", - &string.trim_start_matches('u').trim_start_matches('U') - )); - } else { - if let Some(prev) = prev { + _ => { replacement.push_str(locator.slice(TextRange::new(prev, range.end()))); } } - prev = Some(range.end()); + prev = range.end(); } Fix::unspecified(Edit::range_replacement(replacement, expr.range())) } @@ -159,11 +159,7 @@ pub fn unnecessary_encode_utf8( expr.range(), ); if checker.patch(Rule::UnnecessaryEncodeUTF8) { - diagnostic.set_fix(replace_with_bytes_literal( - checker.locator, - expr, - variable, - )); + diagnostic.set_fix(replace_with_bytes_literal(checker.locator, expr)); } checker.diagnostics.push(diagnostic); } else if let EncodingArg::Keyword(kwarg) = encoding_arg { diff --git a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP012.py.snap b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP012.py.snap index 485ba36a2a..1006d7fcb3 100644 --- a/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP012.py.snap +++ b/crates/ruff/src/rules/pyupgrade/snapshots/ruff__rules__pyupgrade__tests__UP012.py.snap @@ -373,6 +373,7 @@ UP012.py:59:1: UP012 [*] Unnecessary call to `encode` as UTF-8 59 |+bR"foo\o" # br"foo\o" 60 60 | U"foo".encode("utf-8") # b"foo" 61 61 | print("foo".encode()) # print(b"foo") +62 62 | UP012.py:60:1: UP012 [*] Unnecessary call to `encode` as UTF-8 | @@ -391,6 +392,8 @@ UP012.py:60:1: UP012 [*] Unnecessary call to `encode` as UTF-8 60 |-U"foo".encode("utf-8") # b"foo" 60 |+b"foo" # b"foo" 61 61 | print("foo".encode()) # print(b"foo") +62 62 | +63 63 | # `encode` on parenthesized strings. UP012.py:61:7: UP012 [*] Unnecessary call to `encode` as UTF-8 | @@ -398,6 +401,8 @@ UP012.py:61:7: UP012 [*] Unnecessary call to `encode` as UTF-8 62 | U"foo".encode("utf-8") # b"foo" 63 | print("foo".encode()) # print(b"foo") | ^^^^^^^^^^^^^^ UP012 +64 | +65 | # `encode` on parenthesized strings. | = help: Rewrite as bytes literal @@ -407,5 +412,58 @@ UP012.py:61:7: UP012 [*] Unnecessary call to `encode` as UTF-8 60 60 | U"foo".encode("utf-8") # b"foo" 61 |-print("foo".encode()) # print(b"foo") 61 |+print(b"foo") # print(b"foo") +62 62 | +63 63 | # `encode` on parenthesized strings. +64 64 | ( + +UP012.py:64:1: UP012 [*] Unnecessary call to `encode` as UTF-8 + | +64 | # `encode` on parenthesized strings. +65 | / ( +66 | | "abc" +67 | | "def" +68 | | ).encode() + | |__________^ UP012 +69 | +70 | (( + | + = help: Rewrite as bytes literal + +ℹ Suggested fix +62 62 | +63 63 | # `encode` on parenthesized strings. +64 64 | ( +65 |- "abc" +66 |- "def" +67 |-).encode() + 65 |+ b"abc" + 66 |+ b"def" + 67 |+) +68 68 | +69 69 | (( +70 70 | "abc" + +UP012.py:69:1: UP012 [*] Unnecessary call to `encode` as UTF-8 + | +69 | ).encode() +70 | +71 | / (( +72 | | "abc" +73 | | "def" +74 | | )).encode() + | |___________^ UP012 + | + = help: Rewrite as bytes literal + +ℹ Suggested fix +67 67 | ).encode() +68 68 | +69 69 | (( +70 |- "abc" +71 |- "def" +72 |-)).encode() + 70 |+ b"abc" + 71 |+ b"def" + 72 |+))