mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-12-18 00:53:31 +00:00
Auto merge of #10360 - JirkaVebr:transmute_integer_to_non_zero_wrapper, r=llogiq
Add the `transmute_int_to_non_zero` lint Fixes #10288 This adds a new complexity lint `transmute_int_to_non_zero` which checks for transmutes to any of the `NonZero*` types, and suggests their `new_unchecked` method instead. r? `@llogiq` changelog: New lint: [`transmute_int_to_non_zero`]
This commit is contained in:
commit
dfe23dc236
6 changed files with 196 additions and 0 deletions
|
@ -4794,6 +4794,7 @@ Released 2018-09-13
|
|||
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
|
||||
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
|
||||
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
|
||||
[`transmute_int_to_non_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_non_zero
|
||||
[`transmute_null_to_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_null_to_fn
|
||||
[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
|
||||
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
|
||||
|
|
|
@ -577,6 +577,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::transmute::TRANSMUTE_INT_TO_BOOL_INFO,
|
||||
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
|
||||
crate::transmute::TRANSMUTE_INT_TO_FLOAT_INFO,
|
||||
crate::transmute::TRANSMUTE_INT_TO_NON_ZERO_INFO,
|
||||
crate::transmute::TRANSMUTE_NULL_TO_FN_INFO,
|
||||
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
|
||||
crate::transmute::TRANSMUTE_PTR_TO_PTR_INFO,
|
||||
|
|
|
@ -3,6 +3,7 @@ mod transmute_float_to_int;
|
|||
mod transmute_int_to_bool;
|
||||
mod transmute_int_to_char;
|
||||
mod transmute_int_to_float;
|
||||
mod transmute_int_to_non_zero;
|
||||
mod transmute_null_to_fn;
|
||||
mod transmute_num_to_bytes;
|
||||
mod transmute_ptr_to_ptr;
|
||||
|
@ -253,6 +254,31 @@ declare_clippy_lint! {
|
|||
"transmutes from an integer to a float"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked`
|
||||
/// method instead.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Transmutes work on any types and thus might cause unsoundness when those types change
|
||||
/// elsewhere. `new_unchecked` only works for the appropriate types instead.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use core::num::NonZeroU32;
|
||||
/// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) };
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use core::num::NonZeroU32;
|
||||
/// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) };
|
||||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub TRANSMUTE_INT_TO_NON_ZERO,
|
||||
complexity,
|
||||
"transmutes from an integer to a non-zero wrapper"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for transmutes from a float to an integer.
|
||||
|
@ -451,6 +477,7 @@ impl_lint_pass!(Transmute => [
|
|||
TRANSMUTE_BYTES_TO_STR,
|
||||
TRANSMUTE_INT_TO_BOOL,
|
||||
TRANSMUTE_INT_TO_FLOAT,
|
||||
TRANSMUTE_INT_TO_NON_ZERO,
|
||||
TRANSMUTE_FLOAT_TO_INT,
|
||||
TRANSMUTE_NUM_TO_BYTES,
|
||||
UNSOUND_COLLECTION_TRANSMUTE,
|
||||
|
@ -501,6 +528,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
|
|||
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
|
||||
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
|
||||
| transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||
| transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
|
||||
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||
| (
|
||||
|
|
61
clippy_lints/src/transmute/transmute_int_to_non_zero.rs
Normal file
61
clippy_lints/src/transmute/transmute_int_to_non_zero.rs
Normal file
|
@ -0,0 +1,61 @@
|
|||
use super::TRANSMUTE_INT_TO_NON_ZERO;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::sugg;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::{
|
||||
query::Key,
|
||||
ty::{self, Ty},
|
||||
};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
/// Checks for `transmute_int_to_non_zero` lint.
|
||||
/// Returns `true` if it's triggered, otherwise returns `false`.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
e: &'tcx Expr<'_>,
|
||||
from_ty: Ty<'tcx>,
|
||||
to_ty: Ty<'tcx>,
|
||||
arg: &'tcx Expr<'_>,
|
||||
) -> bool {
|
||||
let (ty::Int(_) | ty::Uint(_), Some(to_ty_id)) = (&from_ty.kind(), to_ty.ty_adt_id()) else {
|
||||
return false;
|
||||
};
|
||||
let Some(to_type_sym) = cx.tcx.get_diagnostic_name(to_ty_id) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !matches!(
|
||||
to_type_sym,
|
||||
sym::NonZeroU8
|
||||
| sym::NonZeroU16
|
||||
| sym::NonZeroU32
|
||||
| sym::NonZeroU64
|
||||
| sym::NonZeroU128
|
||||
| sym::NonZeroI8
|
||||
| sym::NonZeroI16
|
||||
| sym::NonZeroI32
|
||||
| sym::NonZeroI64
|
||||
| sym::NonZeroI128
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
TRANSMUTE_INT_TO_NON_ZERO,
|
||||
e.span,
|
||||
&format!("transmute from a `{from_ty}` to a `{to_type_sym}`"),
|
||||
|diag| {
|
||||
let arg = sugg::Sugg::hir(cx, arg, "..");
|
||||
diag.span_suggestion(
|
||||
e.span,
|
||||
"consider using",
|
||||
format!("{to_type_sym}::{}({arg})", sym::new_unchecked),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
},
|
||||
);
|
||||
true
|
||||
}
|
41
tests/ui/transmute_int_to_non_zero.rs
Normal file
41
tests/ui/transmute_int_to_non_zero.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
#![warn(clippy::transmute_int_to_non_zero)]
|
||||
|
||||
use core::num::*;
|
||||
|
||||
fn main() {
|
||||
let int_u8: u8 = 1;
|
||||
let int_u16: u16 = 1;
|
||||
let int_u32: u32 = 1;
|
||||
let int_u64: u64 = 1;
|
||||
let int_u128: u128 = 1;
|
||||
|
||||
let int_i8: i8 = 1;
|
||||
let int_i16: i16 = 1;
|
||||
let int_i32: i32 = 1;
|
||||
let int_i64: i64 = 1;
|
||||
let int_i128: i128 = 1;
|
||||
|
||||
let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
|
||||
let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
|
||||
let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
|
||||
let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
|
||||
let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
|
||||
|
||||
let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
|
||||
let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
|
||||
let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
|
||||
let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
|
||||
let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
|
||||
|
||||
let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) };
|
||||
let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) };
|
||||
let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) };
|
||||
let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) };
|
||||
let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) };
|
||||
|
||||
let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) };
|
||||
let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) };
|
||||
let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) };
|
||||
let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) };
|
||||
let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) };
|
||||
}
|
64
tests/ui/transmute_int_to_non_zero.stderr
Normal file
64
tests/ui/transmute_int_to_non_zero.stderr
Normal file
|
@ -0,0 +1,64 @@
|
|||
error: transmute from a `u8` to a `NonZeroU8`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:18:33
|
||||
|
|
||||
LL | let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)`
|
||||
|
|
||||
= note: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings`
|
||||
|
||||
error: transmute from a `u16` to a `NonZeroU16`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:19:34
|
||||
|
|
||||
LL | let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)`
|
||||
|
||||
error: transmute from a `u32` to a `NonZeroU32`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:20:34
|
||||
|
|
||||
LL | let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)`
|
||||
|
||||
error: transmute from a `u64` to a `NonZeroU64`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:21:34
|
||||
|
|
||||
LL | let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)`
|
||||
|
||||
error: transmute from a `u128` to a `NonZeroU128`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:22:35
|
||||
|
|
||||
LL | let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)`
|
||||
|
||||
error: transmute from a `i8` to a `NonZeroI8`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:24:33
|
||||
|
|
||||
LL | let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)`
|
||||
|
||||
error: transmute from a `i16` to a `NonZeroI16`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:25:34
|
||||
|
|
||||
LL | let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)`
|
||||
|
||||
error: transmute from a `i32` to a `NonZeroI32`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:26:34
|
||||
|
|
||||
LL | let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)`
|
||||
|
||||
error: transmute from a `i64` to a `NonZeroI64`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:27:34
|
||||
|
|
||||
LL | let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)`
|
||||
|
||||
error: transmute from a `i128` to a `NonZeroI128`
|
||||
--> $DIR/transmute_int_to_non_zero.rs:28:35
|
||||
|
|
||||
LL | let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
Loading…
Reference in a new issue