about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Uy <ariel.b.uy@gmail.com>2022-04-28 20:54:58 -0700
committerAriel Uy <ariel.b.uy@gmail.com>2022-04-29 19:11:00 -0700
commitd10296910f36cf51187b1b5183a3a628422dd757 (patch)
tree641d37f7bb73407fc00455f7235b971bee2cf428
parent94623ee882d6c598e09cd0787fcc62bd98d88d94 (diff)
downloadrust-d10296910f36cf51187b1b5183a3a628422dd757.tar.gz
rust-d10296910f36cf51187b1b5183a3a628422dd757.zip
Support negative ints in manual_range_contains
Fixes issue where ranges containing ints with different signs would be
incorrect due to comparing as unsigned.
-rw-r--r--clippy_lints/src/ranges.rs17
-rw-r--r--clippy_utils/src/consts.rs10
-rw-r--r--tests/ui/range_contains.fixed8
-rw-r--r--tests/ui/range_contains.rs8
-rw-r--r--tests/ui/range_contains.stderr14
5 files changed, 42 insertions, 15 deletions
diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index e213c208794..043299333b1 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -219,15 +219,17 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
         _ => return,
     };
     // value, name, order (higher/lower), inclusiveness
-    if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) =
-        (check_range_bounds(cx, l), check_range_bounds(cx, r))
+    if let (
+        Some((lval, lexpr, lid, name_span, lval_span, lord, linc)),
+        Some((rval, _, rid, _, rval_span, rord, rinc)),
+    ) = (check_range_bounds(cx, l), check_range_bounds(cx, r))
     {
         // we only lint comparisons on the same name and with different
         // direction
         if lid != rid || lord == rord {
             return;
         }
-        let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval);
+        let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(lexpr), &lval, &rval);
         if combine_and && ord == Some(rord) {
             // order lower bound and upper bound
             let (l_span, u_span, l_inc, u_inc) = if rord == Ordering::Less {
@@ -292,7 +294,10 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
     }
 }
 
-fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> {
+fn check_range_bounds<'a>(
+    cx: &'a LateContext<'_>,
+    ex: &'a Expr<'_>,
+) -> Option<(Constant, &'a Expr<'a>, HirId, Span, Span, Ordering, bool)> {
     if let ExprKind::Binary(ref op, l, r) = ex.kind {
         let (inclusive, ordering) = match op.node {
             BinOpKind::Gt => (false, Ordering::Greater),
@@ -303,11 +308,11 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
         };
         if let Some(id) = path_to_local(l) {
             if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
-                return Some((c, id, l.span, r.span, ordering, inclusive));
+                return Some((c, r, id, l.span, r.span, ordering, inclusive));
             }
         } else if let Some(id) = path_to_local(r) {
             if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
-                return Some((c, id, r.span, l.span, ordering.reverse(), inclusive));
+                return Some((c, l, id, r.span, l.span, ordering.reverse(), inclusive));
             }
         }
     }
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 0e916ca8164..3d34eaa916e 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -130,12 +130,10 @@ impl Constant {
         match (left, right) {
             (&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
             (&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
-            (&Self::Int(l), &Self::Int(r)) => {
-                if let ty::Int(int_ty) = *cmp_type.kind() {
-                    Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
-                } else {
-                    Some(l.cmp(&r))
-                }
+            (&Self::Int(l), &Self::Int(r)) => match *cmp_type.kind() {
+                ty::Int(int_ty) => Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty))),
+                ty::Uint(_) => Some(l.cmp(&r)),
+                _ => bug!("Not an int type"),
             },
             (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
             (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed
index 47c974e614b..f4977199711 100644
--- a/tests/ui/range_contains.fixed
+++ b/tests/ui/range_contains.fixed
@@ -6,7 +6,7 @@
 #[allow(clippy::short_circuit_statement)]
 #[allow(clippy::unnecessary_operation)]
 fn main() {
-    let x = 9_u32;
+    let x = 9_i32;
 
     // order shouldn't matter
     (8..12).contains(&x);
@@ -43,6 +43,12 @@ fn main() {
     let y = 3.;
     (0. ..1.).contains(&y);
     !(0. ..=1.).contains(&y);
+
+    // handle negatives #8721
+    (-10..=10).contains(&x);
+    x >= 10 && x <= -10;
+    (-3. ..=3.).contains(&y);
+    y >= 3. && y <= -3.;
 }
 
 // Fix #6373
diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs
index 835deced5e4..9e2180b0c99 100644
--- a/tests/ui/range_contains.rs
+++ b/tests/ui/range_contains.rs
@@ -6,7 +6,7 @@
 #[allow(clippy::short_circuit_statement)]
 #[allow(clippy::unnecessary_operation)]
 fn main() {
-    let x = 9_u32;
+    let x = 9_i32;
 
     // order shouldn't matter
     x >= 8 && x < 12;
@@ -43,6 +43,12 @@ fn main() {
     let y = 3.;
     y >= 0. && y < 1.;
     y < 0. || y > 1.;
+
+    // handle negatives #8721
+    x >= -10 && x <= 10;
+    x >= 10 && x <= -10;
+    y >= -3. && y <= 3.;
+    y >= 3. && y <= -3.;
 }
 
 // Fix #6373
diff --git a/tests/ui/range_contains.stderr b/tests/ui/range_contains.stderr
index bc79f1bca84..1817ee1715d 100644
--- a/tests/ui/range_contains.stderr
+++ b/tests/ui/range_contains.stderr
@@ -84,5 +84,17 @@ error: manual `!RangeInclusive::contains` implementation
 LL |     y < 0. || y > 1.;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
 
-error: aborting due to 14 previous errors
+error: manual `RangeInclusive::contains` implementation
+  --> $DIR/range_contains.rs:48:5
+   |
+LL |     x >= -10 && x <= 10;
+   |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
+
+error: manual `RangeInclusive::contains` implementation
+  --> $DIR/range_contains.rs:50:5
+   |
+LL |     y >= -3. && y <= 3.;
+   |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
+
+error: aborting due to 16 previous errors