Skip to content

Commit 629ed54

Browse files
committed
[cast_lossless]: Suggest type alias instead of the aliased type
1 parent 78f5e0d commit 629ed54

11 files changed

+120
-56
lines changed

clippy_lints/src/casts/cast_lossless.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::in_constant;
33
use clippy_utils::msrvs::{self, Msrv};
4-
use clippy_utils::source::snippet_opt;
4+
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
55
use clippy_utils::ty::is_isize_or_usize;
66
use rustc_errors::Applicability;
7-
use rustc_hir::{Expr, ExprKind};
7+
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
88
use rustc_lint::LateContext;
99
use rustc_middle::ty::{self, FloatTy, Ty};
1010

@@ -16,6 +16,7 @@ pub(super) fn check(
1616
cast_op: &Expr<'_>,
1717
cast_from: Ty<'_>,
1818
cast_to: Ty<'_>,
19+
cast_to_hir: &rustc_hir::Ty<'_>,
1920
msrv: &Msrv,
2021
) {
2122
if !should_lint(cx, expr, cast_from, cast_to, msrv) {
@@ -24,11 +25,11 @@ pub(super) fn check(
2425

2526
// The suggestion is to use a function call, so if the original expression
2627
// has parens on the outside, they are no longer needed.
27-
let mut applicability = Applicability::MachineApplicable;
28+
let mut app = Applicability::MachineApplicable;
2829
let opt = snippet_opt(cx, cast_op.span);
2930
let sugg = opt.as_ref().map_or_else(
3031
|| {
31-
applicability = Applicability::HasPlaceholders;
32+
app = Applicability::HasPlaceholders;
3233
".."
3334
},
3435
|snip| {
@@ -40,10 +41,23 @@ pub(super) fn check(
4041
},
4142
);
4243

44+
// Display the type alias instead of the aliased type
45+
// FIXME: Do this for `cast_from` as well, if it ever becomes possible. Currently type aliases are
46+
// expanded when going from the HIR to `Ty`, so we can't reliably do so right now.
47+
let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind
48+
// It's a bit annoying but the turbofish is optional for types. I don't think there's any
49+
// way to have arguments on an alias to a primitive anyway, so it should be ok.
50+
&& path.segments.iter().all(|segment| segment.args.is_none())
51+
{
52+
snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app)
53+
} else {
54+
cast_to.to_string().into()
55+
};
56+
4357
let message = if cast_from.is_bool() {
44-
format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`")
58+
format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`")
4559
} else {
46-
format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type")
60+
format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type")
4761
};
4862

4963
span_lint_and_sugg(
@@ -52,8 +66,8 @@ pub(super) fn check(
5266
expr.span,
5367
&message,
5468
"try",
55-
format!("{cast_to}::from({sugg})"),
56-
applicability,
69+
format!("{cast_to_fmt}::from({sugg})"),
70+
app,
5771
);
5872
}
5973

clippy_lints/src/casts/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
739739
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
740740
cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
741741
}
742-
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
742+
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
743743
cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
744744
}
745745

tests/ui/cast_lossless_bool.fixed

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![allow(dead_code)]
44
#![warn(clippy::cast_lossless)]
55

6+
type U8 = u8;
7+
68
fn main() {
79
// Test clippy::cast_lossless with casts to integer types
810
let _ = u8::from(true);
@@ -21,6 +23,8 @@ fn main() {
2123

2224
// Test with an expression wrapped in parens
2325
let _ = u16::from(true | false);
26+
27+
let _ = U8::from(true);
2428
}
2529

2630
// The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const,

tests/ui/cast_lossless_bool.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![allow(dead_code)]
44
#![warn(clippy::cast_lossless)]
55

6+
type U8 = u8;
7+
68
fn main() {
79
// Test clippy::cast_lossless with casts to integer types
810
let _ = true as u8;
@@ -21,6 +23,8 @@ fn main() {
2123

2224
// Test with an expression wrapped in parens
2325
let _ = (true | false) as u16;
26+
27+
let _ = true as U8;
2428
}
2529

2630
// The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const,

tests/ui/cast_lossless_bool.stderr

+21-15
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,94 @@
11
error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
2-
--> $DIR/cast_lossless_bool.rs:8:13
2+
--> $DIR/cast_lossless_bool.rs:10:13
33
|
44
LL | let _ = true as u8;
55
| ^^^^^^^^^^ help: try: `u8::from(true)`
66
|
77
= note: `-D clippy::cast-lossless` implied by `-D warnings`
88

99
error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
10-
--> $DIR/cast_lossless_bool.rs:9:13
10+
--> $DIR/cast_lossless_bool.rs:11:13
1111
|
1212
LL | let _ = true as u16;
1313
| ^^^^^^^^^^^ help: try: `u16::from(true)`
1414

1515
error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)`
16-
--> $DIR/cast_lossless_bool.rs:10:13
16+
--> $DIR/cast_lossless_bool.rs:12:13
1717
|
1818
LL | let _ = true as u32;
1919
| ^^^^^^^^^^^ help: try: `u32::from(true)`
2020

2121
error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)`
22-
--> $DIR/cast_lossless_bool.rs:11:13
22+
--> $DIR/cast_lossless_bool.rs:13:13
2323
|
2424
LL | let _ = true as u64;
2525
| ^^^^^^^^^^^ help: try: `u64::from(true)`
2626

2727
error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)`
28-
--> $DIR/cast_lossless_bool.rs:12:13
28+
--> $DIR/cast_lossless_bool.rs:14:13
2929
|
3030
LL | let _ = true as u128;
3131
| ^^^^^^^^^^^^ help: try: `u128::from(true)`
3232

3333
error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)`
34-
--> $DIR/cast_lossless_bool.rs:13:13
34+
--> $DIR/cast_lossless_bool.rs:15:13
3535
|
3636
LL | let _ = true as usize;
3737
| ^^^^^^^^^^^^^ help: try: `usize::from(true)`
3838

3939
error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)`
40-
--> $DIR/cast_lossless_bool.rs:15:13
40+
--> $DIR/cast_lossless_bool.rs:17:13
4141
|
4242
LL | let _ = true as i8;
4343
| ^^^^^^^^^^ help: try: `i8::from(true)`
4444

4545
error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)`
46-
--> $DIR/cast_lossless_bool.rs:16:13
46+
--> $DIR/cast_lossless_bool.rs:18:13
4747
|
4848
LL | let _ = true as i16;
4949
| ^^^^^^^^^^^ help: try: `i16::from(true)`
5050

5151
error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)`
52-
--> $DIR/cast_lossless_bool.rs:17:13
52+
--> $DIR/cast_lossless_bool.rs:19:13
5353
|
5454
LL | let _ = true as i32;
5555
| ^^^^^^^^^^^ help: try: `i32::from(true)`
5656

5757
error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)`
58-
--> $DIR/cast_lossless_bool.rs:18:13
58+
--> $DIR/cast_lossless_bool.rs:20:13
5959
|
6060
LL | let _ = true as i64;
6161
| ^^^^^^^^^^^ help: try: `i64::from(true)`
6262

6363
error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)`
64-
--> $DIR/cast_lossless_bool.rs:19:13
64+
--> $DIR/cast_lossless_bool.rs:21:13
6565
|
6666
LL | let _ = true as i128;
6767
| ^^^^^^^^^^^^ help: try: `i128::from(true)`
6868

6969
error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)`
70-
--> $DIR/cast_lossless_bool.rs:20:13
70+
--> $DIR/cast_lossless_bool.rs:22:13
7171
|
7272
LL | let _ = true as isize;
7373
| ^^^^^^^^^^^^^ help: try: `isize::from(true)`
7474

7575
error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
76-
--> $DIR/cast_lossless_bool.rs:23:13
76+
--> $DIR/cast_lossless_bool.rs:25:13
7777
|
7878
LL | let _ = (true | false) as u16;
7979
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)`
8080

81+
error: casting `bool` to `U8` is more cleanly stated with `U8::from(_)`
82+
--> $DIR/cast_lossless_bool.rs:27:13
83+
|
84+
LL | let _ = true as U8;
85+
| ^^^^^^^^^^ help: try: `U8::from(true)`
86+
8187
error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
82-
--> $DIR/cast_lossless_bool.rs:51:13
88+
--> $DIR/cast_lossless_bool.rs:55:13
8389
|
8490
LL | let _ = true as u8;
8591
| ^^^^^^^^^^ help: try: `u8::from(true)`
8692

87-
error: aborting due to 14 previous errors
93+
error: aborting due to 15 previous errors
8894

tests/ui/cast_lossless_float.fixed

+5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
44
#![warn(clippy::cast_lossless)]
55

6+
type F32 = f32;
7+
type F64 = f64;
8+
69
fn main() {
710
// Test clippy::cast_lossless with casts to floating-point types
811
let x0 = 1i8;
912
let _ = f32::from(x0);
1013
let _ = f64::from(x0);
14+
let _ = F32::from(x0);
15+
let _ = F64::from(x0);
1116
let x1 = 1u8;
1217
let _ = f32::from(x1);
1318
let _ = f64::from(x1);

tests/ui/cast_lossless_float.rs

+5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
44
#![warn(clippy::cast_lossless)]
55

6+
type F32 = f32;
7+
type F64 = f64;
8+
69
fn main() {
710
// Test clippy::cast_lossless with casts to floating-point types
811
let x0 = 1i8;
912
let _ = x0 as f32;
1013
let _ = x0 as f64;
14+
let _ = x0 as F32;
15+
let _ = x0 as F64;
1116
let x1 = 1u8;
1217
let _ = x1 as f32;
1318
let _ = x1 as f64;

tests/ui/cast_lossless_float.stderr

+24-12
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,82 @@
11
error: casting `i8` to `f32` may become silently lossy if you later change the type
2-
--> $DIR/cast_lossless_float.rs:9:13
2+
--> $DIR/cast_lossless_float.rs:12:13
33
|
44
LL | let _ = x0 as f32;
55
| ^^^^^^^^^ help: try: `f32::from(x0)`
66
|
77
= note: `-D clippy::cast-lossless` implied by `-D warnings`
88

99
error: casting `i8` to `f64` may become silently lossy if you later change the type
10-
--> $DIR/cast_lossless_float.rs:10:13
10+
--> $DIR/cast_lossless_float.rs:13:13
1111
|
1212
LL | let _ = x0 as f64;
1313
| ^^^^^^^^^ help: try: `f64::from(x0)`
1414

15+
error: casting `i8` to `F32` may become silently lossy if you later change the type
16+
--> $DIR/cast_lossless_float.rs:14:13
17+
|
18+
LL | let _ = x0 as F32;
19+
| ^^^^^^^^^ help: try: `F32::from(x0)`
20+
21+
error: casting `i8` to `F64` may become silently lossy if you later change the type
22+
--> $DIR/cast_lossless_float.rs:15:13
23+
|
24+
LL | let _ = x0 as F64;
25+
| ^^^^^^^^^ help: try: `F64::from(x0)`
26+
1527
error: casting `u8` to `f32` may become silently lossy if you later change the type
16-
--> $DIR/cast_lossless_float.rs:12:13
28+
--> $DIR/cast_lossless_float.rs:17:13
1729
|
1830
LL | let _ = x1 as f32;
1931
| ^^^^^^^^^ help: try: `f32::from(x1)`
2032

2133
error: casting `u8` to `f64` may become silently lossy if you later change the type
22-
--> $DIR/cast_lossless_float.rs:13:13
34+
--> $DIR/cast_lossless_float.rs:18:13
2335
|
2436
LL | let _ = x1 as f64;
2537
| ^^^^^^^^^ help: try: `f64::from(x1)`
2638

2739
error: casting `i16` to `f32` may become silently lossy if you later change the type
28-
--> $DIR/cast_lossless_float.rs:15:13
40+
--> $DIR/cast_lossless_float.rs:20:13
2941
|
3042
LL | let _ = x2 as f32;
3143
| ^^^^^^^^^ help: try: `f32::from(x2)`
3244

3345
error: casting `i16` to `f64` may become silently lossy if you later change the type
34-
--> $DIR/cast_lossless_float.rs:16:13
46+
--> $DIR/cast_lossless_float.rs:21:13
3547
|
3648
LL | let _ = x2 as f64;
3749
| ^^^^^^^^^ help: try: `f64::from(x2)`
3850

3951
error: casting `u16` to `f32` may become silently lossy if you later change the type
40-
--> $DIR/cast_lossless_float.rs:18:13
52+
--> $DIR/cast_lossless_float.rs:23:13
4153
|
4254
LL | let _ = x3 as f32;
4355
| ^^^^^^^^^ help: try: `f32::from(x3)`
4456

4557
error: casting `u16` to `f64` may become silently lossy if you later change the type
46-
--> $DIR/cast_lossless_float.rs:19:13
58+
--> $DIR/cast_lossless_float.rs:24:13
4759
|
4860
LL | let _ = x3 as f64;
4961
| ^^^^^^^^^ help: try: `f64::from(x3)`
5062

5163
error: casting `i32` to `f64` may become silently lossy if you later change the type
52-
--> $DIR/cast_lossless_float.rs:21:13
64+
--> $DIR/cast_lossless_float.rs:26:13
5365
|
5466
LL | let _ = x4 as f64;
5567
| ^^^^^^^^^ help: try: `f64::from(x4)`
5668

5769
error: casting `u32` to `f64` may become silently lossy if you later change the type
58-
--> $DIR/cast_lossless_float.rs:23:13
70+
--> $DIR/cast_lossless_float.rs:28:13
5971
|
6072
LL | let _ = x5 as f64;
6173
| ^^^^^^^^^ help: try: `f64::from(x5)`
6274

6375
error: casting `f32` to `f64` may become silently lossy if you later change the type
64-
--> $DIR/cast_lossless_float.rs:26:13
76+
--> $DIR/cast_lossless_float.rs:31:13
6577
|
6678
LL | let _ = 1.0f32 as f64;
6779
| ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
6880

69-
error: aborting due to 11 previous errors
81+
error: aborting due to 13 previous errors
7082

tests/ui/cast_lossless_integer.fixed

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
44
#![warn(clippy::cast_lossless)]
55

6+
type I64 = i64;
7+
68
fn main() {
79
// Test clippy::cast_lossless with casts to integer types
810
let _ = i16::from(1i8);
@@ -26,6 +28,8 @@ fn main() {
2628

2729
// Test with an expression wrapped in parens
2830
let _ = u16::from(1u8 + 1u8);
31+
32+
let _ = I64::from(1i8);
2933
}
3034

3135
// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,

tests/ui/cast_lossless_integer.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
44
#![warn(clippy::cast_lossless)]
55

6+
type I64 = i64;
7+
68
fn main() {
79
// Test clippy::cast_lossless with casts to integer types
810
let _ = 1i8 as i16;
@@ -26,6 +28,8 @@ fn main() {
2628

2729
// Test with an expression wrapped in parens
2830
let _ = (1u8 + 1u8) as u16;
31+
32+
let _ = 1i8 as I64;
2933
}
3034

3135
// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,

0 commit comments

Comments
 (0)