Skip to content

Commit

Permalink
Auto merge of rust-lang#8876 - Alexendoo:cast-abs-to-different-uint, …
Browse files Browse the repository at this point in the history
…r=dswij,xFrednet

`cast_abs_to_unsigned`: do not remove cast if it's required

Fixes rust-lang#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
  • Loading branch information
bors committed May 31, 2022
2 parents 2466a05 + a342f52 commit 9add456
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 23 deletions.
46 changes: 24 additions & 22 deletions clippy_lints/src/casts/cast_abs_to_unsigned.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
use clippy_utils::{meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use rustc_middle::ty::{self, Ty};
use rustc_semver::RustcVersion;

use super::CAST_ABS_TO_UNSIGNED;
Expand All @@ -18,25 +17,28 @@ pub(super) fn check(
cast_to: Ty<'_>,
msrv: Option<RustcVersion>,
) {
if_chain! {
if meets_msrv(msrv, msrvs::UNSIGNED_ABS);
if cast_from.is_integral();
if cast_to.is_integral();
if cast_from.is_signed();
if !cast_to.is_signed();
if let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind;
if let method_name = method_path.ident.name.as_str();
if method_name == "abs";
then {
span_lint_and_sugg(
cx,
CAST_ABS_TO_UNSIGNED,
expr.span,
&format!("casting the result of `{}::{}()` to {}", cast_from, method_name, cast_to),
"replace with",
format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
Applicability::MachineApplicable,
);
}
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
&& let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
&& method_path.ident.name.as_str() == "abs"
{
let span = if from.bit_width() == to.bit_width() {
expr.span
} else {
// if the result of `.unsigned_abs` would be a different type, keep the cast
// e.g. `i64 -> usize`, `i16 -> u8`
cast_expr.span
};

span_lint_and_sugg(
cx,
CAST_ABS_TO_UNSIGNED,
span,
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
Applicability::MachineApplicable,
);
}
}
21 changes: 21 additions & 0 deletions tests/ui/cast_abs_to_unsigned.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,25 @@ fn main() {
let x: i32 = -42;
let y: u32 = x.unsigned_abs();
println!("The absolute value of {} is {}", x, y);

let a: i32 = -3;
let _: usize = a.unsigned_abs() as usize;
let _: usize = a.unsigned_abs() as _;
let _ = a.unsigned_abs() as usize;

let a: i64 = -3;
let _ = a.unsigned_abs() as usize;
let _ = a.unsigned_abs() as u8;
let _ = a.unsigned_abs() as u16;
let _ = a.unsigned_abs() as u32;
let _ = a.unsigned_abs();
let _ = a.unsigned_abs() as u128;

let a: isize = -3;
let _ = a.unsigned_abs();
let _ = a.unsigned_abs() as u8;
let _ = a.unsigned_abs() as u16;
let _ = a.unsigned_abs() as u32;
let _ = a.unsigned_abs() as u64;
let _ = a.unsigned_abs() as u128;
}
21 changes: 21 additions & 0 deletions tests/ui/cast_abs_to_unsigned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,25 @@ fn main() {
let x: i32 = -42;
let y: u32 = x.abs() as u32;
println!("The absolute value of {} is {}", x, y);

let a: i32 = -3;
let _: usize = a.abs() as usize;
let _: usize = a.abs() as _;
let _ = a.abs() as usize;

let a: i64 = -3;
let _ = a.abs() as usize;
let _ = a.abs() as u8;
let _ = a.abs() as u16;
let _ = a.abs() as u32;
let _ = a.abs() as u64;
let _ = a.abs() as u128;

let a: isize = -3;
let _ = a.abs() as usize;
let _ = a.abs() as u8;
let _ = a.abs() as u16;
let _ = a.abs() as u32;
let _ = a.abs() as u64;
let _ = a.abs() as u128;
}
92 changes: 91 additions & 1 deletion tests/ui/cast_abs_to_unsigned.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,95 @@ LL | let y: u32 = x.abs() as u32;
|
= note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings`

error: aborting due to previous error
error: casting the result of `i32::abs()` to usize
--> $DIR/cast_abs_to_unsigned.rs:10:20
|
LL | let _: usize = a.abs() as usize;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i32::abs()` to usize
--> $DIR/cast_abs_to_unsigned.rs:11:20
|
LL | let _: usize = a.abs() as _;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i32::abs()` to usize
--> $DIR/cast_abs_to_unsigned.rs:12:13
|
LL | let _ = a.abs() as usize;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i64::abs()` to usize
--> $DIR/cast_abs_to_unsigned.rs:15:13
|
LL | let _ = a.abs() as usize;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i64::abs()` to u8
--> $DIR/cast_abs_to_unsigned.rs:16:13
|
LL | let _ = a.abs() as u8;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i64::abs()` to u16
--> $DIR/cast_abs_to_unsigned.rs:17:13
|
LL | let _ = a.abs() as u16;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i64::abs()` to u32
--> $DIR/cast_abs_to_unsigned.rs:18:13
|
LL | let _ = a.abs() as u32;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i64::abs()` to u64
--> $DIR/cast_abs_to_unsigned.rs:19:13
|
LL | let _ = a.abs() as u64;
| ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `i64::abs()` to u128
--> $DIR/cast_abs_to_unsigned.rs:20:13
|
LL | let _ = a.abs() as u128;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `isize::abs()` to usize
--> $DIR/cast_abs_to_unsigned.rs:23:13
|
LL | let _ = a.abs() as usize;
| ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `isize::abs()` to u8
--> $DIR/cast_abs_to_unsigned.rs:24:13
|
LL | let _ = a.abs() as u8;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `isize::abs()` to u16
--> $DIR/cast_abs_to_unsigned.rs:25:13
|
LL | let _ = a.abs() as u16;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `isize::abs()` to u32
--> $DIR/cast_abs_to_unsigned.rs:26:13
|
LL | let _ = a.abs() as u32;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `isize::abs()` to u64
--> $DIR/cast_abs_to_unsigned.rs:27:13
|
LL | let _ = a.abs() as u64;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: casting the result of `isize::abs()` to u128
--> $DIR/cast_abs_to_unsigned.rs:28:13
|
LL | let _ = a.abs() as u128;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`

error: aborting due to 16 previous errors

0 comments on commit 9add456

Please sign in to comment.