Skip to content

Commit 9058b04

Browse files
committed
Auto merge of #11096 - y21:issue11091, r=giraffate
[`manual_range_patterns`]: lint negative values Fixes #11091. Now also lints negative values in patterns (`-1 | -2 | -3`) changelog: [`manual_range_patterns`]: lint negative values
2 parents 507d1c2 + c927912 commit 9058b04

File tree

4 files changed

+38
-10
lines changed

4 files changed

+38
-10
lines changed

clippy_lints/src/manual_range_patterns.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_hir::Expr;
66
use rustc_hir::ExprKind;
77
use rustc_hir::PatKind;
88
use rustc_hir::RangeEnd;
9+
use rustc_hir::UnOp;
910
use rustc_lint::LintContext;
1011
use rustc_lint::{LateContext, LateLintPass};
1112
use rustc_middle::lint::in_external_macro;
@@ -19,6 +20,10 @@ declare_clippy_lint! {
1920
/// ### Why is this bad?
2021
/// Using an explicit range is more concise and easier to read.
2122
///
23+
/// ### Known issues
24+
/// This lint intentionally does not handle numbers greater than `i128::MAX` for `u128` literals
25+
/// in order to support negative numbers.
26+
///
2227
/// ### Example
2328
/// ```rust
2429
/// let x = 6;
@@ -36,11 +41,14 @@ declare_clippy_lint! {
3641
}
3742
declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
3843

39-
fn expr_as_u128(expr: &Expr<'_>) -> Option<u128> {
40-
if let ExprKind::Lit(lit) = expr.kind
44+
fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
45+
if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
46+
expr_as_i128(expr).map(|num| -num)
47+
} else if let ExprKind::Lit(lit) = expr.kind
4148
&& let LitKind::Int(num, _) = lit.node
4249
{
43-
Some(num)
50+
// Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
51+
num.try_into().ok()
4452
} else {
4553
None
4654
}
@@ -56,22 +64,22 @@ impl LateLintPass<'_> for ManualRangePatterns {
5664
if let PatKind::Or(pats) = pat.kind
5765
&& pats.len() >= 3
5866
{
59-
let mut min = u128::MAX;
60-
let mut max = 0;
67+
let mut min = i128::MAX;
68+
let mut max = i128::MIN;
6169
let mut numbers_found = FxHashSet::default();
6270
let mut ranges_found = Vec::new();
6371

6472
for pat in pats {
6573
if let PatKind::Lit(lit) = pat.kind
66-
&& let Some(num) = expr_as_u128(lit)
74+
&& let Some(num) = expr_as_i128(lit)
6775
{
6876
numbers_found.insert(num);
6977

7078
min = min.min(num);
7179
max = max.max(num);
7280
} else if let PatKind::Range(Some(left), Some(right), end) = pat.kind
73-
&& let Some(left) = expr_as_u128(left)
74-
&& let Some(right) = expr_as_u128(right)
81+
&& let Some(left) = expr_as_i128(left)
82+
&& let Some(right) = expr_as_i128(right)
7583
&& right >= left
7684
{
7785
min = min.min(left);

tests/ui/manual_range_patterns.fixed

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ fn main() {
2525
1..=10 => true,
2626
_ => false,
2727
};
28+
let _ = matches!(f, -5..=3);
29+
let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing
30+
let _ = matches!(f, -1000001..=1000001);
31+
let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002);
2832

2933
macro_rules! mac {
3034
($e:expr) => {

tests/ui/manual_range_patterns.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ fn main() {
2525
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
2626
_ => false,
2727
};
28+
let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2);
29+
let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing
30+
let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001);
31+
let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002);
2832

2933
macro_rules! mac {
3034
($e:expr) => {

tests/ui/manual_range_patterns.stderr

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,19 @@ LL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true,
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10`
3838

3939
error: this OR pattern can be rewritten using a range
40-
--> $DIR/manual_range_patterns.rs:31:26
40+
--> $DIR/manual_range_patterns.rs:28:25
41+
|
42+
LL | let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2);
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-5..=3`
44+
45+
error: this OR pattern can be rewritten using a range
46+
--> $DIR/manual_range_patterns.rs:30:25
47+
|
48+
LL | let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001);
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-1000001..=1000001`
50+
51+
error: this OR pattern can be rewritten using a range
52+
--> $DIR/manual_range_patterns.rs:35:26
4153
|
4254
LL | matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10)
4355
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10`
@@ -47,5 +59,5 @@ LL | mac!(f);
4759
|
4860
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
4961

50-
error: aborting due to 7 previous errors
62+
error: aborting due to 9 previous errors
5163

0 commit comments

Comments
 (0)