Skip to content

Commit 4366edf

Browse files
committed
fix [cast_possible_truncation] offering wrong suggestion for casting float to integer
1 parent 41fa24c commit 4366edf

File tree

3 files changed

+83
-43
lines changed

3 files changed

+83
-43
lines changed

clippy_lints/src/casts/cast_possible_truncation.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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_help, span_lint_and_then};
33
use clippy_utils::expr_or_init;
44
use clippy_utils::source::snippet;
55
use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
@@ -85,6 +85,7 @@ pub(super) fn check(
8585
cast_to: Ty<'_>,
8686
cast_to_span: Span,
8787
) {
88+
let help = "if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...";
8889
let msg = match (cast_from.kind(), cast_to.is_integral()) {
8990
(ty::Int(_) | ty::Uint(_), true) => {
9091
let from_nbits = apply_reductions(
@@ -153,7 +154,14 @@ pub(super) fn check(
153154
},
154155

155156
(ty::Float(_), true) => {
156-
format!("casting `{cast_from}` to `{cast_to}` may truncate the value")
157+
return span_lint_and_help(
158+
cx,
159+
CAST_POSSIBLE_TRUNCATION,
160+
expr.span,
161+
&format!("casting `{cast_from}` to `{cast_to}` may truncate the value"),
162+
None,
163+
help,
164+
);
157165
},
158166

159167
(ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {
@@ -165,10 +173,14 @@ pub(super) fn check(
165173

166174
let name_of_cast_from = snippet(cx, cast_expr.span, "..");
167175
let cast_to_snip = snippet(cx, cast_to_span, "..");
168-
let suggestion = format!("{cast_to_snip}::try_from({name_of_cast_from})");
176+
let suggestion = if cast_to_snip == "_" {
177+
format!("<{cast_to_snip}>::try_from({name_of_cast_from})")
178+
} else {
179+
format!("{cast_to_snip}::try_from({name_of_cast_from})")
180+
};
169181

170182
span_lint_and_then(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg, |diag| {
171-
diag.help("if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...");
183+
diag.help(help);
172184
diag.span_suggestion_with_style(
173185
expr.span,
174186
"... or use `try_from` and handle the error accordingly",

tests/ui/cast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ fn main() {
2929
1f64 as isize;
3030
1f64 as usize;
3131
1f32 as u32 as u16;
32+
{
33+
let _x: i8 = 1i32 as _;
34+
1f32 as i32;
35+
1f64 as i32;
36+
1f32 as u8;
37+
}
3238
// Test clippy::cast_possible_wrap
3339
1u8 as i8;
3440
1u16 as i16;

tests/ui/cast.stderr

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ LL | 1f32 as i32;
4444
|
4545
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
4646
= 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-
| ~~~~~~~~~~~~~~~~~~~
5147

5248
error: casting `f32` to `u32` may truncate the value
5349
--> $DIR/cast.rs:25:5
@@ -56,10 +52,6 @@ LL | 1f32 as u32;
5652
| ^^^^^^^^^^^
5753
|
5854
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
59-
help: ... or use `try_from` and handle the error accordingly
60-
|
61-
LL | u32::try_from(1f32);
62-
| ~~~~~~~~~~~~~~~~~~~
6355

6456
error: casting `f32` to `u32` may lose the sign of the value
6557
--> $DIR/cast.rs:25:5
@@ -112,10 +104,6 @@ LL | 1f64 as isize;
112104
| ^^^^^^^^^^^^^
113105
|
114106
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
115-
help: ... or use `try_from` and handle the error accordingly
116-
|
117-
LL | isize::try_from(1f64);
118-
| ~~~~~~~~~~~~~~~~~~~~~
119107

120108
error: casting `f64` to `usize` may truncate the value
121109
--> $DIR/cast.rs:30:5
@@ -124,10 +112,6 @@ LL | 1f64 as usize;
124112
| ^^^^^^^^^^^^^
125113
|
126114
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
127-
help: ... or use `try_from` and handle the error accordingly
128-
|
129-
LL | usize::try_from(1f64);
130-
| ~~~~~~~~~~~~~~~~~~~~~
131115

132116
error: casting `f64` to `usize` may lose the sign of the value
133117
--> $DIR/cast.rs:30:5
@@ -154,63 +138,101 @@ LL | 1f32 as u32 as u16;
154138
| ^^^^^^^^^^^
155139
|
156140
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
157-
help: ... or use `try_from` and handle the error accordingly
158-
|
159-
LL | u32::try_from(1f32) as u16;
160-
| ~~~~~~~~~~~~~~~~~~~
161141

162142
error: casting `f32` to `u32` may lose the sign of the value
163143
--> $DIR/cast.rs:31:5
164144
|
165145
LL | 1f32 as u32 as u16;
166146
| ^^^^^^^^^^^
167147

148+
error: casting `i32` to `i8` may truncate the value
149+
--> $DIR/cast.rs:33:22
150+
|
151+
LL | let _x: i8 = 1i32 as _;
152+
| ^^^^^^^^^
153+
|
154+
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
155+
help: ... or use `try_from` and handle the error accordingly
156+
|
157+
LL | let _x: i8 = <_>::try_from(1i32);
158+
| ~~~~~~~~~~~~~~~~~~~
159+
160+
error: casting `f32` to `i32` may truncate the value
161+
--> $DIR/cast.rs:34:9
162+
|
163+
LL | 1f32 as i32;
164+
| ^^^^^^^^^^^
165+
|
166+
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
167+
168+
error: casting `f64` to `i32` may truncate the value
169+
--> $DIR/cast.rs:35:9
170+
|
171+
LL | 1f64 as i32;
172+
| ^^^^^^^^^^^
173+
|
174+
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
175+
176+
error: casting `f32` to `u8` may truncate the value
177+
--> $DIR/cast.rs:36:9
178+
|
179+
LL | 1f32 as u8;
180+
| ^^^^^^^^^^
181+
|
182+
= help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
183+
184+
error: casting `f32` to `u8` may lose the sign of the value
185+
--> $DIR/cast.rs:36:9
186+
|
187+
LL | 1f32 as u8;
188+
| ^^^^^^^^^^
189+
168190
error: casting `u8` to `i8` may wrap around the value
169-
--> $DIR/cast.rs:33:5
191+
--> $DIR/cast.rs:39:5
170192
|
171193
LL | 1u8 as i8;
172194
| ^^^^^^^^^
173195
|
174196
= note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
175197

176198
error: casting `u16` to `i16` may wrap around the value
177-
--> $DIR/cast.rs:34:5
199+
--> $DIR/cast.rs:40:5
178200
|
179201
LL | 1u16 as i16;
180202
| ^^^^^^^^^^^
181203

182204
error: casting `u32` to `i32` may wrap around the value
183-
--> $DIR/cast.rs:35:5
205+
--> $DIR/cast.rs:41:5
184206
|
185207
LL | 1u32 as i32;
186208
| ^^^^^^^^^^^
187209

188210
error: casting `u64` to `i64` may wrap around the value
189-
--> $DIR/cast.rs:36:5
211+
--> $DIR/cast.rs:42:5
190212
|
191213
LL | 1u64 as i64;
192214
| ^^^^^^^^^^^
193215

194216
error: casting `usize` to `isize` may wrap around the value
195-
--> $DIR/cast.rs:37:5
217+
--> $DIR/cast.rs:43:5
196218
|
197219
LL | 1usize as isize;
198220
| ^^^^^^^^^^^^^^^
199221

200222
error: casting `i32` to `u32` may lose the sign of the value
201-
--> $DIR/cast.rs:40:5
223+
--> $DIR/cast.rs:46:5
202224
|
203225
LL | -1i32 as u32;
204226
| ^^^^^^^^^^^^
205227

206228
error: casting `isize` to `usize` may lose the sign of the value
207-
--> $DIR/cast.rs:42:5
229+
--> $DIR/cast.rs:48:5
208230
|
209231
LL | -1isize as usize;
210232
| ^^^^^^^^^^^^^^^^
211233

212234
error: casting `i64` to `i8` may truncate the value
213-
--> $DIR/cast.rs:109:5
235+
--> $DIR/cast.rs:115:5
214236
|
215237
LL | (-99999999999i64).min(1) as i8; // should be linted because signed
216238
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -222,7 +244,7 @@ LL | i8::try_from((-99999999999i64).min(1)); // should be linted because sig
222244
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
223245

224246
error: casting `u64` to `u8` may truncate the value
225-
--> $DIR/cast.rs:121:5
247+
--> $DIR/cast.rs:127:5
226248
|
227249
LL | 999999u64.clamp(0, 256) as u8; // should still be linted
228250
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -234,7 +256,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted
234256
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
235257

236258
error: casting `main::E2` to `u8` may truncate the value
237-
--> $DIR/cast.rs:142:21
259+
--> $DIR/cast.rs:148:21
238260
|
239261
LL | let _ = self as u8;
240262
| ^^^^^^^^^^
@@ -246,15 +268,15 @@ LL | let _ = u8::try_from(self);
246268
| ~~~~~~~~~~~~~~~~~~
247269

248270
error: casting `main::E2::B` to `u8` will truncate the value
249-
--> $DIR/cast.rs:143:21
271+
--> $DIR/cast.rs:149:21
250272
|
251273
LL | let _ = Self::B as u8;
252274
| ^^^^^^^^^^^^^
253275
|
254276
= note: `-D clippy::cast-enum-truncation` implied by `-D warnings`
255277

256278
error: casting `main::E5` to `i8` may truncate the value
257-
--> $DIR/cast.rs:179:21
279+
--> $DIR/cast.rs:185:21
258280
|
259281
LL | let _ = self as i8;
260282
| ^^^^^^^^^^
@@ -266,13 +288,13 @@ LL | let _ = i8::try_from(self);
266288
| ~~~~~~~~~~~~~~~~~~
267289

268290
error: casting `main::E5::A` to `i8` will truncate the value
269-
--> $DIR/cast.rs:180:21
291+
--> $DIR/cast.rs:186:21
270292
|
271293
LL | let _ = Self::A as i8;
272294
| ^^^^^^^^^^^^^
273295

274296
error: casting `main::E6` to `i16` may truncate the value
275-
--> $DIR/cast.rs:194:21
297+
--> $DIR/cast.rs:200:21
276298
|
277299
LL | let _ = self as i16;
278300
| ^^^^^^^^^^^
@@ -284,7 +306,7 @@ LL | let _ = i16::try_from(self);
284306
| ~~~~~~~~~~~~~~~~~~~
285307

286308
error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
287-
--> $DIR/cast.rs:209:21
309+
--> $DIR/cast.rs:215:21
288310
|
289311
LL | let _ = self as usize;
290312
| ^^^^^^^^^^^^^
@@ -296,7 +318,7 @@ LL | let _ = usize::try_from(self);
296318
| ~~~~~~~~~~~~~~~~~~~~~
297319

298320
error: casting `main::E10` to `u16` may truncate the value
299-
--> $DIR/cast.rs:250:21
321+
--> $DIR/cast.rs:256:21
300322
|
301323
LL | let _ = self as u16;
302324
| ^^^^^^^^^^^
@@ -308,7 +330,7 @@ LL | let _ = u16::try_from(self);
308330
| ~~~~~~~~~~~~~~~~~~~
309331

310332
error: casting `u32` to `u8` may truncate the value
311-
--> $DIR/cast.rs:258:13
333+
--> $DIR/cast.rs:264:13
312334
|
313335
LL | let c = (q >> 16) as u8;
314336
| ^^^^^^^^^^^^^^^
@@ -320,7 +342,7 @@ LL | let c = u8::try_from((q >> 16));
320342
| ~~~~~~~~~~~~~~~~~~~~~~~
321343

322344
error: casting `u32` to `u8` may truncate the value
323-
--> $DIR/cast.rs:261:13
345+
--> $DIR/cast.rs:267:13
324346
|
325347
LL | let c = (q / 1000) as u8;
326348
| ^^^^^^^^^^^^^^^^
@@ -331,5 +353,5 @@ help: ... or use `try_from` and handle the error accordingly
331353
LL | let c = u8::try_from((q / 1000));
332354
| ~~~~~~~~~~~~~~~~~~~~~~~~
333355

334-
error: aborting due to 36 previous errors
356+
error: aborting due to 41 previous errors
335357

0 commit comments

Comments
 (0)