Skip to content

Commit d102969

Browse files
committed
Support negative ints in manual_range_contains
Fixes issue where ranges containing ints with different signs would be incorrect due to comparing as unsigned.
1 parent 94623ee commit d102969

File tree

5 files changed

+42
-15
lines changed

5 files changed

+42
-15
lines changed

clippy_lints/src/ranges.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,17 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
219219
_ => return,
220220
};
221221
// value, name, order (higher/lower), inclusiveness
222-
if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) =
223-
(check_range_bounds(cx, l), check_range_bounds(cx, r))
222+
if let (
223+
Some((lval, lexpr, lid, name_span, lval_span, lord, linc)),
224+
Some((rval, _, rid, _, rval_span, rord, rinc)),
225+
) = (check_range_bounds(cx, l), check_range_bounds(cx, r))
224226
{
225227
// we only lint comparisons on the same name and with different
226228
// direction
227229
if lid != rid || lord == rord {
228230
return;
229231
}
230-
let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval);
232+
let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(lexpr), &lval, &rval);
231233
if combine_and && ord == Some(rord) {
232234
// order lower bound and upper bound
233235
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<'
292294
}
293295
}
294296

295-
fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> {
297+
fn check_range_bounds<'a>(
298+
cx: &'a LateContext<'_>,
299+
ex: &'a Expr<'_>,
300+
) -> Option<(Constant, &'a Expr<'a>, HirId, Span, Span, Ordering, bool)> {
296301
if let ExprKind::Binary(ref op, l, r) = ex.kind {
297302
let (inclusive, ordering) = match op.node {
298303
BinOpKind::Gt => (false, Ordering::Greater),
@@ -303,11 +308,11 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
303308
};
304309
if let Some(id) = path_to_local(l) {
305310
if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
306-
return Some((c, id, l.span, r.span, ordering, inclusive));
311+
return Some((c, r, id, l.span, r.span, ordering, inclusive));
307312
}
308313
} else if let Some(id) = path_to_local(r) {
309314
if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
310-
return Some((c, id, r.span, l.span, ordering.reverse(), inclusive));
315+
return Some((c, l, id, r.span, l.span, ordering.reverse(), inclusive));
311316
}
312317
}
313318
}

clippy_utils/src/consts.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,10 @@ impl Constant {
130130
match (left, right) {
131131
(&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
132132
(&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
133-
(&Self::Int(l), &Self::Int(r)) => {
134-
if let ty::Int(int_ty) = *cmp_type.kind() {
135-
Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
136-
} else {
137-
Some(l.cmp(&r))
138-
}
133+
(&Self::Int(l), &Self::Int(r)) => match *cmp_type.kind() {
134+
ty::Int(int_ty) => Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty))),
135+
ty::Uint(_) => Some(l.cmp(&r)),
136+
_ => bug!("Not an int type"),
139137
},
140138
(&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
141139
(&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),

tests/ui/range_contains.fixed

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#[allow(clippy::short_circuit_statement)]
77
#[allow(clippy::unnecessary_operation)]
88
fn main() {
9-
let x = 9_u32;
9+
let x = 9_i32;
1010

1111
// order shouldn't matter
1212
(8..12).contains(&x);
@@ -43,6 +43,12 @@ fn main() {
4343
let y = 3.;
4444
(0. ..1.).contains(&y);
4545
!(0. ..=1.).contains(&y);
46+
47+
// handle negatives #8721
48+
(-10..=10).contains(&x);
49+
x >= 10 && x <= -10;
50+
(-3. ..=3.).contains(&y);
51+
y >= 3. && y <= -3.;
4652
}
4753

4854
// Fix #6373

tests/ui/range_contains.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#[allow(clippy::short_circuit_statement)]
77
#[allow(clippy::unnecessary_operation)]
88
fn main() {
9-
let x = 9_u32;
9+
let x = 9_i32;
1010

1111
// order shouldn't matter
1212
x >= 8 && x < 12;
@@ -43,6 +43,12 @@ fn main() {
4343
let y = 3.;
4444
y >= 0. && y < 1.;
4545
y < 0. || y > 1.;
46+
47+
// handle negatives #8721
48+
x >= -10 && x <= 10;
49+
x >= 10 && x <= -10;
50+
y >= -3. && y <= 3.;
51+
y >= 3. && y <= -3.;
4652
}
4753

4854
// Fix #6373

tests/ui/range_contains.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,17 @@ error: manual `!RangeInclusive::contains` implementation
8484
LL | y < 0. || y > 1.;
8585
| ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
8686

87-
error: aborting due to 14 previous errors
87+
error: manual `RangeInclusive::contains` implementation
88+
--> $DIR/range_contains.rs:48:5
89+
|
90+
LL | x >= -10 && x <= 10;
91+
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
92+
93+
error: manual `RangeInclusive::contains` implementation
94+
--> $DIR/range_contains.rs:50:5
95+
|
96+
LL | y >= -3. && y <= 3.;
97+
| ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
98+
99+
error: aborting due to 16 previous errors
88100

0 commit comments

Comments
 (0)