]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/casts/mod.rs
Auto merge of #8692 - kyoto7250:fixing_unnecessary_to_owned, r=giraffate
[rust.git] / clippy_lints / src / casts / mod.rs
1 mod cast_abs_to_unsigned;
2 mod cast_enum_constructor;
3 mod cast_lossless;
4 mod cast_possible_truncation;
5 mod cast_possible_wrap;
6 mod cast_precision_loss;
7 mod cast_ptr_alignment;
8 mod cast_ref_to_mut;
9 mod cast_sign_loss;
10 mod cast_slice_different_sizes;
11 mod char_lit_as_u8;
12 mod fn_to_numeric_cast;
13 mod fn_to_numeric_cast_any;
14 mod fn_to_numeric_cast_with_truncation;
15 mod ptr_as_ptr;
16 mod unnecessary_cast;
17 mod utils;
18
19 use clippy_utils::is_hir_ty_cfg_dependant;
20 use rustc_hir::{Expr, ExprKind};
21 use rustc_lint::{LateContext, LateLintPass, LintContext};
22 use rustc_middle::lint::in_external_macro;
23 use rustc_semver::RustcVersion;
24 use rustc_session::{declare_tool_lint, impl_lint_pass};
25
26 declare_clippy_lint! {
27     /// ### What it does
28     /// Checks for casts from any numerical to a float type where
29     /// the receiving type cannot store all values from the original type without
30     /// rounding errors. This possible rounding is to be expected, so this lint is
31     /// `Allow` by default.
32     ///
33     /// Basically, this warns on casting any integer with 32 or more bits to `f32`
34     /// or any 64-bit integer to `f64`.
35     ///
36     /// ### Why is this bad?
37     /// It's not bad at all. But in some applications it can be
38     /// helpful to know where precision loss can take place. This lint can help find
39     /// those places in the code.
40     ///
41     /// ### Example
42     /// ```rust
43     /// let x = u64::MAX;
44     /// x as f64;
45     /// ```
46     #[clippy::version = "pre 1.29.0"]
47     pub CAST_PRECISION_LOSS,
48     pedantic,
49     "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
50 }
51
52 declare_clippy_lint! {
53     /// ### What it does
54     /// Checks for casts from a signed to an unsigned numerical
55     /// type. In this case, negative values wrap around to large positive values,
56     /// which can be quite surprising in practice. However, as the cast works as
57     /// defined, this lint is `Allow` by default.
58     ///
59     /// ### Why is this bad?
60     /// Possibly surprising results. You can activate this lint
61     /// as a one-time check to see where numerical wrapping can arise.
62     ///
63     /// ### Example
64     /// ```rust
65     /// let y: i8 = -1;
66     /// y as u128; // will return 18446744073709551615
67     /// ```
68     #[clippy::version = "pre 1.29.0"]
69     pub CAST_SIGN_LOSS,
70     pedantic,
71     "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
72 }
73
74 declare_clippy_lint! {
75     /// ### What it does
76     /// Checks for casts between numerical types that may
77     /// truncate large values. This is expected behavior, so the cast is `Allow` by
78     /// default.
79     ///
80     /// ### Why is this bad?
81     /// In some problem domains, it is good practice to avoid
82     /// truncation. This lint can be activated to help assess where additional
83     /// checks could be beneficial.
84     ///
85     /// ### Example
86     /// ```rust
87     /// fn as_u8(x: u64) -> u8 {
88     ///     x as u8
89     /// }
90     /// ```
91     #[clippy::version = "pre 1.29.0"]
92     pub CAST_POSSIBLE_TRUNCATION,
93     pedantic,
94     "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
95 }
96
97 declare_clippy_lint! {
98     /// ### What it does
99     /// Checks for casts from an unsigned type to a signed type of
100     /// the same size. Performing such a cast is a 'no-op' for the compiler,
101     /// i.e., nothing is changed at the bit level, and the binary representation of
102     /// the value is reinterpreted. This can cause wrapping if the value is too big
103     /// for the target signed type. However, the cast works as defined, so this lint
104     /// is `Allow` by default.
105     ///
106     /// ### Why is this bad?
107     /// While such a cast is not bad in itself, the results can
108     /// be surprising when this is not the intended behavior, as demonstrated by the
109     /// example below.
110     ///
111     /// ### Example
112     /// ```rust
113     /// u32::MAX as i32; // will yield a value of `-1`
114     /// ```
115     #[clippy::version = "pre 1.29.0"]
116     pub CAST_POSSIBLE_WRAP,
117     pedantic,
118     "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
119 }
120
121 declare_clippy_lint! {
122     /// ### What it does
123     /// Checks for casts between numerical types that may
124     /// be replaced by safe conversion functions.
125     ///
126     /// ### Why is this bad?
127     /// Rust's `as` keyword will perform many kinds of
128     /// conversions, including silently lossy conversions. Conversion functions such
129     /// as `i32::from` will only perform lossless conversions. Using the conversion
130     /// functions prevents conversions from turning into silent lossy conversions if
131     /// the types of the input expressions ever change, and make it easier for
132     /// people reading the code to know that the conversion is lossless.
133     ///
134     /// ### Example
135     /// ```rust
136     /// fn as_u64(x: u8) -> u64 {
137     ///     x as u64
138     /// }
139     /// ```
140     ///
141     /// Using `::from` would look like this:
142     ///
143     /// ```rust
144     /// fn as_u64(x: u8) -> u64 {
145     ///     u64::from(x)
146     /// }
147     /// ```
148     #[clippy::version = "pre 1.29.0"]
149     pub CAST_LOSSLESS,
150     pedantic,
151     "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
152 }
153
154 declare_clippy_lint! {
155     /// ### What it does
156     /// Checks for casts to the same type, casts of int literals to integer types
157     /// and casts of float literals to float types.
158     ///
159     /// ### Why is this bad?
160     /// It's just unnecessary.
161     ///
162     /// ### Example
163     /// ```rust
164     /// let _ = 2i32 as i32;
165     /// let _ = 0.5 as f32;
166     /// ```
167     ///
168     /// Better:
169     ///
170     /// ```rust
171     /// let _ = 2_i32;
172     /// let _ = 0.5_f32;
173     /// ```
174     #[clippy::version = "pre 1.29.0"]
175     pub UNNECESSARY_CAST,
176     complexity,
177     "cast to the same type, e.g., `x as i32` where `x: i32`"
178 }
179
180 declare_clippy_lint! {
181     /// ### What it does
182     /// Checks for casts, using `as` or `pointer::cast`,
183     /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
184     ///
185     /// ### Why is this bad?
186     /// Dereferencing the resulting pointer may be undefined
187     /// behavior.
188     ///
189     /// ### Known problems
190     /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
191     /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
192     /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
193     ///
194     /// ### Example
195     /// ```rust
196     /// let _ = (&1u8 as *const u8) as *const u16;
197     /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
198     ///
199     /// (&1u8 as *const u8).cast::<u16>();
200     /// (&mut 1u8 as *mut u8).cast::<u16>();
201     /// ```
202     #[clippy::version = "pre 1.29.0"]
203     pub CAST_PTR_ALIGNMENT,
204     pedantic,
205     "cast from a pointer to a more-strictly-aligned pointer"
206 }
207
208 declare_clippy_lint! {
209     /// ### What it does
210     /// Checks for casts of function pointers to something other than usize
211     ///
212     /// ### Why is this bad?
213     /// Casting a function pointer to anything other than usize/isize is not portable across
214     /// architectures, because you end up losing bits if the target type is too small or end up with a
215     /// bunch of extra bits that waste space and add more instructions to the final binary than
216     /// strictly necessary for the problem
217     ///
218     /// Casting to isize also doesn't make sense since there are no signed addresses.
219     ///
220     /// ### Example
221     /// ```rust
222     /// // Bad
223     /// fn fun() -> i32 { 1 }
224     /// let a = fun as i64;
225     ///
226     /// // Good
227     /// fn fun2() -> i32 { 1 }
228     /// let a = fun2 as usize;
229     /// ```
230     #[clippy::version = "pre 1.29.0"]
231     pub FN_TO_NUMERIC_CAST,
232     style,
233     "casting a function pointer to a numeric type other than usize"
234 }
235
236 declare_clippy_lint! {
237     /// ### What it does
238     /// Checks for casts of a function pointer to a numeric type not wide enough to
239     /// store address.
240     ///
241     /// ### Why is this bad?
242     /// Such a cast discards some bits of the function's address. If this is intended, it would be more
243     /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
244     /// a comment) to perform the truncation.
245     ///
246     /// ### Example
247     /// ```rust
248     /// // Bad
249     /// fn fn1() -> i16 {
250     ///     1
251     /// };
252     /// let _ = fn1 as i32;
253     ///
254     /// // Better: Cast to usize first, then comment with the reason for the truncation
255     /// fn fn2() -> i16 {
256     ///     1
257     /// };
258     /// let fn_ptr = fn2 as usize;
259     /// let fn_ptr_truncated = fn_ptr as i32;
260     /// ```
261     #[clippy::version = "pre 1.29.0"]
262     pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
263     style,
264     "casting a function pointer to a numeric type not wide enough to store the address"
265 }
266
267 declare_clippy_lint! {
268     /// ### What it does
269     /// Checks for casts of a function pointer to any integer type.
270     ///
271     /// ### Why is this bad?
272     /// Casting a function pointer to an integer can have surprising results and can occur
273     /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
274     /// low-level with function pointers then you can opt-out of casting functions to integers in
275     /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
276     /// pointer casts in your code.
277     ///
278     /// ### Example
279     /// ```rust
280     /// // Bad: fn1 is cast as `usize`
281     /// fn fn1() -> u16 {
282     ///     1
283     /// };
284     /// let _ = fn1 as usize;
285     ///
286     /// // Good: maybe you intended to call the function?
287     /// fn fn2() -> u16 {
288     ///     1
289     /// };
290     /// let _ = fn2() as usize;
291     ///
292     /// // Good: maybe you intended to cast it to a function type?
293     /// fn fn3() -> u16 {
294     ///     1
295     /// }
296     /// let _ = fn3 as fn() -> u16;
297     /// ```
298     #[clippy::version = "1.58.0"]
299     pub FN_TO_NUMERIC_CAST_ANY,
300     restriction,
301     "casting a function pointer to any integer type"
302 }
303
304 declare_clippy_lint! {
305     /// ### What it does
306     /// Checks for casts of `&T` to `&mut T` anywhere in the code.
307     ///
308     /// ### Why is this bad?
309     /// It’s basically guaranteed to be undefined behaviour.
310     /// `UnsafeCell` is the only way to obtain aliasable data that is considered
311     /// mutable.
312     ///
313     /// ### Example
314     /// ```rust,ignore
315     /// fn x(r: &i32) {
316     ///     unsafe {
317     ///         *(r as *const _ as *mut _) += 1;
318     ///     }
319     /// }
320     /// ```
321     ///
322     /// Instead consider using interior mutability types.
323     ///
324     /// ```rust
325     /// use std::cell::UnsafeCell;
326     ///
327     /// fn x(r: &UnsafeCell<i32>) {
328     ///     unsafe {
329     ///         *r.get() += 1;
330     ///     }
331     /// }
332     /// ```
333     #[clippy::version = "1.33.0"]
334     pub CAST_REF_TO_MUT,
335     correctness,
336     "a cast of reference to a mutable pointer"
337 }
338
339 declare_clippy_lint! {
340     /// ### What it does
341     /// Checks for expressions where a character literal is cast
342     /// to `u8` and suggests using a byte literal instead.
343     ///
344     /// ### Why is this bad?
345     /// In general, casting values to smaller types is
346     /// error-prone and should be avoided where possible. In the particular case of
347     /// converting a character literal to u8, it is easy to avoid by just using a
348     /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
349     /// than `'a' as u8`.
350     ///
351     /// ### Example
352     /// ```rust,ignore
353     /// 'x' as u8
354     /// ```
355     ///
356     /// A better version, using the byte literal:
357     ///
358     /// ```rust,ignore
359     /// b'x'
360     /// ```
361     #[clippy::version = "pre 1.29.0"]
362     pub CHAR_LIT_AS_U8,
363     complexity,
364     "casting a character literal to `u8` truncates"
365 }
366
367 declare_clippy_lint! {
368     /// ### What it does
369     /// Checks for `as` casts between raw pointers without changing its mutability,
370     /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
371     ///
372     /// ### Why is this bad?
373     /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
374     /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
375     ///
376     /// ### Example
377     /// ```rust
378     /// let ptr: *const u32 = &42_u32;
379     /// let mut_ptr: *mut u32 = &mut 42_u32;
380     /// let _ = ptr as *const i32;
381     /// let _ = mut_ptr as *mut i32;
382     /// ```
383     /// Use instead:
384     /// ```rust
385     /// let ptr: *const u32 = &42_u32;
386     /// let mut_ptr: *mut u32 = &mut 42_u32;
387     /// let _ = ptr.cast::<i32>();
388     /// let _ = mut_ptr.cast::<i32>();
389     /// ```
390     #[clippy::version = "1.51.0"]
391     pub PTR_AS_PTR,
392     pedantic,
393     "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
394 }
395
396 declare_clippy_lint! {
397     /// ### What it does
398     /// Checks for casts from an enum type to an integral type which will definitely truncate the
399     /// value.
400     ///
401     /// ### Why is this bad?
402     /// The resulting integral value will not match the value of the variant it came from.
403     ///
404     /// ### Example
405     /// ```rust
406     /// enum E { X = 256 };
407     /// let _ = E::X as u8;
408     /// ```
409     #[clippy::version = "1.60.0"]
410     pub CAST_ENUM_TRUNCATION,
411     suspicious,
412     "casts from an enum type to an integral type which will truncate the value"
413 }
414
415 declare_clippy_lint! {
416     /// Checks for `as` casts between raw pointers to slices with differently sized elements.
417     ///
418     /// ### Why is this bad?
419     /// The produced raw pointer to a slice does not update its length metadata. The produced
420     /// pointer will point to a different number of bytes than the original pointer because the
421     /// length metadata of a raw slice pointer is in elements rather than bytes.
422     /// Producing a slice reference from the raw pointer will either create a slice with
423     /// less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
424     ///
425     /// ### Example
426     /// // Missing data
427     /// ```rust
428     /// let a = [1_i32, 2, 3, 4];
429     /// let p = &a as *const [i32] as *const [u8];
430     /// unsafe {
431     ///     println!("{:?}", &*p);
432     /// }
433     /// ```
434     /// // Undefined Behavior (note: also potential alignment issues)
435     /// ```rust
436     /// let a = [1_u8, 2, 3, 4];
437     /// let p = &a as *const [u8] as *const [u32];
438     /// unsafe {
439     ///     println!("{:?}", &*p);
440     /// }
441     /// ```
442     /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
443     /// ```rust
444     /// let a = [1_i32, 2, 3, 4];
445     /// let old_ptr = &a as *const [i32];
446     /// // The data pointer is cast to a pointer to the target `u8` not `[u8]`
447     /// // The length comes from the known length of 4 i32s times the 4 bytes per i32
448     /// let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
449     /// unsafe {
450     ///     println!("{:?}", &*new_ptr);
451     /// }
452     /// ```
453     #[clippy::version = "1.60.0"]
454     pub CAST_SLICE_DIFFERENT_SIZES,
455     correctness,
456     "casting using `as` between raw pointers to slices of types with different sizes"
457 }
458
459 declare_clippy_lint! {
460     /// ### What it does
461     /// Checks for casts from an enum tuple constructor to an integer.
462     ///
463     /// ### Why is this bad?
464     /// The cast is easily confused with casting a c-like enum value to an integer.
465     ///
466     /// ### Example
467     /// ```rust
468     /// enum E { X(i32) };
469     /// let _ = E::X as usize;
470     /// ```
471     #[clippy::version = "1.61.0"]
472     pub CAST_ENUM_CONSTRUCTOR,
473     suspicious,
474     "casts from an enum tuple constructor to an integer"
475 }
476
477 declare_clippy_lint! {
478     /// ### What it does
479     /// Checks for uses of the `abs()` method that cast the result to unsigned.
480     ///
481     /// ### Why is this bad?
482     /// The `unsigned_abs()` method avoids panic when called on the MIN value.
483     ///
484     /// ### Example
485     /// ```rust
486     /// let x: i32 = -42;
487     /// let y: u32 = x.abs() as u32;
488     /// ```
489     /// Use instead:
490     /// let x: i32 = -42;
491     /// let y: u32 = x.unsigned_abs();
492     /// ```
493     #[clippy::version = "1.61.0"]
494     pub CAST_ABS_TO_UNSIGNED,
495     suspicious,
496     "casting the result of `abs()` to an unsigned integer can panic"
497 }
498
499 pub struct Casts {
500     msrv: Option<RustcVersion>,
501 }
502
503 impl Casts {
504     #[must_use]
505     pub fn new(msrv: Option<RustcVersion>) -> Self {
506         Self { msrv }
507     }
508 }
509
510 impl_lint_pass!(Casts => [
511     CAST_PRECISION_LOSS,
512     CAST_SIGN_LOSS,
513     CAST_POSSIBLE_TRUNCATION,
514     CAST_POSSIBLE_WRAP,
515     CAST_LOSSLESS,
516     CAST_REF_TO_MUT,
517     CAST_PTR_ALIGNMENT,
518     CAST_SLICE_DIFFERENT_SIZES,
519     UNNECESSARY_CAST,
520     FN_TO_NUMERIC_CAST_ANY,
521     FN_TO_NUMERIC_CAST,
522     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
523     CHAR_LIT_AS_U8,
524     PTR_AS_PTR,
525     CAST_ENUM_TRUNCATION,
526     CAST_ENUM_CONSTRUCTOR,
527     CAST_ABS_TO_UNSIGNED
528 ]);
529
530 impl<'tcx> LateLintPass<'tcx> for Casts {
531     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
532         if !in_external_macro(cx.sess(), expr.span) {
533             ptr_as_ptr::check(cx, expr, &self.msrv);
534         }
535
536         if expr.span.from_expansion() {
537             return;
538         }
539
540         if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
541             if is_hir_ty_cfg_dependant(cx, cast_to) {
542                 return;
543             }
544             let (cast_from, cast_to) = (
545                 cx.typeck_results().expr_ty(cast_expr),
546                 cx.typeck_results().expr_ty(expr),
547             );
548
549             if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
550                 return;
551             }
552
553             fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
554             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
555             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
556
557             if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
558                 cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
559                 if cast_from.is_numeric() {
560                     cast_possible_wrap::check(cx, expr, cast_from, cast_to);
561                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
562                     cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
563                     cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
564                 }
565                 cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
566                 cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
567             }
568         }
569
570         cast_ref_to_mut::check(cx, expr);
571         cast_ptr_alignment::check(cx, expr);
572         char_lit_as_u8::check(cx, expr);
573         ptr_as_ptr::check(cx, expr, &self.msrv);
574         cast_slice_different_sizes::check(cx, expr, &self.msrv);
575     }
576
577     extract_msrv_attr!(LateContext);
578 }