From 091f845c687c554aaaf2ea81b1491308e1b0c964 Mon Sep 17 00:00:00 2001 From: konstin Date: Sun, 1 Oct 2023 17:30:31 +0200 Subject: [PATCH] Fix PLE251 rules with f-string escaping **Summary** The `value` of the `FStringMiddle` for `f"""}}ab"""` is `}ab`, i.e. the curly brace escaping is decoded. If we iterate over string this gives us false indices causing exploding fixes for PLE251 rules (PLE2510, PLE2512, PLE2513, PLE2514, PLE2515). Instead, we now use the source range. Handles https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 Handles https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998256 **Test Plan** Minimized fuzzing cases as fixtures. --- .../fixtures/pylint/invalid_characters.py | Bin 1461 -> 1639 bytes .../pylint/rules/invalid_string_characters.rs | 4 ++- ..._tests__PLE2510_invalid_characters.py.snap | 5 ++++ ..._tests__PLE2512_invalid_characters.py.snap | 24 ++++++++++++++++++ ..._tests__PLE2513_invalid_characters.py.snap | 21 +++++++++++++++ ..._tests__PLE2515_invalid_characters.py.snap | 2 ++ 6 files changed, 55 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/invalid_characters.py b/crates/ruff_linter/resources/test/fixtures/pylint/invalid_characters.py index e1864fa38175502c3dcdc92b2b38f0d924a1cb34..79c9307695a9153b9945e2976c45335259630bfa 100644 GIT binary patch delta 187 zcmdnW{hVjRR@QnhWrd8Al7eC@ef{*zl8n+Mz2y8{{lwyuqQo5C;tc(w(zG=F%;MtG z)M9;e6H`-VFdL{QH#M(B*U;R=(9+Vv(7=qVLcvxcO-V_qwl+~J2}l!XurUFXjZ9HY ImIj#&00n(J$p8QV delta 7 OcmaFPvz2?pR#pHF)B_#> diff --git a/crates/ruff_linter/src/rules/pylint/rules/invalid_string_characters.rs b/crates/ruff_linter/src/rules/pylint/rules/invalid_string_characters.rs index 5c00ef89a1b6c..ca4681d7867d3 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/invalid_string_characters.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/invalid_string_characters.rs @@ -180,7 +180,9 @@ pub(crate) fn invalid_string_characters( ) { let text = match tok { Tok::String { .. } => locator.slice(range), - Tok::FStringMiddle { value, .. } => value.as_str(), + // The string value has already decoded escaped curly braces, which would gives us wrong + // column information + Tok::FStringMiddle { .. } => &locator.contents()[range], _ => return, }; diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2510_invalid_characters.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2510_invalid_characters.py.snap index 25e9c12e479f0..b472b75871aa3 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2510_invalid_characters.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2510_invalid_characters.py.snap @@ -48,6 +48,8 @@ invalid_characters.py:55:21: PLE2510 [*] Invalid unescaped character backspace, 54 | 55 | nested_fstrings = f'{f'{f''}'}' | PLE2510 +56 | +57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 | = help: Replace with escape sequence @@ -57,5 +59,8 @@ invalid_characters.py:55:21: PLE2510 [*] Invalid unescaped character backspace, 54 54 | 55 |-nested_fstrings = f'{f'{f''}'}' 55 |+nested_fstrings = f'\b{f'{f''}'}' +56 56 | +57 57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 +58 58 | x = f"""}}ab""" diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2512_invalid_characters.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2512_invalid_characters.py.snap index efda03729de47..aca79fabc8ff7 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2512_invalid_characters.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2512_invalid_characters.py.snap @@ -47,6 +47,8 @@ invalid_characters.py:55:25: PLE2512 [*] Invalid unescaped character SUB, use "\ 54 | 55 | nested_fstrings = f'{f'{f''}'}' | PLE2512 +56 | +57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 | = help: Replace with escape sequence @@ -56,5 +58,27 @@ invalid_characters.py:55:25: PLE2512 [*] Invalid unescaped character SUB, use "\ 54 54 | 55 |-nested_fstrings = f'{f'{f''}'}' 55 |+nested_fstrings = f'{f'\x1A{f''}'}' +56 56 | +57 57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 +58 58 | x = f"""}}ab""" + +invalid_characters.py:58:12: PLE2512 [*] Invalid unescaped character SUB, use "\x1A" instead + | +57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 +58 | x = f"""}}ab""" + | PLE2512 +59 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998256 +60 | x = f"""}}ab""" + | + = help: Replace with escape sequence + +ℹ Fix +55 55 | nested_fstrings = f'{f'{f''}'}' +56 56 | +57 57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 +58 |-x = f"""}}ab""" + 58 |+x = f"""}}a\x1Ab""" +59 59 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998256 +60 60 | x = f"""}}ab""" diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2513_invalid_characters.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2513_invalid_characters.py.snap index fbfd76cfa23a8..87dd00ef5196c 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2513_invalid_characters.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2513_invalid_characters.py.snap @@ -47,6 +47,8 @@ invalid_characters.py:55:29: PLE2513 [*] Invalid unescaped character ESC, use "\ 54 | 55 | nested_fstrings = f'{f'{f''}'}' | PLE2513 +56 | +57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 | = help: Replace with escape sequence @@ -56,5 +58,24 @@ invalid_characters.py:55:29: PLE2513 [*] Invalid unescaped character ESC, use "\ 54 54 | 55 |-nested_fstrings = f'{f'{f''}'}' 55 |+nested_fstrings = f'{f'{f'\x1B'}'}' +56 56 | +57 57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 +58 58 | x = f"""}}ab""" + +invalid_characters.py:60:12: PLE2513 [*] Invalid unescaped character ESC, use "\x1B" instead + | +58 | x = f"""}}ab""" +59 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998256 +60 | x = f"""}}ab""" + | PLE2513 + | + = help: Replace with escape sequence + +ℹ Fix +57 57 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998106 +58 58 | x = f"""}}ab""" +59 59 | # https://github.com/astral-sh/ruff/issues/7455#issuecomment-1741998256 +60 |-x = f"""}}ab""" + 60 |+x = f"""}}a\x1Bb""" diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2515_invalid_characters.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2515_invalid_characters.py.snap index 3a9ba051eea5a..7ef2c89169ac7 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2515_invalid_characters.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLE2515_invalid_characters.py.snap @@ -141,6 +141,7 @@ invalid_characters.py:53:61: PLE2515 [*] Invalid unescaped character zero-width- 53 |+zwsp_after_multicharacter_grapheme_cluster = f"ಫ್ರಾನ್ಸಿಸ್ಕೊ \u200b​" 54 54 | 55 55 | nested_fstrings = f'{f'{f''}'}' +56 56 | invalid_characters.py:53:62: PLE2515 [*] Invalid unescaped character zero-width-space, use "\u200B" instead | @@ -161,5 +162,6 @@ invalid_characters.py:53:62: PLE2515 [*] Invalid unescaped character zero-width- 53 |+zwsp_after_multicharacter_grapheme_cluster = f"ಫ್ರಾನ್ಸಿಸ್ಕೊ ​\u200b" 54 54 | 55 55 | nested_fstrings = f'{f'{f''}'}' +56 56 |