| mod as_pointer_underscore; |
| mod as_ptr_cast_mut; |
| mod as_underscore; |
| mod borrow_as_ptr; |
| mod cast_abs_to_unsigned; |
| mod cast_enum_constructor; |
| mod cast_lossless; |
| mod cast_nan_to_int; |
| mod cast_possible_truncation; |
| mod cast_possible_wrap; |
| mod cast_precision_loss; |
| mod cast_ptr_alignment; |
| mod cast_sign_loss; |
| mod cast_slice_different_sizes; |
| mod cast_slice_from_raw_parts; |
| mod char_lit_as_u8; |
| mod confusing_method_to_numeric_cast; |
| mod fn_to_numeric_cast; |
| mod fn_to_numeric_cast_any; |
| mod fn_to_numeric_cast_with_truncation; |
| mod manual_dangling_ptr; |
| mod needless_type_cast; |
| mod ptr_as_ptr; |
| mod ptr_cast_constness; |
| mod ref_as_ptr; |
| mod unnecessary_cast; |
| mod utils; |
| mod zero_ptr; |
| |
| use clippy_config::Conf; |
| use clippy_utils::is_hir_ty_cfg_dependant; |
| use clippy_utils::msrvs::{self, Msrv}; |
| use rustc_hir::{Expr, ExprKind}; |
| use rustc_lint::{LateContext, LateLintPass, LintContext}; |
| use rustc_session::impl_lint_pass; |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts from any numeric type to a float type where |
| /// the receiving type cannot store all values from the original type without |
| /// rounding errors. This possible rounding is to be expected, so this lint is |
| /// `Allow` by default. |
| /// |
| /// Basically, this warns on casting any integer with 32 or more bits to `f32` |
| /// or any 64-bit integer to `f64`. |
| /// |
| /// ### Why is this bad? |
| /// It's not bad at all. But in some applications it can be |
| /// helpful to know where precision loss can take place. This lint can help find |
| /// those places in the code. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let x = u64::MAX; |
| /// x as f64; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub CAST_PRECISION_LOSS, |
| pedantic, |
| "casts that cause loss of precision, e.g., `x as f32` where `x: u64`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts from a signed to an unsigned numeric |
| /// type. In this case, negative values wrap around to large positive values, |
| /// which can be quite surprising in practice. However, since the cast works as |
| /// defined, this lint is `Allow` by default. |
| /// |
| /// ### Why is this bad? |
| /// Possibly surprising results. You can activate this lint |
| /// as a one-time check to see where numeric wrapping can arise. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let y: i8 = -1; |
| /// y as u64; // will return 18446744073709551615 |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub CAST_SIGN_LOSS, |
| pedantic, |
| "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts between numeric types that may |
| /// truncate large values. This is expected behavior, so the cast is `Allow` by |
| /// default. It suggests user either explicitly ignore the lint, |
| /// or use `try_from()` and handle the truncation, default, or panic explicitly. |
| /// |
| /// ### Why is this bad? |
| /// In some problem domains, it is good practice to avoid |
| /// truncation. This lint can be activated to help assess where additional |
| /// checks could be beneficial. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn as_u8(x: u64) -> u8 { |
| /// x as u8 |
| /// } |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// fn as_u8(x: u64) -> u8 { |
| /// if let Ok(x) = u8::try_from(x) { |
| /// x |
| /// } else { |
| /// todo!(); |
| /// } |
| /// } |
| /// // Or |
| /// #[allow(clippy::cast_possible_truncation)] |
| /// fn as_u16(x: u64) -> u16 { |
| /// x as u16 |
| /// } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub CAST_POSSIBLE_TRUNCATION, |
| pedantic, |
| "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts from an unsigned type to a signed type of |
| /// the same size, or possibly smaller due to target-dependent integers. |
| /// Performing such a cast is a no-op for the compiler (that is, nothing is |
| /// changed at the bit level), and the binary representation of the value is |
| /// reinterpreted. This can cause wrapping if the value is too big |
| /// for the target signed type. However, the cast works as defined, so this lint |
| /// is `Allow` by default. |
| /// |
| /// ### Why is this bad? |
| /// While such a cast is not bad in itself, the results can |
| /// be surprising when this is not the intended behavior: |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let _ = u32::MAX as i32; // will yield a value of `-1` |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// let _ = i32::try_from(u32::MAX).ok(); |
| /// ``` |
| /// |
| #[clippy::version = "pre 1.29.0"] |
| pub CAST_POSSIBLE_WRAP, |
| pedantic, |
| "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts between numeric types that can be replaced by safe |
| /// conversion functions. |
| /// |
| /// ### Why is this bad? |
| /// Rust's `as` keyword will perform many kinds of conversions, including |
| /// silently lossy conversions. Conversion functions such as `i32::from` |
| /// will only perform lossless conversions. Using the conversion functions |
| /// prevents conversions from becoming silently lossy if the input types |
| /// ever change, and makes it clear for people reading the code that the |
| /// conversion is lossless. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn as_u64(x: u8) -> u64 { |
| /// x as u64 |
| /// } |
| /// ``` |
| /// |
| /// Using `::from` would look like this: |
| /// |
| /// ```no_run |
| /// fn as_u64(x: u8) -> u64 { |
| /// u64::from(x) |
| /// } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub CAST_LOSSLESS, |
| pedantic, |
| "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts to the same type, casts of int literals to integer |
| /// types, casts of float literals to float types, and casts between raw |
| /// pointers that don't change type or constness. |
| /// |
| /// ### Why is this bad? |
| /// It's just unnecessary. |
| /// |
| /// ### Known problems |
| /// When the expression on the left is a function call, the lint considers |
| /// the return type to be a type alias if it's aliased through a `use` |
| /// statement (like `use std::io::Result as IoResult`). It will not lint |
| /// such cases. |
| /// |
| /// This check will only work on primitive types without any intermediate |
| /// references: raw pointers and trait objects may or may not work. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let _ = 2i32 as i32; |
| /// let _ = 0.5 as f32; |
| /// ``` |
| /// |
| /// Better: |
| /// |
| /// ```no_run |
| /// let _ = 2_i32; |
| /// let _ = 0.5_f32; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub UNNECESSARY_CAST, |
| complexity, |
| "cast to the same type, e.g., `x as i32` where `x: i32`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts, using `as` or `pointer::cast`, from a |
| /// less strictly aligned pointer to a more strictly aligned pointer. |
| /// |
| /// ### Why is this bad? |
| /// Dereferencing the resulting pointer may be undefined behavior. |
| /// |
| /// ### Known problems |
| /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or |
| /// similar on the resulting pointer is fine. Is over-zealous: casts with |
| /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be |
| /// fine. Miri is able to do a more in-depth analysis. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let _ = (&1u8 as *const u8) as *const u16; |
| /// let _ = (&mut 1u8 as *mut u8) as *mut u16; |
| /// |
| /// (&1u8 as *const u8).cast::<u16>(); |
| /// (&mut 1u8 as *mut u8).cast::<u16>(); |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub CAST_PTR_ALIGNMENT, |
| pedantic, |
| "cast from a pointer to a more strictly aligned pointer" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts of function pointers to something other than `usize`. |
| /// |
| /// ### Why is this bad? |
| /// Casting a function pointer to anything other than `usize`/`isize` is |
| /// not portable across architectures. If the target type is too small the |
| /// address would be truncated, and target types larger than `usize` are |
| /// unnecessary. |
| /// |
| /// Casting to `isize` also doesn't make sense, since addresses are never |
| /// signed. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn fun() -> i32 { 1 } |
| /// let _ = fun as i64; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # fn fun() -> i32 { 1 } |
| /// let _ = fun as usize; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub FN_TO_NUMERIC_CAST, |
| style, |
| "casting a function pointer to a numeric type other than `usize`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts of a function pointer to a numeric type not wide enough to |
| /// store an address. |
| /// |
| /// ### Why is this bad? |
| /// Such a cast discards some bits of the function's address. If this is intended, it would be more |
| /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with |
| /// a comment) to perform the truncation. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn fn1() -> i16 { |
| /// 1 |
| /// }; |
| /// let _ = fn1 as i32; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// // Cast to usize first, then comment with the reason for the truncation |
| /// fn fn1() -> i16 { |
| /// 1 |
| /// }; |
| /// let fn_ptr = fn1 as usize; |
| /// let fn_ptr_truncated = fn_ptr as i32; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION, |
| style, |
| "casting a function pointer to a numeric type not wide enough to store the address" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts of a function pointer to any integer type. |
| /// |
| /// ### Why restrict this? |
| /// Casting a function pointer to an integer can have surprising results and can occur |
| /// accidentally if parentheses are omitted from a function call. If you aren't doing anything |
| /// low-level with function pointers then you can opt out of casting functions to integers in |
| /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function |
| /// pointer casts in your code. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// // fn1 is cast as `usize` |
| /// fn fn1() -> u16 { |
| /// 1 |
| /// }; |
| /// let _ = fn1 as usize; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// // maybe you intended to call the function? |
| /// fn fn2() -> u16 { |
| /// 1 |
| /// }; |
| /// let _ = fn2() as usize; |
| /// |
| /// // or |
| /// |
| /// // maybe you intended to cast it to a function type? |
| /// fn fn3() -> u16 { |
| /// 1 |
| /// } |
| /// let _ = fn3 as fn() -> u16; |
| /// ``` |
| #[clippy::version = "1.58.0"] |
| pub FN_TO_NUMERIC_CAST_ANY, |
| restriction, |
| "casting a function pointer to any integer type" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for expressions where a character literal is cast |
| /// to `u8` and suggests using a byte literal instead. |
| /// |
| /// ### Why is this bad? |
| /// In general, casting values to smaller types is |
| /// error-prone and should be avoided where possible. In the particular case of |
| /// converting a character literal to `u8`, it is easy to avoid by just using a |
| /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter |
| /// than `'a' as u8`. |
| /// |
| /// ### Example |
| /// ```rust,ignore |
| /// 'x' as u8 |
| /// ``` |
| /// |
| /// A better version, using the byte literal: |
| /// |
| /// ```rust,ignore |
| /// b'x' |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub CHAR_LIT_AS_U8, |
| complexity, |
| "casting a character literal to `u8` truncates" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for `as` casts between raw pointers that don't change their |
| /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`. |
| /// |
| /// ### Why is this bad? |
| /// Though `as` casts between raw pointers are not terrible, |
| /// `pointer::cast` is safer because it cannot accidentally change the |
| /// pointer's mutability, nor cast the pointer to other types like `usize`. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let ptr: *const u32 = &42_u32; |
| /// let mut_ptr: *mut u32 = &mut 42_u32; |
| /// let _ = ptr as *const i32; |
| /// let _ = mut_ptr as *mut i32; |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let ptr: *const u32 = &42_u32; |
| /// let mut_ptr: *mut u32 = &mut 42_u32; |
| /// let _ = ptr.cast::<i32>(); |
| /// let _ = mut_ptr.cast::<i32>(); |
| /// ``` |
| #[clippy::version = "1.51.0"] |
| pub PTR_AS_PTR, |
| pedantic, |
| "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to |
| /// `*mut T` and `*mut T` to `*const T`. |
| /// |
| /// ### Why is this bad? |
| /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and |
| /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another |
| /// type. Or, when null pointers are involved, `null()` and `null_mut()` can be used directly. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let ptr: *const u32 = &42_u32; |
| /// let mut_ptr = ptr as *mut u32; |
| /// let ptr = mut_ptr as *const u32; |
| /// let ptr1 = std::ptr::null::<u32>() as *mut u32; |
| /// let ptr2 = std::ptr::null_mut::<u32>() as *const u32; |
| /// let ptr3 = std::ptr::null::<u32>().cast_mut(); |
| /// let ptr4 = std::ptr::null_mut::<u32>().cast_const(); |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let ptr: *const u32 = &42_u32; |
| /// let mut_ptr = ptr.cast_mut(); |
| /// let ptr = mut_ptr.cast_const(); |
| /// let ptr1 = std::ptr::null_mut::<u32>(); |
| /// let ptr2 = std::ptr::null::<u32>(); |
| /// let ptr3 = std::ptr::null_mut::<u32>(); |
| /// let ptr4 = std::ptr::null::<u32>(); |
| /// ``` |
| #[clippy::version = "1.72.0"] |
| pub PTR_CAST_CONSTNESS, |
| pedantic, |
| "casting using `as` on raw pointers to change constness when specialized methods apply" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts from an enum type to an integral type that will definitely truncate the |
| /// value. |
| /// |
| /// ### Why is this bad? |
| /// The resulting integral value will not match the value of the variant it came from. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// enum E { X = 256 }; |
| /// let _ = E::X as u8; |
| /// ``` |
| #[clippy::version = "1.61.0"] |
| pub CAST_ENUM_TRUNCATION, |
| suspicious, |
| "casts from an enum type to an integral type that will truncate the value" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for `as` casts between raw pointers to slices with differently sized elements. |
| /// |
| /// ### Why is this bad? |
| /// The produced raw pointer to a slice does not update its length metadata. The produced |
| /// pointer will point to a different number of bytes than the original pointer because the |
| /// length metadata of a raw slice pointer is in elements rather than bytes. |
| /// Producing a slice reference from the raw pointer will either create a slice with |
| /// less data (which can be surprising) or create a slice with more data and cause Undefined Behavior. |
| /// |
| /// ### Example |
| /// // Missing data |
| /// ```no_run |
| /// let a = [1_i32, 2, 3, 4]; |
| /// let p = &a as *const [i32] as *const [u8]; |
| /// unsafe { |
| /// println!("{:?}", &*p); |
| /// } |
| /// ``` |
| /// // Undefined Behavior (note: also potential alignment issues) |
| /// ```no_run |
| /// let a = [1_u8, 2, 3, 4]; |
| /// let p = &a as *const [u8] as *const [u32]; |
| /// unsafe { |
| /// println!("{:?}", &*p); |
| /// } |
| /// ``` |
| /// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length |
| /// ```no_run |
| /// let a = [1_i32, 2, 3, 4]; |
| /// let old_ptr = &a as *const [i32]; |
| /// // The data pointer is cast to a pointer to the target `u8` not `[u8]` |
| /// // The length comes from the known length of 4 i32s times the 4 bytes per i32 |
| /// let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16); |
| /// unsafe { |
| /// println!("{:?}", &*new_ptr); |
| /// } |
| /// ``` |
| #[clippy::version = "1.61.0"] |
| pub CAST_SLICE_DIFFERENT_SIZES, |
| correctness, |
| "casting using `as` between raw pointers to slices of types with different sizes" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts from an enum tuple constructor to an integer. |
| /// |
| /// ### Why is this bad? |
| /// The cast is easily confused with casting a c-like enum value to an integer. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// enum E { X(i32) }; |
| /// let _ = E::X as usize; |
| /// ``` |
| #[clippy::version = "1.61.0"] |
| pub CAST_ENUM_CONSTRUCTOR, |
| suspicious, |
| "casts from an enum tuple constructor to an integer" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for usage of the `abs()` method that cast the result to unsigned. |
| /// |
| /// ### Why is this bad? |
| /// The `unsigned_abs()` method avoids panic when called on the MIN value. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let x: i32 = -42; |
| /// let y: u32 = x.abs() as u32; |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let x: i32 = -42; |
| /// let y: u32 = x.unsigned_abs(); |
| /// ``` |
| #[clippy::version = "1.62.0"] |
| pub CAST_ABS_TO_UNSIGNED, |
| suspicious, |
| "casting the result of `abs()` to an unsigned integer can panic" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for the usage of `as _` conversion using inferred type. |
| /// |
| /// ### Why restrict this? |
| /// The conversion might include lossy conversion or a dangerous cast that might go |
| /// undetected due to the type being inferred. |
| /// |
| /// The lint is allowed by default as using `_` is less wordy than always specifying the type. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn foo(n: usize) {} |
| /// let n: u16 = 256; |
| /// foo(n as _); |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// fn foo(n: usize) {} |
| /// let n: u16 = 256; |
| /// foo(n as usize); |
| /// ``` |
| #[clippy::version = "1.63.0"] |
| pub AS_UNDERSCORE, |
| restriction, |
| "detects `as _` conversion" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for the usage of `&expr as *const T` or |
| /// `&mut expr as *mut T`, and suggest using `&raw const` or |
| /// `&raw mut` instead. |
| /// |
| /// ### Why is this bad? |
| /// This would improve readability and avoid creating a reference |
| /// that points to an uninitialized value or unaligned place. |
| /// Read the `&raw` explanation in the Reference for more information. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let val = 1; |
| /// let p = &val as *const i32; |
| /// |
| /// let mut val_mut = 1; |
| /// let p_mut = &mut val_mut as *mut i32; |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let val = 1; |
| /// let p = &raw const val; |
| /// |
| /// let mut val_mut = 1; |
| /// let p_mut = &raw mut val_mut; |
| /// ``` |
| #[clippy::version = "1.60.0"] |
| pub BORROW_AS_PTR, |
| pedantic, |
| "borrowing just to cast to a raw pointer" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for a raw slice being cast to a slice pointer |
| /// |
| /// ### Why is this bad? |
| /// This can result in multiple `&mut` references to the same location when only a pointer is |
| /// required. |
| /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require |
| /// the same [safety requirements] to be upheld. |
| /// |
| /// ### Example |
| /// ```rust,ignore |
| /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _; |
| /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _; |
| /// ``` |
| /// Use instead: |
| /// ```rust,ignore |
| /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len); |
| /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len); |
| /// ``` |
| /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety |
| #[clippy::version = "1.65.0"] |
| pub CAST_SLICE_FROM_RAW_PARTS, |
| suspicious, |
| "casting a slice created from a pointer and length to a slice pointer" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer. |
| /// |
| /// ### Why is this bad? |
| /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior |
| /// mutability is used, making it unlikely that having it as a mutable pointer is correct. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let mut vec = Vec::<u8>::with_capacity(1); |
| /// let ptr = vec.as_ptr() as *mut u8; |
| /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let mut vec = Vec::<u8>::with_capacity(1); |
| /// let ptr = vec.as_mut_ptr(); |
| /// unsafe { ptr.write(4) }; |
| /// ``` |
| #[clippy::version = "1.66.0"] |
| pub AS_PTR_CAST_MUT, |
| nursery, |
| "casting the result of the `&self`-taking `as_ptr` to a mutable pointer" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for a known NaN float being cast to an integer |
| /// |
| /// ### Why is this bad? |
| /// NaNs are cast into zero, so one could simply use this and make the |
| /// code more readable. The lint could also hint at a programmer error. |
| /// |
| /// ### Example |
| /// ```rust,ignore |
| /// let _ = (0.0_f32 / 0.0) as u64; |
| /// ``` |
| /// Use instead: |
| /// ```rust,ignore |
| /// let _ = 0_u64; |
| /// ``` |
| #[clippy::version = "1.66.0"] |
| pub CAST_NAN_TO_INT, |
| suspicious, |
| "casting a known floating-point NaN into an integer" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Catch casts from `0` to some pointer type |
| /// |
| /// ### Why is this bad? |
| /// This generally means `null` and is better expressed as |
| /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let a = 0 as *const u32; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// let a = std::ptr::null::<u32>(); |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub ZERO_PTR, |
| style, |
| "using `0 as *{const, mut} T`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts of references to pointer using `as` |
| /// and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead. |
| /// |
| /// ### Why is this bad? |
| /// Using `as` casts may result in silently changing mutability or type. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let a_ref = &1; |
| /// let a_ptr = a_ref as *const _; |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let a_ref = &1; |
| /// let a_ptr = std::ptr::from_ref(a_ref); |
| /// ``` |
| #[clippy::version = "1.78.0"] |
| pub REF_AS_PTR, |
| pedantic, |
| "using `as` to cast a reference to pointer" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for the usage of `as *const _` or `as *mut _` conversion using inferred type. |
| /// |
| /// ### Why restrict this? |
| /// The conversion might include a dangerous cast that might go undetected due to the type being inferred. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn as_usize<T>(t: &T) -> usize { |
| /// // BUG: `t` is already a reference, so we will here |
| /// // return a dangling pointer to a temporary value instead |
| /// &t as *const _ as usize |
| /// } |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// fn as_usize<T>(t: &T) -> usize { |
| /// t as *const T as usize |
| /// } |
| /// ``` |
| #[clippy::version = "1.85.0"] |
| pub AS_POINTER_UNDERSCORE, |
| restriction, |
| "detects `as *mut _` and `as *const _` conversion" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts of small constant literals or `mem::align_of` results to raw pointers. |
| /// |
| /// ### Why is this bad? |
| /// This creates a dangling pointer and is better expressed as |
| /// {`std`, `core`}`::ptr::`{`dangling`, `dangling_mut`}. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let ptr = 4 as *const u32; |
| /// let aligned = std::mem::align_of::<u32>() as *const u32; |
| /// let mut_ptr: *mut i64 = 8 as *mut _; |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let ptr = std::ptr::dangling::<u32>(); |
| /// let aligned = std::ptr::dangling::<u32>(); |
| /// let mut_ptr: *mut i64 = std::ptr::dangling_mut(); |
| /// ``` |
| #[clippy::version = "1.88.0"] |
| pub MANUAL_DANGLING_PTR, |
| style, |
| "casting small constant literals to pointers to create dangling pointers" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for casts of a primitive method pointer like `max`/`min` to any integer type. |
| /// |
| /// ### Why restrict this? |
| /// Casting a function pointer to an integer can have surprising results and can occur |
| /// accidentally if parentheses are omitted from a function call. If you aren't doing anything |
| /// low-level with function pointers then you can opt out of casting functions to integers in |
| /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function |
| /// pointer casts in your code. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let _ = u16::max as usize; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// let _ = u16::MAX as usize; |
| /// ``` |
| #[clippy::version = "1.89.0"] |
| pub CONFUSING_METHOD_TO_NUMERIC_CAST, |
| suspicious, |
| "casting a primitive method pointer to any integer type" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for bindings (constants, statics, or let bindings) that are defined |
| /// with one numeric type but are consistently cast to a different type in all usages. |
| /// |
| /// ### Why is this bad? |
| /// If a binding is always cast to a different type when used, it would be clearer |
| /// and more efficient to define it with the target type from the start. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// const SIZE: u16 = 15; |
| /// let arr: [u8; SIZE as usize] = [0; SIZE as usize]; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// const SIZE: usize = 15; |
| /// let arr: [u8; SIZE] = [0; SIZE]; |
| /// ``` |
| #[clippy::version = "1.93.0"] |
| pub NEEDLESS_TYPE_CAST, |
| nursery, |
| "binding defined with one type but always cast to another" |
| } |
| |
| pub struct Casts { |
| msrv: Msrv, |
| } |
| |
| impl Casts { |
| pub fn new(conf: &'static Conf) -> Self { |
| Self { msrv: conf.msrv } |
| } |
| } |
| |
| impl_lint_pass!(Casts => [ |
| CAST_PRECISION_LOSS, |
| CAST_SIGN_LOSS, |
| CAST_POSSIBLE_TRUNCATION, |
| CAST_POSSIBLE_WRAP, |
| CAST_LOSSLESS, |
| CAST_PTR_ALIGNMENT, |
| CAST_SLICE_DIFFERENT_SIZES, |
| UNNECESSARY_CAST, |
| FN_TO_NUMERIC_CAST_ANY, |
| FN_TO_NUMERIC_CAST, |
| FN_TO_NUMERIC_CAST_WITH_TRUNCATION, |
| CHAR_LIT_AS_U8, |
| PTR_AS_PTR, |
| PTR_CAST_CONSTNESS, |
| CAST_ENUM_TRUNCATION, |
| CAST_ENUM_CONSTRUCTOR, |
| CAST_ABS_TO_UNSIGNED, |
| AS_UNDERSCORE, |
| BORROW_AS_PTR, |
| CAST_SLICE_FROM_RAW_PARTS, |
| AS_PTR_CAST_MUT, |
| CAST_NAN_TO_INT, |
| ZERO_PTR, |
| REF_AS_PTR, |
| AS_POINTER_UNDERSCORE, |
| MANUAL_DANGLING_PTR, |
| CONFUSING_METHOD_TO_NUMERIC_CAST, |
| NEEDLESS_TYPE_CAST, |
| ]); |
| |
| impl<'tcx> LateLintPass<'tcx> for Casts { |
| fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { |
| if expr.span.in_external_macro(cx.sess().source_map()) { |
| return; |
| } |
| |
| if let ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind { |
| if is_hir_ty_cfg_dependant(cx, cast_to_hir) { |
| return; |
| } |
| let (cast_from, cast_to) = ( |
| cx.typeck_results().expr_ty(cast_from_expr), |
| cx.typeck_results().expr_ty(expr), |
| ); |
| |
| if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) { |
| return; |
| } |
| char_lit_as_u8::check(cx, expr, cast_from_expr, cast_to); |
| cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, self.msrv); |
| cast_ptr_alignment::check(cx, expr, cast_from, cast_to); |
| ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); |
| ptr_as_ptr::check(cx, expr, cast_from_expr, cast_from, cast_to_hir, cast_to, self.msrv); |
| as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); |
| fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to); |
| confusing_method_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); |
| fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); |
| fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to); |
| zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir, self.msrv); |
| |
| if self.msrv.meets(cx, msrvs::MANUAL_DANGLING_PTR) { |
| manual_dangling_ptr::check(cx, expr, cast_from_expr, cast_to_hir); |
| } |
| |
| if cast_to.is_numeric() { |
| cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span); |
| if cast_from.is_numeric() { |
| cast_possible_wrap::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); |
| cast_precision_loss::check(cx, expr, cast_from, cast_to); |
| cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); |
| cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); |
| cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to); |
| } |
| cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, self.msrv); |
| cast_enum_constructor::check(cx, expr, cast_from_expr, cast_from); |
| } |
| |
| as_underscore::check(cx, expr, cast_to_hir); |
| as_pointer_underscore::check(cx, cast_to, cast_to_hir); |
| |
| let was_borrow_as_ptr_emitted = self.msrv.meets(cx, msrvs::BORROW_AS_PTR) |
| && borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, self.msrv); |
| if !was_borrow_as_ptr_emitted && self.msrv.meets(cx, msrvs::PTR_FROM_REF) { |
| ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); |
| } |
| } |
| |
| if self.msrv.meets(cx, msrvs::RAW_REF_OP) { |
| borrow_as_ptr::check_implicit_cast(cx, expr); |
| } |
| if self.msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) { |
| cast_slice_from_raw_parts::check_implicit_cast(cx, expr); |
| } |
| cast_ptr_alignment::check_cast_method(cx, expr); |
| cast_slice_different_sizes::check(cx, expr, self.msrv); |
| ptr_cast_constness::check_null_ptr_cast_method(cx, expr); |
| } |
| |
| fn check_body(&mut self, cx: &LateContext<'tcx>, body: &rustc_hir::Body<'tcx>) { |
| needless_type_cast::check(cx, body); |
| } |
| } |