mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 06:41:23 +00:00
[RUF021]: Add an autofix (#9449)
## Summary This adds an autofix for the newly added RUF021 (see #9440).
This commit is contained in:
parent
ad1ca72a35
commit
6be73322da
3 changed files with 249 additions and 49 deletions
|
@ -10,6 +10,7 @@
|
|||
|
||||
a, b, c = 1, 0, 2
|
||||
x = a or b and c # RUF021: => `a or (b and c)`
|
||||
x = a or b and c # looooooooooooooooooooooooooooooong comment but it won't prevent an autofix
|
||||
|
||||
a, b, c = 0, 1, 2
|
||||
y = a and b or c # RUF021: => `(a and b) or c`
|
||||
|
@ -30,7 +31,8 @@ while a and b or c and d: # RUF021: => `(and b) or (c and d)`
|
|||
pass
|
||||
|
||||
b, c, d, e = 2, 3, 0, 4
|
||||
z = [a for a in range(5) if a or b or c or d and e] # RUF021: => `a or b or c or (d and e)`
|
||||
# RUF021: => `a or b or c or (d and e)`:
|
||||
z = [a for a in range(5) if a or b or c or d and e]
|
||||
|
||||
a, b, c, d = 0, 1, 3, 0
|
||||
assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
|
@ -39,6 +41,20 @@ if (not a) and b or c or d: # RUF021: => `((not a) and b) or c or d`
|
|||
if (not a and b) or c or d: # OK
|
||||
pass
|
||||
|
||||
if (
|
||||
some_reasonably_long_condition
|
||||
or some_other_reasonably_long_condition
|
||||
and some_third_reasonably_long_condition
|
||||
or some_fourth_reasonably_long_condition
|
||||
and some_fifth_reasonably_long_condition
|
||||
# a commment
|
||||
and some_sixth_reasonably_long_condition
|
||||
and some_seventh_reasonably_long_condition
|
||||
# another comment
|
||||
or some_eighth_reasonably_long_condition
|
||||
):
|
||||
pass
|
||||
|
||||
#############################################
|
||||
# If they're all the same operator, it's fine
|
||||
#############################################
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||
|
@ -36,13 +36,17 @@ use crate::checkers::ast::Checker;
|
|||
#[violation]
|
||||
pub struct ParenthesizeChainedOperators;
|
||||
|
||||
impl Violation for ParenthesizeChainedOperators {
|
||||
impl AlwaysFixableViolation for ParenthesizeChainedOperators {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
"Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear"
|
||||
)
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> String {
|
||||
"Parenthesize the `and` subexpression".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// RUF021
|
||||
|
@ -75,18 +79,22 @@ pub(crate) fn parenthesize_chained_logical_operators(
|
|||
..
|
||||
},
|
||||
) => {
|
||||
let locator = checker.locator();
|
||||
let source_range = bool_op.range();
|
||||
if parenthesized_range(
|
||||
bool_op.into(),
|
||||
expr.into(),
|
||||
checker.indexer().comment_ranges(),
|
||||
checker.locator().contents(),
|
||||
locator.contents(),
|
||||
)
|
||||
.is_none()
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
ParenthesizeChainedOperators,
|
||||
bool_op.range(),
|
||||
));
|
||||
let new_source = format!("({})", locator.slice(source_range));
|
||||
let edit = Edit::range_replacement(new_source, source_range);
|
||||
checker.diagnostics.push(
|
||||
Diagnostic::new(ParenthesizeChainedOperators, source_range)
|
||||
.with_fix(Fix::safe_edit(edit)),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
|
|
|
@ -1,83 +1,259 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||
---
|
||||
RUF021.py:12:10: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
RUF021.py:12:10: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
11 | a, b, c = 1, 0, 2
|
||||
12 | x = a or b and c # RUF021: => `a or (b and c)`
|
||||
| ^^^^^^^ RUF021
|
||||
13 |
|
||||
14 | a, b, c = 0, 1, 2
|
||||
13 | x = a or b and c # looooooooooooooooooooooooooooooong comment but it won't prevent an autofix
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:15:5: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
9 9 | # as part of a chain.
|
||||
10 10 |
|
||||
11 11 | a, b, c = 1, 0, 2
|
||||
12 |-x = a or b and c # RUF021: => `a or (b and c)`
|
||||
12 |+x = a or (b and c) # RUF021: => `a or (b and c)`
|
||||
13 13 | x = a or b and c # looooooooooooooooooooooooooooooong comment but it won't prevent an autofix
|
||||
14 14 |
|
||||
15 15 | a, b, c = 0, 1, 2
|
||||
|
||||
RUF021.py:13:10: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
14 | a, b, c = 0, 1, 2
|
||||
15 | y = a and b or c # RUF021: => `(a and b) or c`
|
||||
11 | a, b, c = 1, 0, 2
|
||||
12 | x = a or b and c # RUF021: => `a or (b and c)`
|
||||
13 | x = a or b and c # looooooooooooooooooooooooooooooong comment but it won't prevent an autofix
|
||||
| ^^^^^^^ RUF021
|
||||
16 |
|
||||
17 | a, b, c, d = 1, 2, 0, 3
|
||||
14 |
|
||||
15 | a, b, c = 0, 1, 2
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:18:14: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
10 10 |
|
||||
11 11 | a, b, c = 1, 0, 2
|
||||
12 12 | x = a or b and c # RUF021: => `a or (b and c)`
|
||||
13 |-x = a or b and c # looooooooooooooooooooooooooooooong comment but it won't prevent an autofix
|
||||
13 |+x = a or (b and c) # looooooooooooooooooooooooooooooong comment but it won't prevent an autofix
|
||||
14 14 |
|
||||
15 15 | a, b, c = 0, 1, 2
|
||||
16 16 | y = a and b or c # RUF021: => `(a and b) or c`
|
||||
|
||||
RUF021.py:16:5: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
17 | a, b, c, d = 1, 2, 0, 3
|
||||
18 | if a or b or c and d: # RUF021: => `a or b or (c and d)`
|
||||
15 | a, b, c = 0, 1, 2
|
||||
16 | y = a and b or c # RUF021: => `(a and b) or c`
|
||||
| ^^^^^^^ RUF021
|
||||
19 | pass
|
||||
17 |
|
||||
18 | a, b, c, d = 1, 2, 0, 3
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:25:11: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
13 13 | x = a or b and c # looooooooooooooooooooooooooooooong comment but it won't prevent an autofix
|
||||
14 14 |
|
||||
15 15 | a, b, c = 0, 1, 2
|
||||
16 |-y = a and b or c # RUF021: => `(a and b) or c`
|
||||
16 |+y = (a and b) or c # RUF021: => `(a and b) or c`
|
||||
17 17 |
|
||||
18 18 | a, b, c, d = 1, 2, 0, 3
|
||||
19 19 | if a or b or c and d: # RUF021: => `a or b or (c and d)`
|
||||
|
||||
RUF021.py:19:14: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
23 | if bool():
|
||||
24 | pass
|
||||
25 | elif a or b and c or d: # RUF021: => `a or (b and c) or d`
|
||||
18 | a, b, c, d = 1, 2, 0, 3
|
||||
19 | if a or b or c and d: # RUF021: => `a or b or (c and d)`
|
||||
| ^^^^^^^ RUF021
|
||||
26 | pass
|
||||
20 | pass
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:29:7: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
16 16 | y = a and b or c # RUF021: => `(a and b) or c`
|
||||
17 17 |
|
||||
18 18 | a, b, c, d = 1, 2, 0, 3
|
||||
19 |-if a or b or c and d: # RUF021: => `a or b or (c and d)`
|
||||
19 |+if a or b or (c and d): # RUF021: => `a or b or (c and d)`
|
||||
20 20 | pass
|
||||
21 21 |
|
||||
22 22 | a, b, c, d = 0, 0, 2, 3
|
||||
|
||||
RUF021.py:26:11: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
28 | a, b, c, d = 0, 1, 0, 2
|
||||
29 | while a and b or c and d: # RUF021: => `(and b) or (c and d)`
|
||||
24 | if bool():
|
||||
25 | pass
|
||||
26 | elif a or b and c or d: # RUF021: => `a or (b and c) or d`
|
||||
| ^^^^^^^ RUF021
|
||||
30 | pass
|
||||
27 | pass
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:29:18: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
23 23 |
|
||||
24 24 | if bool():
|
||||
25 25 | pass
|
||||
26 |-elif a or b and c or d: # RUF021: => `a or (b and c) or d`
|
||||
26 |+elif a or (b and c) or d: # RUF021: => `a or (b and c) or d`
|
||||
27 27 | pass
|
||||
28 28 |
|
||||
29 29 | a, b, c, d = 0, 1, 0, 2
|
||||
|
||||
RUF021.py:30:7: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
28 | a, b, c, d = 0, 1, 0, 2
|
||||
29 | while a and b or c and d: # RUF021: => `(and b) or (c and d)`
|
||||
29 | a, b, c, d = 0, 1, 0, 2
|
||||
30 | while a and b or c and d: # RUF021: => `(and b) or (c and d)`
|
||||
| ^^^^^^^ RUF021
|
||||
30 | pass
|
||||
31 | pass
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:33:44: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
27 27 | pass
|
||||
28 28 |
|
||||
29 29 | a, b, c, d = 0, 1, 0, 2
|
||||
30 |-while a and b or c and d: # RUF021: => `(and b) or (c and d)`
|
||||
30 |+while (a and b) or c and d: # RUF021: => `(and b) or (c and d)`
|
||||
31 31 | pass
|
||||
32 32 |
|
||||
33 33 | b, c, d, e = 2, 3, 0, 4
|
||||
|
||||
RUF021.py:30:18: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
32 | b, c, d, e = 2, 3, 0, 4
|
||||
33 | z = [a for a in range(5) if a or b or c or d and e] # RUF021: => `a or b or c or (d and e)`
|
||||
29 | a, b, c, d = 0, 1, 0, 2
|
||||
30 | while a and b or c and d: # RUF021: => `(and b) or (c and d)`
|
||||
| ^^^^^^^ RUF021
|
||||
34 |
|
||||
35 | a, b, c, d = 0, 1, 3, 0
|
||||
31 | pass
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:36:8: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
27 27 | pass
|
||||
28 28 |
|
||||
29 29 | a, b, c, d = 0, 1, 0, 2
|
||||
30 |-while a and b or c and d: # RUF021: => `(and b) or (c and d)`
|
||||
30 |+while a and b or (c and d): # RUF021: => `(and b) or (c and d)`
|
||||
31 31 | pass
|
||||
32 32 |
|
||||
33 33 | b, c, d, e = 2, 3, 0, 4
|
||||
|
||||
RUF021.py:35:44: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
35 | a, b, c, d = 0, 1, 3, 0
|
||||
36 | assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
33 | b, c, d, e = 2, 3, 0, 4
|
||||
34 | # RUF021: => `a or b or c or (d and e)`:
|
||||
35 | z = [a for a in range(5) if a or b or c or d and e]
|
||||
| ^^^^^^^ RUF021
|
||||
36 |
|
||||
37 | a, b, c, d = 0, 1, 3, 0
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
ℹ Safe fix
|
||||
32 32 |
|
||||
33 33 | b, c, d, e = 2, 3, 0, 4
|
||||
34 34 | # RUF021: => `a or b or c or (d and e)`:
|
||||
35 |-z = [a for a in range(5) if a or b or c or d and e]
|
||||
35 |+z = [a for a in range(5) if a or b or c or (d and e)]
|
||||
36 36 |
|
||||
37 37 | a, b, c, d = 0, 1, 3, 0
|
||||
38 38 | assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
|
||||
RUF021.py:38:8: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
37 | a, b, c, d = 0, 1, 3, 0
|
||||
38 | assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
| ^^^^^^^^^^^ RUF021
|
||||
37 |
|
||||
38 | if (not a) and b or c or d: # RUF021: => `((not a) and b) or c or d`
|
||||
39 |
|
||||
40 | if (not a) and b or c or d: # RUF021: => `((not a) and b) or c or d`
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
RUF021.py:38:4: RUF021 Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
ℹ Safe fix
|
||||
35 35 | z = [a for a in range(5) if a or b or c or d and e]
|
||||
36 36 |
|
||||
37 37 | a, b, c, d = 0, 1, 3, 0
|
||||
38 |-assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
38 |+assert (not a and b) or c or d # RUF021: => `(not a and b) or c or d`
|
||||
39 39 |
|
||||
40 40 | if (not a) and b or c or d: # RUF021: => `((not a) and b) or c or d`
|
||||
41 41 | if (not a and b) or c or d: # OK
|
||||
|
||||
RUF021.py:40:4: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
36 | assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
37 |
|
||||
38 | if (not a) and b or c or d: # RUF021: => `((not a) and b) or c or d`
|
||||
38 | assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
39 |
|
||||
40 | if (not a) and b or c or d: # RUF021: => `((not a) and b) or c or d`
|
||||
| ^^^^^^^^^^^^^ RUF021
|
||||
39 | if (not a and b) or c or d: # OK
|
||||
40 | pass
|
||||
41 | if (not a and b) or c or d: # OK
|
||||
42 | pass
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
ℹ Safe fix
|
||||
37 37 | a, b, c, d = 0, 1, 3, 0
|
||||
38 38 | assert not a and b or c or d # RUF021: => `(not a and b) or c or d`
|
||||
39 39 |
|
||||
40 |-if (not a) and b or c or d: # RUF021: => `((not a) and b) or c or d`
|
||||
40 |+if ((not a) and b) or c or d: # RUF021: => `((not a) and b) or c or d`
|
||||
41 41 | if (not a and b) or c or d: # OK
|
||||
42 42 | pass
|
||||
43 43 |
|
||||
|
||||
RUF021.py:46:8: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
44 | if (
|
||||
45 | some_reasonably_long_condition
|
||||
46 | or some_other_reasonably_long_condition
|
||||
| ________^
|
||||
47 | | and some_third_reasonably_long_condition
|
||||
| |____________________________________________^ RUF021
|
||||
48 | or some_fourth_reasonably_long_condition
|
||||
49 | and some_fifth_reasonably_long_condition
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
ℹ Safe fix
|
||||
43 43 |
|
||||
44 44 | if (
|
||||
45 45 | some_reasonably_long_condition
|
||||
46 |- or some_other_reasonably_long_condition
|
||||
47 |- and some_third_reasonably_long_condition
|
||||
46 |+ or (some_other_reasonably_long_condition
|
||||
47 |+ and some_third_reasonably_long_condition)
|
||||
48 48 | or some_fourth_reasonably_long_condition
|
||||
49 49 | and some_fifth_reasonably_long_condition
|
||||
50 50 | # a commment
|
||||
|
||||
RUF021.py:48:8: RUF021 [*] Parenthesize `a and b` expressions when chaining `and` and `or` together, to make the precedence clear
|
||||
|
|
||||
46 | or some_other_reasonably_long_condition
|
||||
47 | and some_third_reasonably_long_condition
|
||||
48 | or some_fourth_reasonably_long_condition
|
||||
| ________^
|
||||
49 | | and some_fifth_reasonably_long_condition
|
||||
50 | | # a commment
|
||||
51 | | and some_sixth_reasonably_long_condition
|
||||
52 | | and some_seventh_reasonably_long_condition
|
||||
| |______________________________________________^ RUF021
|
||||
53 | # another comment
|
||||
54 | or some_eighth_reasonably_long_condition
|
||||
|
|
||||
= help: Parenthesize the `and` subexpression
|
||||
|
||||
ℹ Safe fix
|
||||
45 45 | some_reasonably_long_condition
|
||||
46 46 | or some_other_reasonably_long_condition
|
||||
47 47 | and some_third_reasonably_long_condition
|
||||
48 |- or some_fourth_reasonably_long_condition
|
||||
48 |+ or (some_fourth_reasonably_long_condition
|
||||
49 49 | and some_fifth_reasonably_long_condition
|
||||
50 50 | # a commment
|
||||
51 51 | and some_sixth_reasonably_long_condition
|
||||
52 |- and some_seventh_reasonably_long_condition
|
||||
52 |+ and some_seventh_reasonably_long_condition)
|
||||
53 53 | # another comment
|
||||
54 54 | or some_eighth_reasonably_long_condition
|
||||
55 55 | ):
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue