mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 06:41:23 +00:00
Correct quick fix message for W605
(#8255)
## Summary This PR fixes the `W605` rule implementation to provide the quickfix message as per the fix provided. ## Test Plan Update snapshots. fixes: #8155
This commit is contained in:
parent
a4dd1e5fad
commit
4ffd4ed61f
4 changed files with 88 additions and 38 deletions
|
@ -5,7 +5,7 @@ use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_index::Indexer;
|
use ruff_python_index::Indexer;
|
||||||
use ruff_python_parser::Tok;
|
use ruff_python_parser::Tok;
|
||||||
use ruff_source_file::Locator;
|
use ruff_source_file::Locator;
|
||||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||||
|
|
||||||
use crate::fix::edits::pad_start;
|
use crate::fix::edits::pad_start;
|
||||||
|
|
||||||
|
@ -25,22 +25,50 @@ use crate::fix::edits::pad_start;
|
||||||
/// regex = r"\.png$"
|
/// regex = r"\.png$"
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Or, if the string already contains a valid escape sequence:
|
||||||
|
/// ```python
|
||||||
|
/// value = "new line\nand invalid escape \_ here"
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// value = "new line\nand invalid escape \\_ here"
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// ## References
|
/// ## References
|
||||||
/// - [Python documentation: String and Bytes literals](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)
|
/// - [Python documentation: String and Bytes literals](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct InvalidEscapeSequence(char);
|
pub struct InvalidEscapeSequence {
|
||||||
|
ch: char,
|
||||||
|
fix_title: FixTitle,
|
||||||
|
}
|
||||||
|
|
||||||
impl AlwaysFixableViolation for InvalidEscapeSequence {
|
impl AlwaysFixableViolation for InvalidEscapeSequence {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
let InvalidEscapeSequence(char) = self;
|
let InvalidEscapeSequence { ch, .. } = self;
|
||||||
format!("Invalid escape sequence: `\\{char}`")
|
format!("Invalid escape sequence: `\\{ch}`")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_title(&self) -> String {
|
fn fix_title(&self) -> String {
|
||||||
"Add backslash to escape sequence".to_string()
|
match self.fix_title {
|
||||||
|
FixTitle::AddBackslash => format!("Add backslash to escape sequence"),
|
||||||
|
FixTitle::UseRawStringLiteral => format!("Use a raw string literal"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum FixTitle {
|
||||||
|
AddBackslash,
|
||||||
|
UseRawStringLiteral,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct InvalidEscapeChar {
|
||||||
|
ch: char,
|
||||||
|
range: TextRange,
|
||||||
|
}
|
||||||
|
|
||||||
/// W605
|
/// W605
|
||||||
pub(crate) fn invalid_escape_sequence(
|
pub(crate) fn invalid_escape_sequence(
|
||||||
|
@ -67,7 +95,7 @@ pub(crate) fn invalid_escape_sequence(
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut contains_valid_escape_sequence = false;
|
let mut contains_valid_escape_sequence = false;
|
||||||
let mut invalid_escape_sequence = Vec::new();
|
let mut invalid_escape_chars = Vec::new();
|
||||||
|
|
||||||
let mut prev = None;
|
let mut prev = None;
|
||||||
let bytes = token_source_code.as_bytes();
|
let bytes = token_source_code.as_bytes();
|
||||||
|
@ -154,16 +182,28 @@ pub(crate) fn invalid_escape_sequence(
|
||||||
|
|
||||||
let location = token_range.start() + TextSize::try_from(i).unwrap();
|
let location = token_range.start() + TextSize::try_from(i).unwrap();
|
||||||
let range = TextRange::at(location, next_char.text_len() + TextSize::from(1));
|
let range = TextRange::at(location, next_char.text_len() + TextSize::from(1));
|
||||||
invalid_escape_sequence.push(Diagnostic::new(InvalidEscapeSequence(next_char), range));
|
invalid_escape_chars.push(InvalidEscapeChar {
|
||||||
|
ch: next_char,
|
||||||
|
range,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut invalid_escape_sequence = Vec::new();
|
||||||
if contains_valid_escape_sequence {
|
if contains_valid_escape_sequence {
|
||||||
// Escape with backslash.
|
// Escape with backslash.
|
||||||
for diagnostic in &mut invalid_escape_sequence {
|
for invalid_escape_char in &invalid_escape_chars {
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
let diagnostic = Diagnostic::new(
|
||||||
|
InvalidEscapeSequence {
|
||||||
|
ch: invalid_escape_char.ch,
|
||||||
|
fix_title: FixTitle::AddBackslash,
|
||||||
|
},
|
||||||
|
invalid_escape_char.range,
|
||||||
|
)
|
||||||
|
.with_fix(Fix::safe_edit(Edit::insertion(
|
||||||
r"\".to_string(),
|
r"\".to_string(),
|
||||||
diagnostic.start() + TextSize::from(1),
|
invalid_escape_char.range.start() + TextSize::from(1),
|
||||||
)));
|
)));
|
||||||
|
invalid_escape_sequence.push(diagnostic);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let tok_start = if token.is_f_string_middle() {
|
let tok_start = if token.is_f_string_middle() {
|
||||||
|
@ -178,14 +218,24 @@ pub(crate) fn invalid_escape_sequence(
|
||||||
token_range.start()
|
token_range.start()
|
||||||
};
|
};
|
||||||
// Turn into raw string.
|
// Turn into raw string.
|
||||||
for diagnostic in &mut invalid_escape_sequence {
|
for invalid_escape_char in &invalid_escape_chars {
|
||||||
|
let diagnostic = Diagnostic::new(
|
||||||
|
InvalidEscapeSequence {
|
||||||
|
ch: invalid_escape_char.ch,
|
||||||
|
fix_title: FixTitle::UseRawStringLiteral,
|
||||||
|
},
|
||||||
|
invalid_escape_char.range,
|
||||||
|
)
|
||||||
|
.with_fix(
|
||||||
// If necessary, add a space between any leading keyword (`return`, `yield`,
|
// If necessary, add a space between any leading keyword (`return`, `yield`,
|
||||||
// `assert`, etc.) and the string. For example, `return"foo"` is valid, but
|
// `assert`, etc.) and the string. For example, `return"foo"` is valid, but
|
||||||
// `returnr"foo"` is not.
|
// `returnr"foo"` is not.
|
||||||
diagnostic.set_fix(Fix::safe_edit(Edit::insertion(
|
Fix::safe_edit(Edit::insertion(
|
||||||
pad_start("r".to_string(), tok_start, locator),
|
pad_start("r".to_string(), tok_start, locator),
|
||||||
tok_start,
|
tok_start,
|
||||||
)));
|
)),
|
||||||
|
);
|
||||||
|
invalid_escape_sequence.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ W605_0.py:2:10: W605 [*] Invalid escape sequence: `\.`
|
||||||
3 |
|
3 |
|
||||||
4 | #: W605:2:1
|
4 | #: W605:2:1
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
1 1 | #: W605:1:10
|
1 1 | #: W605:1:10
|
||||||
|
@ -27,7 +27,7 @@ W605_0.py:6:1: W605 [*] Invalid escape sequence: `\.`
|
||||||
| ^^ W605
|
| ^^ W605
|
||||||
7 | '''
|
7 | '''
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
2 2 | regex = '\.png$'
|
2 2 | regex = '\.png$'
|
||||||
|
@ -47,7 +47,7 @@ W605_0.py:11:6: W605 [*] Invalid escape sequence: `\_`
|
||||||
| ^^ W605
|
| ^^ W605
|
||||||
12 | )
|
12 | )
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
8 8 |
|
8 8 |
|
||||||
|
@ -68,7 +68,7 @@ W605_0.py:18:6: W605 [*] Invalid escape sequence: `\_`
|
||||||
19 | in the middle
|
19 | in the middle
|
||||||
20 | """
|
20 | """
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
12 12 | )
|
12 12 | )
|
||||||
|
@ -107,7 +107,7 @@ W605_0.py:28:12: W605 [*] Invalid escape sequence: `\.`
|
||||||
29 |
|
29 |
|
||||||
30 | #: Okay
|
30 | #: Okay
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
25 25 |
|
25 25 |
|
||||||
|
|
|
@ -9,7 +9,7 @@ W605_1.py:2:10: W605 [*] Invalid escape sequence: `\.`
|
||||||
3 |
|
3 |
|
||||||
4 | #: W605:2:1
|
4 | #: W605:2:1
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
1 1 | #: W605:1:10
|
1 1 | #: W605:1:10
|
||||||
|
@ -27,7 +27,7 @@ W605_1.py:6:1: W605 [*] Invalid escape sequence: `\.`
|
||||||
| ^^ W605
|
| ^^ W605
|
||||||
7 | '''
|
7 | '''
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
2 2 | regex = '\.png$'
|
2 2 | regex = '\.png$'
|
||||||
|
@ -47,7 +47,7 @@ W605_1.py:11:6: W605 [*] Invalid escape sequence: `\_`
|
||||||
| ^^ W605
|
| ^^ W605
|
||||||
12 | )
|
12 | )
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
8 8 |
|
8 8 |
|
||||||
|
@ -68,7 +68,7 @@ W605_1.py:18:6: W605 [*] Invalid escape sequence: `\_`
|
||||||
19 | in the middle
|
19 | in the middle
|
||||||
20 | """
|
20 | """
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
12 12 | )
|
12 12 | )
|
||||||
|
@ -89,7 +89,7 @@ W605_1.py:25:12: W605 [*] Invalid escape sequence: `\.`
|
||||||
26 |
|
26 |
|
||||||
27 | #: Okay
|
27 | #: Okay
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
22 22 |
|
22 22 |
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff/src/rules/pycodestyle/mod.rs
|
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
|
||||||
---
|
---
|
||||||
W605_2.py:4:11: W605 [*] Invalid escape sequence: `\.`
|
W605_2.py:4:11: W605 [*] Invalid escape sequence: `\.`
|
||||||
|
|
|
|
||||||
|
@ -9,7 +9,7 @@ W605_2.py:4:11: W605 [*] Invalid escape sequence: `\.`
|
||||||
5 |
|
5 |
|
||||||
6 | #: W605:2:1
|
6 | #: W605:2:1
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
1 1 | # Same as `W605_0.py` but using f-strings instead.
|
1 1 | # Same as `W605_0.py` but using f-strings instead.
|
||||||
|
@ -29,7 +29,7 @@ W605_2.py:8:1: W605 [*] Invalid escape sequence: `\.`
|
||||||
| ^^ W605
|
| ^^ W605
|
||||||
9 | '''
|
9 | '''
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
4 4 | regex = f'\.png$'
|
4 4 | regex = f'\.png$'
|
||||||
|
@ -49,7 +49,7 @@ W605_2.py:13:7: W605 [*] Invalid escape sequence: `\_`
|
||||||
| ^^ W605
|
| ^^ W605
|
||||||
14 | )
|
14 | )
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
10 10 |
|
10 10 |
|
||||||
|
@ -70,7 +70,7 @@ W605_2.py:20:6: W605 [*] Invalid escape sequence: `\_`
|
||||||
21 | in the middle
|
21 | in the middle
|
||||||
22 | """
|
22 | """
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
14 14 | )
|
14 14 | )
|
||||||
|
@ -129,7 +129,7 @@ W605_2.py:44:11: W605 [*] Invalid escape sequence: `\{`
|
||||||
45 | value = f'\{1}'
|
45 | value = f'\{1}'
|
||||||
46 | value = f'{1:\}'
|
46 | value = f'{1:\}'
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
41 41 | ''' # noqa
|
41 41 | ''' # noqa
|
||||||
|
@ -150,7 +150,7 @@ W605_2.py:45:11: W605 [*] Invalid escape sequence: `\{`
|
||||||
46 | value = f'{1:\}'
|
46 | value = f'{1:\}'
|
||||||
47 | value = f"{f"\{1}"}"
|
47 | value = f"{f"\{1}"}"
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
42 42 |
|
42 42 |
|
||||||
|
@ -171,7 +171,7 @@ W605_2.py:46:14: W605 [*] Invalid escape sequence: `\}`
|
||||||
47 | value = f"{f"\{1}"}"
|
47 | value = f"{f"\{1}"}"
|
||||||
48 | value = rf"{f"\{1}"}"
|
48 | value = rf"{f"\{1}"}"
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
43 43 | regex = f'\\\_'
|
43 43 | regex = f'\\\_'
|
||||||
|
@ -191,7 +191,7 @@ W605_2.py:47:14: W605 [*] Invalid escape sequence: `\{`
|
||||||
| ^^ W605
|
| ^^ W605
|
||||||
48 | value = rf"{f"\{1}"}"
|
48 | value = rf"{f"\{1}"}"
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
44 44 | value = f'\{{1}}'
|
44 44 | value = f'\{{1}}'
|
||||||
|
@ -212,7 +212,7 @@ W605_2.py:48:15: W605 [*] Invalid escape sequence: `\{`
|
||||||
49 |
|
49 |
|
||||||
50 | # Okay
|
50 | # Okay
|
||||||
|
|
|
|
||||||
= help: Add backslash to escape sequence
|
= help: Use a raw string literal
|
||||||
|
|
||||||
ℹ Fix
|
ℹ Fix
|
||||||
45 45 | value = f'\{1}'
|
45 45 | value = f'\{1}'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue