Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flake8-implicit-str-concat] Normalize octals before merging concatenated strings in single-line-implicit-string-concatenation (ISC001) #13118

Merged
merged 9 commits into from
Aug 27, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,12 @@
+ f"second"} d"
_ = f"a {f"first {f"middle"}"
+ f"second"} d"

# See https://github.com/astral-sh/ruff/issues/12936
_ = "\12""0" # fix should be "\0120"
_ = "\\12""0" # fix should be "\\120"
_ = "\\\12""0" # fix should be "\\\0120"
_ = "\12 0""0" # fix should be "\12 00"
_ = r"\12"r"0" # fix should be r"\120"
_ = "\12 and more""0" # fix should be "\12 and more0"
_ = "\8""0" # fix should be "\80"
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,14 @@ fn concatenate_strings(a_range: TextRange, b_range: TextRange, locator: &Locator
return None;
}

let a_body = &a_text[a_leading_quote.len()..a_text.len() - a_trailing_quote.len()];
let mut a_body =
a_text[a_leading_quote.len()..a_text.len() - a_trailing_quote.len()].to_string();
let b_body = &b_text[b_leading_quote.len()..b_text.len() - b_trailing_quote.len()];

if a_leading_quote.find(['r', 'R']).is_none() {
a_body = normalize_ending_octal(&a_body);
}

let concatenation = format!("{a_leading_quote}{a_body}{b_body}{a_trailing_quote}");
let range = TextRange::new(a_range.start(), b_range.end());

Expand All @@ -183,3 +188,41 @@ fn concatenate_strings(a_range: TextRange, b_range: TextRange, locator: &Locator
range,
)))
}

/// Pads an octal at the end of the string
/// to three digits, if necessary.
fn normalize_ending_octal(text: &str) -> String {
// Early return for short strings
if text.len() < 2 {
return text.to_string();
}

let mut rev_bytes = text.bytes().rev();
if let Some(last_byte @ b'0'..=b'7') = rev_bytes.next() {
// "\y" -> "\00y"
if has_odd_consecutive_backslashes(&rev_bytes) {
let prefix = &text[..text.len() - 2];
return format!("{prefix}\\00{}", last_byte as char);
}
// "\xy" -> "\0xy"
if let Some(penultimate_byte @ b'0'..=b'7') = rev_bytes.next() {
if has_odd_consecutive_backslashes(&rev_bytes) {
let prefix = &text[..text.len() - 3];
return format!(
"{prefix}\\0{}{}",
penultimate_byte as char, last_byte as char
);
}
}
}
text.to_string()
}

fn has_odd_consecutive_backslashes<I: Iterator<Item = u8> + Clone>(itr: &I) -> bool {
let mut itrclone = itr.clone();
let mut odd_backslashes = false;
while let Some(b'\\') = itrclone.next() {
odd_backslashes = !odd_backslashes;
}
odd_backslashes
}
AlexWaygood marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,139 @@ ISC.py:73:20: ISC001 [*] Implicitly concatenated string literals on one line
75 75 | f"def"} g"
76 76 |

ISC.py:84:5: ISC001 [*] Implicitly concatenated string literals on one line
|
83 | # See https://github.com/astral-sh/ruff/issues/12936
84 | _ = "\12""0" # fix should be "\0120"
| ^^^^^^^^ ISC001
85 | _ = "\\12""0" # fix should be "\\120"
86 | _ = "\\\12""0" # fix should be "\\\0120"
|
= help: Combine string literals

ℹ Safe fix
81 81 | + f"second"} d"
82 82 |
83 83 | # See https://github.com/astral-sh/ruff/issues/12936
84 |-_ = "\12""0" # fix should be "\0120"
84 |+_ = "\0120" # fix should be "\0120"
85 85 | _ = "\\12""0" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"

ISC.py:85:5: ISC001 [*] Implicitly concatenated string literals on one line
|
83 | # See https://github.com/astral-sh/ruff/issues/12936
84 | _ = "\12""0" # fix should be "\0120"
85 | _ = "\\12""0" # fix should be "\\120"
| ^^^^^^^^^ ISC001
86 | _ = "\\\12""0" # fix should be "\\\0120"
87 | _ = "\12 0""0" # fix should be "\12 00"
|
= help: Combine string literals

ℹ Safe fix
82 82 |
83 83 | # See https://github.com/astral-sh/ruff/issues/12936
84 84 | _ = "\12""0" # fix should be "\0120"
85 |-_ = "\\12""0" # fix should be "\\120"
85 |+_ = "\\120" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"

ISC.py:86:5: ISC001 [*] Implicitly concatenated string literals on one line
|
84 | _ = "\12""0" # fix should be "\0120"
85 | _ = "\\12""0" # fix should be "\\120"
86 | _ = "\\\12""0" # fix should be "\\\0120"
| ^^^^^^^^^^ ISC001
87 | _ = "\12 0""0" # fix should be "\12 00"
88 | _ = r"\12"r"0" # fix should be r"\120"
|
= help: Combine string literals

ℹ Safe fix
83 83 | # See https://github.com/astral-sh/ruff/issues/12936
84 84 | _ = "\12""0" # fix should be "\0120"
85 85 | _ = "\\12""0" # fix should be "\\120"
86 |-_ = "\\\12""0" # fix should be "\\\0120"
86 |+_ = "\\\0120" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"

ISC.py:87:5: ISC001 [*] Implicitly concatenated string literals on one line
|
85 | _ = "\\12""0" # fix should be "\\120"
86 | _ = "\\\12""0" # fix should be "\\\0120"
87 | _ = "\12 0""0" # fix should be "\12 00"
| ^^^^^^^^^^ ISC001
88 | _ = r"\12"r"0" # fix should be r"\120"
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
|
= help: Combine string literals

ℹ Safe fix
84 84 | _ = "\12""0" # fix should be "\0120"
85 85 | _ = "\\12""0" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 |-_ = "\12 0""0" # fix should be "\12 00"
87 |+_ = "\12 00" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 90 | _ = "\8""0" # fix should be "\80"

ISC.py:88:5: ISC001 [*] Implicitly concatenated string literals on one line
|
86 | _ = "\\\12""0" # fix should be "\\\0120"
87 | _ = "\12 0""0" # fix should be "\12 00"
88 | _ = r"\12"r"0" # fix should be r"\120"
| ^^^^^^^^^^ ISC001
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 | _ = "\8""0" # fix should be "\80"
|
= help: Combine string literals

ℹ Safe fix
85 85 | _ = "\\12""0" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 |-_ = r"\12"r"0" # fix should be r"\120"
88 |+_ = r"\120" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 90 | _ = "\8""0" # fix should be "\80"

ISC.py:89:5: ISC001 [*] Implicitly concatenated string literals on one line
|
87 | _ = "\12 0""0" # fix should be "\12 00"
88 | _ = r"\12"r"0" # fix should be r"\120"
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
| ^^^^^^^^^^^^^^^^^ ISC001
90 | _ = "\8""0" # fix should be "\80"
|
= help: Combine string literals

ℹ Safe fix
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 |-_ = "\12 and more""0" # fix should be "\12 and more0"
89 |+_ = "\12 and more0" # fix should be "\12 and more0"
90 90 | _ = "\8""0" # fix should be "\80"

ISC.py:90:5: ISC001 [*] Implicitly concatenated string literals on one line
|
88 | _ = r"\12"r"0" # fix should be r"\120"
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 | _ = "\8""0" # fix should be "\80"
| ^^^^^^^ ISC001
|
= help: Combine string literals

ℹ Safe fix
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 |-_ = "\8""0" # fix should be "\80"
90 |+_ = "\80" # fix should be "\80"
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ ISC.py:80:10: ISC003 Explicitly concatenated string should be implicitly concate
| __________^
81 | | + f"second"} d"
| |_______________^ ISC003
82 |
83 | # See https://github.com/astral-sh/ruff/issues/12936
|


Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,139 @@ ISC.py:73:20: ISC001 [*] Implicitly concatenated string literals on one line
75 75 | f"def"} g"
76 76 |

ISC.py:84:5: ISC001 [*] Implicitly concatenated string literals on one line
|
83 | # See https://github.com/astral-sh/ruff/issues/12936
84 | _ = "\12""0" # fix should be "\0120"
| ^^^^^^^^ ISC001
85 | _ = "\\12""0" # fix should be "\\120"
86 | _ = "\\\12""0" # fix should be "\\\0120"
|
= help: Combine string literals

ℹ Safe fix
81 81 | + f"second"} d"
82 82 |
83 83 | # See https://github.com/astral-sh/ruff/issues/12936
84 |-_ = "\12""0" # fix should be "\0120"
84 |+_ = "\0120" # fix should be "\0120"
85 85 | _ = "\\12""0" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"

ISC.py:85:5: ISC001 [*] Implicitly concatenated string literals on one line
|
83 | # See https://github.com/astral-sh/ruff/issues/12936
84 | _ = "\12""0" # fix should be "\0120"
85 | _ = "\\12""0" # fix should be "\\120"
| ^^^^^^^^^ ISC001
86 | _ = "\\\12""0" # fix should be "\\\0120"
87 | _ = "\12 0""0" # fix should be "\12 00"
|
= help: Combine string literals

ℹ Safe fix
82 82 |
83 83 | # See https://github.com/astral-sh/ruff/issues/12936
84 84 | _ = "\12""0" # fix should be "\0120"
85 |-_ = "\\12""0" # fix should be "\\120"
85 |+_ = "\\120" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"

ISC.py:86:5: ISC001 [*] Implicitly concatenated string literals on one line
|
84 | _ = "\12""0" # fix should be "\0120"
85 | _ = "\\12""0" # fix should be "\\120"
86 | _ = "\\\12""0" # fix should be "\\\0120"
| ^^^^^^^^^^ ISC001
87 | _ = "\12 0""0" # fix should be "\12 00"
88 | _ = r"\12"r"0" # fix should be r"\120"
|
= help: Combine string literals

ℹ Safe fix
83 83 | # See https://github.com/astral-sh/ruff/issues/12936
84 84 | _ = "\12""0" # fix should be "\0120"
85 85 | _ = "\\12""0" # fix should be "\\120"
86 |-_ = "\\\12""0" # fix should be "\\\0120"
86 |+_ = "\\\0120" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"

ISC.py:87:5: ISC001 [*] Implicitly concatenated string literals on one line
|
85 | _ = "\\12""0" # fix should be "\\120"
86 | _ = "\\\12""0" # fix should be "\\\0120"
87 | _ = "\12 0""0" # fix should be "\12 00"
| ^^^^^^^^^^ ISC001
88 | _ = r"\12"r"0" # fix should be r"\120"
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
|
= help: Combine string literals

ℹ Safe fix
84 84 | _ = "\12""0" # fix should be "\0120"
85 85 | _ = "\\12""0" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 |-_ = "\12 0""0" # fix should be "\12 00"
87 |+_ = "\12 00" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 90 | _ = "\8""0" # fix should be "\80"

ISC.py:88:5: ISC001 [*] Implicitly concatenated string literals on one line
|
86 | _ = "\\\12""0" # fix should be "\\\0120"
87 | _ = "\12 0""0" # fix should be "\12 00"
88 | _ = r"\12"r"0" # fix should be r"\120"
| ^^^^^^^^^^ ISC001
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 | _ = "\8""0" # fix should be "\80"
|
= help: Combine string literals

ℹ Safe fix
85 85 | _ = "\\12""0" # fix should be "\\120"
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 |-_ = r"\12"r"0" # fix should be r"\120"
88 |+_ = r"\120" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 90 | _ = "\8""0" # fix should be "\80"

ISC.py:89:5: ISC001 [*] Implicitly concatenated string literals on one line
|
87 | _ = "\12 0""0" # fix should be "\12 00"
88 | _ = r"\12"r"0" # fix should be r"\120"
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
| ^^^^^^^^^^^^^^^^^ ISC001
90 | _ = "\8""0" # fix should be "\80"
|
= help: Combine string literals

ℹ Safe fix
86 86 | _ = "\\\12""0" # fix should be "\\\0120"
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 |-_ = "\12 and more""0" # fix should be "\12 and more0"
89 |+_ = "\12 and more0" # fix should be "\12 and more0"
90 90 | _ = "\8""0" # fix should be "\80"

ISC.py:90:5: ISC001 [*] Implicitly concatenated string literals on one line
|
88 | _ = r"\12"r"0" # fix should be r"\120"
89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 | _ = "\8""0" # fix should be "\80"
| ^^^^^^^ ISC001
|
= help: Combine string literals

ℹ Safe fix
87 87 | _ = "\12 0""0" # fix should be "\12 00"
88 88 | _ = r"\12"r"0" # fix should be r"\120"
89 89 | _ = "\12 and more""0" # fix should be "\12 and more0"
90 |-_ = "\8""0" # fix should be "\80"
90 |+_ = "\80" # fix should be "\80"
Loading