Skip to content

Commit 699b140

Browse files
author
navh
committed
rust-lang#9231 suggest TryFrom when truncation possible
1 parent b72e451 commit 699b140

File tree

4 files changed

+55
-30
lines changed

4 files changed

+55
-30
lines changed

clippy_lints/src/casts/cast_possible_truncation.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
use clippy_utils::consts::{constant, Constant};
2-
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
33
use clippy_utils::expr_or_init;
4+
use clippy_utils::source::snippet_with_applicability;
45
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
56
use rustc_ast::ast;
67
use rustc_attr::IntType;
8+
use rustc_errors::Applicability;
79
use rustc_hir::def::{DefKind, Res};
810
use rustc_hir::{BinOpKind, Expr, ExprKind};
911
use rustc_lint::LateContext;
@@ -145,7 +147,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
145147
);
146148
return;
147149
}
148-
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
150+
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
149151
},
150152

151153
(ty::Float(_), true) => {
@@ -159,5 +161,18 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
159161
_ => return,
160162
};
161163

162-
span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg);
164+
let mut applicability = Applicability::MachineApplicable;
165+
166+
let snippet = snippet_with_applicability(cx, expr.span, "x", &mut applicability);
167+
let name_of_cast_from = snippet.split(" as").next().unwrap_or("x");
168+
169+
span_lint_and_sugg(
170+
cx,
171+
CAST_POSSIBLE_TRUNCATION,
172+
expr.span,
173+
&msg,
174+
"avoid silent truncation by using",
175+
format!("{cast_to}::try_from({name_of_cast_from}).unwrap()"),
176+
applicability,
177+
);
163178
}

src/docs/cast_possible_truncation.txt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,21 @@ default.
66
### Why is this bad?
77
In some problem domains, it is good practice to avoid
88
truncation. This lint can be activated to help assess where additional
9-
checks could be beneficial.
9+
checks could be beneficial, and suggests implementing TryFrom trait.
1010

1111
### Example
1212
```
1313
fn as_u8(x: u64) -> u8 {
1414
x as u8
1515
}
16-
```
16+
```
17+
18+
will silently truncate requiring detection and handling after the fact.
19+
20+
```
21+
fn as_u8(x: u64) -> u8 {
22+
u8::try_from(x).unwrap()
23+
}
24+
```
25+
26+
does not, but can now panic.

tests/ui/cast.stderr

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ error: casting `f32` to `i32` may truncate the value
4040
--> $DIR/cast.rs:24:5
4141
|
4242
LL | 1f32 as i32;
43-
| ^^^^^^^^^^^
43+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `i32::try_from(1f32).unwrap()`
4444
|
4545
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
4646

4747
error: casting `f32` to `u32` may truncate the value
4848
--> $DIR/cast.rs:25:5
4949
|
5050
LL | 1f32 as u32;
51-
| ^^^^^^^^^^^
51+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `u32::try_from(1f32).unwrap()`
5252

5353
error: casting `f32` to `u32` may lose the sign of the value
5454
--> $DIR/cast.rs:25:5
@@ -62,31 +62,31 @@ error: casting `f64` to `f32` may truncate the value
6262
--> $DIR/cast.rs:26:5
6363
|
6464
LL | 1f64 as f32;
65-
| ^^^^^^^^^^^
65+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `f32::try_from(1f64).unwrap()`
6666

6767
error: casting `i32` to `i8` may truncate the value
6868
--> $DIR/cast.rs:27:5
6969
|
7070
LL | 1i32 as i8;
71-
| ^^^^^^^^^^
71+
| ^^^^^^^^^^ help: avoid silent truncation by using: `i8::try_from(1i32).unwrap()`
7272

7373
error: casting `i32` to `u8` may truncate the value
7474
--> $DIR/cast.rs:28:5
7575
|
7676
LL | 1i32 as u8;
77-
| ^^^^^^^^^^
77+
| ^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from(1i32).unwrap()`
7878

7979
error: casting `f64` to `isize` may truncate the value
8080
--> $DIR/cast.rs:29:5
8181
|
8282
LL | 1f64 as isize;
83-
| ^^^^^^^^^^^^^
83+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `isize::try_from(1f64).unwrap()`
8484

8585
error: casting `f64` to `usize` may truncate the value
8686
--> $DIR/cast.rs:30:5
8787
|
8888
LL | 1f64 as usize;
89-
| ^^^^^^^^^^^^^
89+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `usize::try_from(1f64).unwrap()`
9090

9191
error: casting `f64` to `usize` may lose the sign of the value
9292
--> $DIR/cast.rs:30:5
@@ -142,19 +142,19 @@ error: casting `i64` to `i8` may truncate the value
142142
--> $DIR/cast.rs:108:5
143143
|
144144
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
145-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
145+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `i8::try_from((-99999999999i64).min(1)).unwrap()`
146146

147147
error: casting `u64` to `u8` may truncate the value
148148
--> $DIR/cast.rs:120:5
149149
|
150150
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
151-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
151+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from(999999u64.clamp(0, 256)).unwrap()`
152152

153153
error: casting `main::E2` to `u8` may truncate the value
154154
--> $DIR/cast.rs:141:21
155155
|
156156
LL | let _ = self as u8;
157-
| ^^^^^^^^^^
157+
| ^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from(self).unwrap()`
158158

159159
error: casting `main::E2::B` to `u8` will truncate the value
160160
--> $DIR/cast.rs:142:21
@@ -168,7 +168,7 @@ error: casting `main::E5` to `i8` may truncate the value
168168
--> $DIR/cast.rs:178:21
169169
|
170170
LL | let _ = self as i8;
171-
| ^^^^^^^^^^
171+
| ^^^^^^^^^^ help: avoid silent truncation by using: `i8::try_from(self).unwrap()`
172172

173173
error: casting `main::E5::A` to `i8` will truncate the value
174174
--> $DIR/cast.rs:179:21
@@ -180,31 +180,31 @@ error: casting `main::E6` to `i16` may truncate the value
180180
--> $DIR/cast.rs:193:21
181181
|
182182
LL | let _ = self as i16;
183-
| ^^^^^^^^^^^
183+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `i16::try_from(self).unwrap()`
184184

185185
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
186186
--> $DIR/cast.rs:208:21
187187
|
188188
LL | let _ = self as usize;
189-
| ^^^^^^^^^^^^^
189+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `usize::try_from(self).unwrap()`
190190

191191
error: casting `main::E10` to `u16` may truncate the value
192192
--> $DIR/cast.rs:249:21
193193
|
194194
LL | let _ = self as u16;
195-
| ^^^^^^^^^^^
195+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `u16::try_from(self).unwrap()`
196196

197197
error: casting `u32` to `u8` may truncate the value
198198
--> $DIR/cast.rs:257:13
199199
|
200200
LL | let c = (q >> 16) as u8;
201-
| ^^^^^^^^^^^^^^^
201+
| ^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from((q >> 16)).unwrap()`
202202

203203
error: casting `u32` to `u8` may truncate the value
204204
--> $DIR/cast.rs:260:13
205205
|
206206
LL | let c = (q / 1000) as u8;
207-
| ^^^^^^^^^^^^^^^^
207+
| ^^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from((q / 1000)).unwrap()`
208208

209209
error: aborting due to 33 previous errors
210210

tests/ui/cast_size.stderr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: casting `isize` to `i8` may truncate the value
22
--> $DIR/cast_size.rs:12:5
33
|
44
LL | 1isize as i8;
5-
| ^^^^^^^^^^^^
5+
| ^^^^^^^^^^^^ help: avoid silent truncation by using: `i8::try_from(1isize).unwrap()`
66
|
77
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
88

@@ -36,25 +36,25 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi
3636
--> $DIR/cast_size.rs:19:5
3737
|
3838
LL | 1isize as i32;
39-
| ^^^^^^^^^^^^^
39+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `i32::try_from(1isize).unwrap()`
4040

4141
error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers
4242
--> $DIR/cast_size.rs:20:5
4343
|
4444
LL | 1isize as u32;
45-
| ^^^^^^^^^^^^^
45+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `u32::try_from(1isize).unwrap()`
4646

4747
error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers
4848
--> $DIR/cast_size.rs:21:5
4949
|
5050
LL | 1usize as u32;
51-
| ^^^^^^^^^^^^^
51+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `u32::try_from(1usize).unwrap()`
5252

5353
error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
5454
--> $DIR/cast_size.rs:22:5
5555
|
5656
LL | 1usize as i32;
57-
| ^^^^^^^^^^^^^
57+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `i32::try_from(1usize).unwrap()`
5858

5959
error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
6060
--> $DIR/cast_size.rs:22:5
@@ -68,19 +68,19 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi
6868
--> $DIR/cast_size.rs:24:5
6969
|
7070
LL | 1i64 as isize;
71-
| ^^^^^^^^^^^^^
71+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `isize::try_from(1i64).unwrap()`
7272

7373
error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
7474
--> $DIR/cast_size.rs:25:5
7575
|
7676
LL | 1i64 as usize;
77-
| ^^^^^^^^^^^^^
77+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `usize::try_from(1i64).unwrap()`
7878

7979
error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
8080
--> $DIR/cast_size.rs:26:5
8181
|
8282
LL | 1u64 as isize;
83-
| ^^^^^^^^^^^^^
83+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `isize::try_from(1u64).unwrap()`
8484

8585
error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
8686
--> $DIR/cast_size.rs:26:5
@@ -92,7 +92,7 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi
9292
--> $DIR/cast_size.rs:27:5
9393
|
9494
LL | 1u64 as usize;
95-
| ^^^^^^^^^^^^^
95+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `usize::try_from(1u64).unwrap()`
9696

9797
error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
9898
--> $DIR/cast_size.rs:28:5

0 commit comments

Comments
 (0)