Use smarter inversion for comparison checks (#2831)

This commit is contained in:
Charlie Marsh 2023-02-12 17:39:29 -05:00 committed by GitHub
parent 1abaece9ed
commit e2051ef72f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 197 additions and 1 deletions

View file

@ -155,3 +155,19 @@ def f():
if check(x):
return False
return True
def f():
# SIM111
for x in iterable:
if x not in y:
return False
return True
def f():
# SIM111
for x in iterable:
if x > y:
return False
return True

View file

@ -1,6 +1,6 @@
use ruff_macros::{define_violation, derive_message_formats};
use rustpython_parser::ast::{
Comprehension, Constant, Expr, ExprContext, ExprKind, Location, Stmt, StmtKind, Unaryop,
Cmpop, Comprehension, Constant, Expr, ExprContext, ExprKind, Location, Stmt, StmtKind, Unaryop,
};
use crate::ast::helpers::{create_expr, create_stmt, unparse_stmt};
@ -260,6 +260,36 @@ pub fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt, sibling:
} = &loop_info.test.node
{
*operand.clone()
} else if let ExprKind::Compare {
left,
ops,
comparators,
} = &loop_info.test.node
{
if ops.len() == 1 && comparators.len() == 1 {
let op = match &ops[0] {
Cmpop::Eq => Cmpop::NotEq,
Cmpop::NotEq => Cmpop::Eq,
Cmpop::Lt => Cmpop::GtE,
Cmpop::LtE => Cmpop::Gt,
Cmpop::Gt => Cmpop::LtE,
Cmpop::GtE => Cmpop::Lt,
Cmpop::Is => Cmpop::IsNot,
Cmpop::IsNot => Cmpop::Is,
Cmpop::In => Cmpop::NotIn,
Cmpop::NotIn => Cmpop::In,
};
create_expr(ExprKind::Compare {
left: left.clone(),
ops: vec![op],
comparators: vec![comparators[0].clone()],
})
} else {
create_expr(ExprKind::UnaryOp {
op: Unaryop::Not,
operand: Box::new(loop_info.test.clone()),
})
}
} else {
create_expr(ExprKind::UnaryOp {
op: Unaryop::Not,

View file

@ -0,0 +1,150 @@
---
source: crates/ruff/src/rules/flake8_simplify/mod.rs
assertion_line: 47
expression: diagnostics
---
- kind:
ConvertLoopToAll:
all: return all(not check(x) for x in iterable)
location:
row: 25
column: 4
end_location:
row: 27
column: 24
fix:
content:
- return all(not check(x) for x in iterable)
location:
row: 25
column: 4
end_location:
row: 28
column: 15
parent: ~
- kind:
ConvertLoopToAll:
all: return all(x.is_empty() for x in iterable)
location:
row: 33
column: 4
end_location:
row: 35
column: 24
fix:
content:
- return all(x.is_empty() for x in iterable)
location:
row: 33
column: 4
end_location:
row: 36
column: 15
parent: ~
- kind:
ConvertLoopToAll:
all: return all(not check(x) for x in iterable)
location:
row: 64
column: 4
end_location:
row: 68
column: 19
fix:
content:
- return all(not check(x) for x in iterable)
location:
row: 64
column: 4
end_location:
row: 68
column: 19
parent: ~
- kind:
ConvertLoopToAll:
all: return all(not check(x) for x in iterable)
location:
row: 83
column: 4
end_location:
row: 87
column: 19
fix:
content:
- return all(not check(x) for x in iterable)
location:
row: 83
column: 4
end_location:
row: 87
column: 19
parent: ~
- kind:
ConvertLoopToAll:
all: return all(not check(x) for x in iterable)
location:
row: 134
column: 4
end_location:
row: 136
column: 24
fix: ~
parent: ~
- kind:
ConvertLoopToAll:
all: return all(not check(x) for x in iterable)
location:
row: 154
column: 4
end_location:
row: 156
column: 24
fix:
content:
- return all(not check(x) for x in iterable)
location:
row: 154
column: 4
end_location:
row: 157
column: 15
parent: ~
- kind:
ConvertLoopToAll:
all: return all(x in y for x in iterable)
location:
row: 162
column: 4
end_location:
row: 164
column: 24
fix:
content:
- return all(x in y for x in iterable)
location:
row: 162
column: 4
end_location:
row: 165
column: 15
parent: ~
- kind:
ConvertLoopToAll:
all: return all(x <= y for x in iterable)
location:
row: 170
column: 4
end_location:
row: 172
column: 24
fix:
content:
- return all(x <= y for x in iterable)
location:
row: 170
column: 4
end_location:
row: 173
column: 15
parent: ~