Skip to content

Commit 9add456

Browse files
committed
Auto merge of #8876 - Alexendoo:cast-abs-to-different-uint, r=dswij,xFrednet
`cast_abs_to_unsigned`: do not remove cast if it's required Fixes #8873 If `iX` is not cast to `uX` then keep the cast rather than removing it changelog: [`cast_abs_to_unsigned`]: do not remove cast if it's required
2 parents 2466a05 + a342f52 commit 9add456

File tree

4 files changed

+157
-23
lines changed

4 files changed

+157
-23
lines changed
Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::sugg::Sugg;
33
use clippy_utils::{meets_msrv, msrvs};
4-
use if_chain::if_chain;
54
use rustc_errors::Applicability;
65
use rustc_hir::{Expr, ExprKind};
76
use rustc_lint::LateContext;
8-
use rustc_middle::ty::Ty;
7+
use rustc_middle::ty::{self, Ty};
98
use rustc_semver::RustcVersion;
109

1110
use super::CAST_ABS_TO_UNSIGNED;
@@ -18,25 +17,28 @@ pub(super) fn check(
1817
cast_to: Ty<'_>,
1918
msrv: Option<RustcVersion>,
2019
) {
21-
if_chain! {
22-
if meets_msrv(msrv, msrvs::UNSIGNED_ABS);
23-
if cast_from.is_integral();
24-
if cast_to.is_integral();
25-
if cast_from.is_signed();
26-
if !cast_to.is_signed();
27-
if let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind;
28-
if let method_name = method_path.ident.name.as_str();
29-
if method_name == "abs";
30-
then {
31-
span_lint_and_sugg(
32-
cx,
33-
CAST_ABS_TO_UNSIGNED,
34-
expr.span,
35-
&format!("casting the result of `{}::{}()` to {}", cast_from, method_name, cast_to),
36-
"replace with",
37-
format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
38-
Applicability::MachineApplicable,
39-
);
40-
}
20+
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
21+
&& let ty::Int(from) = cast_from.kind()
22+
&& let ty::Uint(to) = cast_to.kind()
23+
&& let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
24+
&& method_path.ident.name.as_str() == "abs"
25+
{
26+
let span = if from.bit_width() == to.bit_width() {
27+
expr.span
28+
} else {
29+
// if the result of `.unsigned_abs` would be a different type, keep the cast
30+
// e.g. `i64 -> usize`, `i16 -> u8`
31+
cast_expr.span
32+
};
33+
34+
span_lint_and_sugg(
35+
cx,
36+
CAST_ABS_TO_UNSIGNED,
37+
span,
38+
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
39+
"replace with",
40+
format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
41+
Applicability::MachineApplicable,
42+
);
4143
}
4244
}

tests/ui/cast_abs_to_unsigned.fixed

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,25 @@ fn main() {
55
let x: i32 = -42;
66
let y: u32 = x.unsigned_abs();
77
println!("The absolute value of {} is {}", x, y);
8+
9+
let a: i32 = -3;
10+
let _: usize = a.unsigned_abs() as usize;
11+
let _: usize = a.unsigned_abs() as _;
12+
let _ = a.unsigned_abs() as usize;
13+
14+
let a: i64 = -3;
15+
let _ = a.unsigned_abs() as usize;
16+
let _ = a.unsigned_abs() as u8;
17+
let _ = a.unsigned_abs() as u16;
18+
let _ = a.unsigned_abs() as u32;
19+
let _ = a.unsigned_abs();
20+
let _ = a.unsigned_abs() as u128;
21+
22+
let a: isize = -3;
23+
let _ = a.unsigned_abs();
24+
let _ = a.unsigned_abs() as u8;
25+
let _ = a.unsigned_abs() as u16;
26+
let _ = a.unsigned_abs() as u32;
27+
let _ = a.unsigned_abs() as u64;
28+
let _ = a.unsigned_abs() as u128;
829
}

tests/ui/cast_abs_to_unsigned.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,25 @@ fn main() {
55
let x: i32 = -42;
66
let y: u32 = x.abs() as u32;
77
println!("The absolute value of {} is {}", x, y);
8+
9+
let a: i32 = -3;
10+
let _: usize = a.abs() as usize;
11+
let _: usize = a.abs() as _;
12+
let _ = a.abs() as usize;
13+
14+
let a: i64 = -3;
15+
let _ = a.abs() as usize;
16+
let _ = a.abs() as u8;
17+
let _ = a.abs() as u16;
18+
let _ = a.abs() as u32;
19+
let _ = a.abs() as u64;
20+
let _ = a.abs() as u128;
21+
22+
let a: isize = -3;
23+
let _ = a.abs() as usize;
24+
let _ = a.abs() as u8;
25+
let _ = a.abs() as u16;
26+
let _ = a.abs() as u32;
27+
let _ = a.abs() as u64;
28+
let _ = a.abs() as u128;
829
}

tests/ui/cast_abs_to_unsigned.stderr

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,95 @@ LL | let y: u32 = x.abs() as u32;
66
|
77
= note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings`
88

9-
error: aborting due to previous error
9+
error: casting the result of `i32::abs()` to usize
10+
--> $DIR/cast_abs_to_unsigned.rs:10:20
11+
|
12+
LL | let _: usize = a.abs() as usize;
13+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
14+
15+
error: casting the result of `i32::abs()` to usize
16+
--> $DIR/cast_abs_to_unsigned.rs:11:20
17+
|
18+
LL | let _: usize = a.abs() as _;
19+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
20+
21+
error: casting the result of `i32::abs()` to usize
22+
--> $DIR/cast_abs_to_unsigned.rs:12:13
23+
|
24+
LL | let _ = a.abs() as usize;
25+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
26+
27+
error: casting the result of `i64::abs()` to usize
28+
--> $DIR/cast_abs_to_unsigned.rs:15:13
29+
|
30+
LL | let _ = a.abs() as usize;
31+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
32+
33+
error: casting the result of `i64::abs()` to u8
34+
--> $DIR/cast_abs_to_unsigned.rs:16:13
35+
|
36+
LL | let _ = a.abs() as u8;
37+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
38+
39+
error: casting the result of `i64::abs()` to u16
40+
--> $DIR/cast_abs_to_unsigned.rs:17:13
41+
|
42+
LL | let _ = a.abs() as u16;
43+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
44+
45+
error: casting the result of `i64::abs()` to u32
46+
--> $DIR/cast_abs_to_unsigned.rs:18:13
47+
|
48+
LL | let _ = a.abs() as u32;
49+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
50+
51+
error: casting the result of `i64::abs()` to u64
52+
--> $DIR/cast_abs_to_unsigned.rs:19:13
53+
|
54+
LL | let _ = a.abs() as u64;
55+
| ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
56+
57+
error: casting the result of `i64::abs()` to u128
58+
--> $DIR/cast_abs_to_unsigned.rs:20:13
59+
|
60+
LL | let _ = a.abs() as u128;
61+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
62+
63+
error: casting the result of `isize::abs()` to usize
64+
--> $DIR/cast_abs_to_unsigned.rs:23:13
65+
|
66+
LL | let _ = a.abs() as usize;
67+
| ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
68+
69+
error: casting the result of `isize::abs()` to u8
70+
--> $DIR/cast_abs_to_unsigned.rs:24:13
71+
|
72+
LL | let _ = a.abs() as u8;
73+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
74+
75+
error: casting the result of `isize::abs()` to u16
76+
--> $DIR/cast_abs_to_unsigned.rs:25:13
77+
|
78+
LL | let _ = a.abs() as u16;
79+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
80+
81+
error: casting the result of `isize::abs()` to u32
82+
--> $DIR/cast_abs_to_unsigned.rs:26:13
83+
|
84+
LL | let _ = a.abs() as u32;
85+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
86+
87+
error: casting the result of `isize::abs()` to u64
88+
--> $DIR/cast_abs_to_unsigned.rs:27:13
89+
|
90+
LL | let _ = a.abs() as u64;
91+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
92+
93+
error: casting the result of `isize::abs()` to u128
94+
--> $DIR/cast_abs_to_unsigned.rs:28:13
95+
|
96+
LL | let _ = a.abs() as u128;
97+
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
98+
99+
error: aborting due to 16 previous errors
10100

0 commit comments

Comments
 (0)