Skip to content

Commit 93e41d3

Browse files
author
Evan Typanski
committed
Fix case where rem was considered commutative
1 parent 75ed0c9 commit 93e41d3

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

clippy_lints/src/manual_rem_euclid.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
5555
if_chain! {
5656
if let ExprKind::Binary(op1, ..) = expr.kind;
5757
if op1.node == BinOpKind::Rem;
58-
if let Some((const1, expr1)) = check_for_positive_int_constant(cx, expr);
58+
if let Some((const1, expr1)) = check_for_positive_int_constant(cx, expr, false);
5959
if let ExprKind::Binary(op2, ..) = expr1.kind;
6060
if op2.node == BinOpKind::Add;
61-
if let Some((const2, expr2)) = check_for_positive_int_constant(cx, expr1);
61+
if let Some((const2, expr2)) = check_for_positive_int_constant(cx, expr1, true);
6262
if let ExprKind::Binary(op3, ..) = expr2.kind;
6363
if op3.node == BinOpKind::Rem;
64-
if let Some((const3, expr3)) = check_for_positive_int_constant(cx, expr2);
64+
if let Some((const3, expr3)) = check_for_positive_int_constant(cx, expr2, false);
6565
if const1 == const2 && const2 == const3;
6666
// Only apply if we see an explicit type annotation on the local.
6767
if let Some(hir_id) = path_to_local(expr3);
@@ -91,13 +91,18 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
9191
}
9292

9393
// Takes a binary expression and separates the operands into the int constant and the other
94-
// operand. Ensures the int constant is positive.
95-
fn check_for_positive_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<(u128, &'a Expr<'a>)> {
94+
// operand. Ensures the int constant is positive. Operators that are not commutative must have the
95+
// constant appear on the right hand side to return a value.
96+
fn check_for_positive_int_constant<'a>(
97+
cx: &'a LateContext<'_>,
98+
expr: &'a Expr<'_>,
99+
is_commutative: bool,
100+
) -> Option<(u128, &'a Expr<'a>)> {
96101
let (int_const, other_op) = if let ExprKind::Binary(_, left, right) = expr.kind {
97-
if let Some(int_const) = constant_full_int(cx, cx.typeck_results(), left) {
98-
(int_const, right)
99-
} else if let Some(int_const) = constant_full_int(cx, cx.typeck_results(), right) {
102+
if let Some(int_const) = constant_full_int(cx, cx.typeck_results(), right) {
100103
(int_const, left)
104+
} else if is_commutative && let Some(int_const) = constant_full_int(cx, cx.typeck_results(), left) {
105+
(int_const, right)
101106
} else {
102107
return None;
103108
}

tests/ui/manual_rem_euclid.fixed

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ fn main() {
2121
let _ = ((not_annotated % 4) + 4) % 4;
2222
let inferred: _ = 24;
2323
let _ = ((inferred % 4) + 4) % 4;
24+
25+
// For lint to apply the constant must always be on the RHS of the previous value for %
26+
let _: i32 = 4 % ((value % 4) + 4);
27+
let _: i32 = ((4 % value) + 4) % 4;
2428
}

tests/ui/manual_rem_euclid.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ fn main() {
2121
let _ = ((not_annotated % 4) + 4) % 4;
2222
let inferred: _ = 24;
2323
let _ = ((inferred % 4) + 4) % 4;
24+
25+
// For lint to apply the constant must always be on the RHS of the previous value for %
26+
let _: i32 = 4 % ((value % 4) + 4);
27+
let _: i32 = ((4 % value) + 4) % 4;
2428
}

0 commit comments

Comments
 (0)