mirror of https://github.com/astral-sh/ruff
Rewrite `not not a` as `bool(a)` in boolean contexts (#4294)
This commit is contained in:
parent
43d6aa9173
commit
61f21a6513
|
|
@ -12,3 +12,10 @@ if not a == b: # OK
|
|||
|
||||
if not a != b: # OK
|
||||
pass
|
||||
|
||||
a = not not b # SIM208
|
||||
|
||||
f(not not a) # SIM208
|
||||
|
||||
if 1 + (not (not a)): # SIM208
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ a = True if b + c else False # SIM210
|
|||
|
||||
a = False if b else True # OK
|
||||
|
||||
|
||||
def f():
|
||||
# OK
|
||||
def bool():
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
|||
use rustpython_common::cformat::{CFormatError, CFormatErrorType};
|
||||
use rustpython_parser::ast::{
|
||||
Arg, Arguments, Comprehension, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext,
|
||||
ExprKind, KeywordData, Located, Operator, Pattern, PatternKind, Stmt, StmtKind, Suite,
|
||||
ExprKind, KeywordData, Located, Operator, Pattern, PatternKind, Stmt, StmtKind, Suite, Unaryop,
|
||||
};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
|
|
@ -2299,7 +2299,16 @@ where
|
|||
let prev_in_type_definition = self.ctx.in_type_definition;
|
||||
let prev_in_boolean_test = self.ctx.in_boolean_test;
|
||||
|
||||
if !matches!(expr.node, ExprKind::BoolOp { .. }) {
|
||||
// If we're in a boolean test (e.g., the `test` of a `StmtKind::If`), but now within a
|
||||
// subexpression (e.g., `a` in `f(a)`), then we're no longer in a boolean test.
|
||||
if !matches!(
|
||||
expr.node,
|
||||
ExprKind::BoolOp { .. }
|
||||
| ExprKind::UnaryOp {
|
||||
op: Unaryop::Not,
|
||||
..
|
||||
}
|
||||
) {
|
||||
self.ctx.in_boolean_test = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Stmt, StmtKind, Unaryop};
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprContext, ExprKind, Stmt, StmtKind, Unaryop};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
|
@ -191,10 +191,27 @@ pub fn double_negation(checker: &mut Checker, expr: &Expr, op: &Unaryop, operand
|
|||
expr.range(),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
|
||||
unparse_expr(operand, checker.stylist),
|
||||
expr.range(),
|
||||
)));
|
||||
if checker.ctx.in_boolean_test {
|
||||
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
|
||||
unparse_expr(operand, checker.stylist),
|
||||
expr.range(),
|
||||
)));
|
||||
} else if checker.ctx.is_builtin("bool") {
|
||||
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
|
||||
unparse_expr(
|
||||
&create_expr(ExprKind::Call {
|
||||
func: Box::new(create_expr(ExprKind::Name {
|
||||
id: "bool".to_string(),
|
||||
ctx: ExprContext::Load,
|
||||
})),
|
||||
args: vec![*operand.clone()],
|
||||
keywords: vec![],
|
||||
}),
|
||||
checker.stylist,
|
||||
),
|
||||
expr.range(),
|
||||
)));
|
||||
};
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,4 +36,64 @@ SIM208.py:4:4: SIM208 [*] Use `a == b` instead of `not (not a == b)`
|
|||
6 6 |
|
||||
7 7 | if not a: # OK
|
||||
|
||||
SIM208.py:16:5: SIM208 [*] Use `b` instead of `not (not b)`
|
||||
|
|
||||
16 | pass
|
||||
17 |
|
||||
18 | a = not not b # SIM208
|
||||
| ^^^^^^^^^ SIM208
|
||||
19 |
|
||||
20 | f(not not a) # SIM208
|
||||
|
|
||||
= help: Replace with `b`
|
||||
|
||||
ℹ Suggested fix
|
||||
13 13 | if not a != b: # OK
|
||||
14 14 | pass
|
||||
15 15 |
|
||||
16 |-a = not not b # SIM208
|
||||
16 |+a = bool(b) # SIM208
|
||||
17 17 |
|
||||
18 18 | f(not not a) # SIM208
|
||||
19 19 |
|
||||
|
||||
SIM208.py:18:3: SIM208 [*] Use `a` instead of `not (not a)`
|
||||
|
|
||||
18 | a = not not b # SIM208
|
||||
19 |
|
||||
20 | f(not not a) # SIM208
|
||||
| ^^^^^^^^^ SIM208
|
||||
21 |
|
||||
22 | if 1 + (not (not a)): # SIM208
|
||||
|
|
||||
= help: Replace with `a`
|
||||
|
||||
ℹ Suggested fix
|
||||
15 15 |
|
||||
16 16 | a = not not b # SIM208
|
||||
17 17 |
|
||||
18 |-f(not not a) # SIM208
|
||||
18 |+f(bool(a)) # SIM208
|
||||
19 19 |
|
||||
20 20 | if 1 + (not (not a)): # SIM208
|
||||
21 21 | pass
|
||||
|
||||
SIM208.py:20:9: SIM208 [*] Use `a` instead of `not (not a)`
|
||||
|
|
||||
20 | f(not not a) # SIM208
|
||||
21 |
|
||||
22 | if 1 + (not (not a)): # SIM208
|
||||
| ^^^^^^^^^^^ SIM208
|
||||
23 | pass
|
||||
|
|
||||
= help: Replace with `a`
|
||||
|
||||
ℹ Suggested fix
|
||||
17 17 |
|
||||
18 18 | f(not not a) # SIM208
|
||||
19 19 |
|
||||
20 |-if 1 + (not (not a)): # SIM208
|
||||
20 |+if 1 + (bool(a)): # SIM208
|
||||
21 21 | pass
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -58,11 +58,11 @@ SIM210.py:5:5: SIM210 [*] Use `bool(b + c)` instead of `True if b + c else False
|
|||
7 7 | a = False if b else True # OK
|
||||
8 8 |
|
||||
|
||||
SIM210.py:14:9: SIM210 [*] Use `bool(b)` instead of `True if b else False`
|
||||
SIM210.py:15:9: SIM210 [*] Use `bool(b)` instead of `True if b else False`
|
||||
|
|
||||
14 | return False
|
||||
15 |
|
||||
16 | a = True if b else False
|
||||
15 | return False
|
||||
16 |
|
||||
17 | a = True if b else False
|
||||
| ^^^^^^^^^^^^^^^^^^^^ SIM210
|
||||
|
|
||||
= help: Replace with `not b
|
||||
|
|
|
|||
Loading…
Reference in New Issue