Skip to content

Commit d054509

Browse files
author
navh
committed
rust-lang#9231 suggest TryFrom when truncation possible
1 parent 8ccd6e8 commit d054509

File tree

4 files changed

+52
-191
lines changed

4 files changed

+52
-191
lines changed

clippy_lints/src/casts/cast_possible_truncation.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use clippy_utils::consts::{constant, Constant};
2-
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
2+
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
33
use clippy_utils::expr_or_init;
4-
use clippy_utils::source::snippet;
4+
use clippy_utils::source::snippet_with_applicability;
55
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
66
use rustc_ast::ast;
77
use rustc_attr::IntType;
8-
use rustc_errors::{Applicability, SuggestionStyle};
8+
use rustc_errors::Applicability;
99
use rustc_hir::def::{DefKind, Res};
1010
use rustc_hir::{BinOpKind, Expr, ExprKind};
1111
use rustc_lint::LateContext;
@@ -161,19 +161,18 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
161161
_ => return,
162162
};
163163

164-
let snippet = snippet(cx, expr.span, "x");
164+
let mut applicability = Applicability::MachineApplicable;
165+
166+
let snippet = snippet_with_applicability(cx, expr.span, "x", &mut applicability);
165167
let name_of_cast_from = snippet.split(" as").next().unwrap_or("x");
166-
let suggestion = format!("{cast_to}::try_from({name_of_cast_from})");
167-
168-
span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
169-
diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...");
170-
diag.span_suggestion_with_style(
171-
expr.span,
172-
"... or use `try_from` and handle the error accordingly",
173-
suggestion,
174-
Applicability::Unspecified,
175-
// always show the suggestion in a separate line
176-
SuggestionStyle::ShowAlways,
177-
);
178-
});
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+
);
179178
}

src/docs/cast_possible_truncation.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,14 @@ checks could be beneficial, and suggests implementing TryFrom trait.
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 & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +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
|
45-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
4645
= note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
47-
help: ... or use `try_from` and handle the error accordingly
48-
|
49-
LL | i32::try_from(1f32);
50-
| ~~~~~~~~~~~~~~~~~~~
5146

5247
error: casting `f32` to `u32` may truncate the value
5348
--> $DIR/cast.rs:25:5
5449
|
5550
LL | 1f32 as u32;
56-
| ^^^^^^^^^^^
57-
|
58-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
59-
help: ... or use `try_from` and handle the error accordingly
60-
|
61-
LL | u32::try_from(1f32);
62-
| ~~~~~~~~~~~~~~~~~~~
51+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `u32::try_from(1f32).unwrap()`
6352

6453
error: casting `f32` to `u32` may lose the sign of the value
6554
--> $DIR/cast.rs:25:5
@@ -73,61 +62,31 @@ error: casting `f64` to `f32` may truncate the value
7362
--> $DIR/cast.rs:26:5
7463
|
7564
LL | 1f64 as f32;
76-
| ^^^^^^^^^^^
77-
|
78-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
79-
help: ... or use `try_from` and handle the error accordingly
80-
|
81-
LL | f32::try_from(1f64);
82-
| ~~~~~~~~~~~~~~~~~~~
65+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `f32::try_from(1f64).unwrap()`
8366

8467
error: casting `i32` to `i8` may truncate the value
8568
--> $DIR/cast.rs:27:5
8669
|
8770
LL | 1i32 as i8;
88-
| ^^^^^^^^^^
89-
|
90-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
91-
help: ... or use `try_from` and handle the error accordingly
92-
|
93-
LL | i8::try_from(1i32);
94-
| ~~~~~~~~~~~~~~~~~~
71+
| ^^^^^^^^^^ help: avoid silent truncation by using: `i8::try_from(1i32).unwrap()`
9572

9673
error: casting `i32` to `u8` may truncate the value
9774
--> $DIR/cast.rs:28:5
9875
|
9976
LL | 1i32 as u8;
100-
| ^^^^^^^^^^
101-
|
102-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
103-
help: ... or use `try_from` and handle the error accordingly
104-
|
105-
LL | u8::try_from(1i32);
106-
| ~~~~~~~~~~~~~~~~~~
77+
| ^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from(1i32).unwrap()`
10778

10879
error: casting `f64` to `isize` may truncate the value
10980
--> $DIR/cast.rs:29:5
11081
|
11182
LL | 1f64 as isize;
112-
| ^^^^^^^^^^^^^
113-
|
114-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
115-
help: ... or use `try_from` and handle the error accordingly
116-
|
117-
LL | isize::try_from(1f64);
118-
| ~~~~~~~~~~~~~~~~~~~~~
83+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `isize::try_from(1f64).unwrap()`
11984

12085
error: casting `f64` to `usize` may truncate the value
12186
--> $DIR/cast.rs:30:5
12287
|
12388
LL | 1f64 as usize;
124-
| ^^^^^^^^^^^^^
125-
|
126-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
127-
help: ... or use `try_from` and handle the error accordingly
128-
|
129-
LL | usize::try_from(1f64);
130-
| ~~~~~~~~~~~~~~~~~~~~~
89+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `usize::try_from(1f64).unwrap()`
13190

13291
error: casting `f64` to `usize` may lose the sign of the value
13392
--> $DIR/cast.rs:30:5
@@ -183,37 +142,19 @@ error: casting `i64` to `i8` may truncate the value
183142
--> $DIR/cast.rs:108:5
184143
|
185144
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
186-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
187-
|
188-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
189-
help: ... or use `try_from` and handle the error accordingly
190-
|
191-
LL | i8::try_from((-99999999999i64).min(1)); // should be linted because signed
192-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
145+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `i8::try_from((-99999999999i64).min(1)).unwrap()`
193146

194147
error: casting `u64` to `u8` may truncate the value
195148
--> $DIR/cast.rs:120:5
196149
|
197150
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
198-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
199-
|
200-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
201-
help: ... or use `try_from` and handle the error accordingly
202-
|
203-
LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted
204-
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
151+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from(999999u64.clamp(0, 256)).unwrap()`
205152

206153
error: casting `main::E2` to `u8` may truncate the value
207154
--> $DIR/cast.rs:141:21
208155
|
209156
LL | let _ = self as u8;
210-
| ^^^^^^^^^^
211-
|
212-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
213-
help: ... or use `try_from` and handle the error accordingly
214-
|
215-
LL | let _ = u8::try_from(self);
216-
| ~~~~~~~~~~~~~~~~~~
157+
| ^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from(self).unwrap()`
217158

218159
error: casting `main::E2::B` to `u8` will truncate the value
219160
--> $DIR/cast.rs:142:21
@@ -227,13 +168,7 @@ error: casting `main::E5` to `i8` may truncate the value
227168
--> $DIR/cast.rs:178:21
228169
|
229170
LL | let _ = self as i8;
230-
| ^^^^^^^^^^
231-
|
232-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
233-
help: ... or use `try_from` and handle the error accordingly
234-
|
235-
LL | let _ = i8::try_from(self);
236-
| ~~~~~~~~~~~~~~~~~~
171+
| ^^^^^^^^^^ help: avoid silent truncation by using: `i8::try_from(self).unwrap()`
237172

238173
error: casting `main::E5::A` to `i8` will truncate the value
239174
--> $DIR/cast.rs:179:21
@@ -245,61 +180,31 @@ error: casting `main::E6` to `i16` may truncate the value
245180
--> $DIR/cast.rs:193:21
246181
|
247182
LL | let _ = self as i16;
248-
| ^^^^^^^^^^^
249-
|
250-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
251-
help: ... or use `try_from` and handle the error accordingly
252-
|
253-
LL | let _ = i16::try_from(self);
254-
| ~~~~~~~~~~~~~~~~~~~
183+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `i16::try_from(self).unwrap()`
255184

256185
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
257186
--> $DIR/cast.rs:208:21
258187
|
259188
LL | let _ = self as usize;
260-
| ^^^^^^^^^^^^^
261-
|
262-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
263-
help: ... or use `try_from` and handle the error accordingly
264-
|
265-
LL | let _ = usize::try_from(self);
266-
| ~~~~~~~~~~~~~~~~~~~~~
189+
| ^^^^^^^^^^^^^ help: avoid silent truncation by using: `usize::try_from(self).unwrap()`
267190

268191
error: casting `main::E10` to `u16` may truncate the value
269192
--> $DIR/cast.rs:249:21
270193
|
271194
LL | let _ = self as u16;
272-
| ^^^^^^^^^^^
273-
|
274-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
275-
help: ... or use `try_from` and handle the error accordingly
276-
|
277-
LL | let _ = u16::try_from(self);
278-
| ~~~~~~~~~~~~~~~~~~~
195+
| ^^^^^^^^^^^ help: avoid silent truncation by using: `u16::try_from(self).unwrap()`
279196

280197
error: casting `u32` to `u8` may truncate the value
281198
--> $DIR/cast.rs:257:13
282199
|
283200
LL | let c = (q >> 16) as u8;
284-
| ^^^^^^^^^^^^^^^
285-
|
286-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
287-
help: ... or use `try_from` and handle the error accordingly
288-
|
289-
LL | let c = u8::try_from((q >> 16));
290-
| ~~~~~~~~~~~~~~~~~~~~~~~
201+
| ^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from((q >> 16)).unwrap()`
291202

292203
error: casting `u32` to `u8` may truncate the value
293204
--> $DIR/cast.rs:260:13
294205
|
295206
LL | let c = (q / 1000) as u8;
296-
| ^^^^^^^^^^^^^^^^
297-
|
298-
= help: if this is intentional allow the lint with `#[allow(clippy::cast_precision_loss)]` ...
299-
help: ... or use `try_from` and handle the error accordingly
300-
|
301-
LL | let c = u8::try_from((q / 1000));
302-
| ~~~~~~~~~~~~~~~~~~~~~~~~
207+
| ^^^^^^^^^^^^^^^^ help: avoid silent truncation by using: `u8::try_from((q / 1000)).unwrap()`
303208

304209
error: aborting due to 33 previous errors
305210

0 commit comments

Comments
 (0)