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_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_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_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_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_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
|
[`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_BOOL_INFO,
|
||||||
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
|
crate::transmute::TRANSMUTE_INT_TO_CHAR_INFO,
|
||||||
crate::transmute::TRANSMUTE_INT_TO_FLOAT_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_NULL_TO_FN_INFO,
|
||||||
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
|
crate::transmute::TRANSMUTE_NUM_TO_BYTES_INFO,
|
||||||
crate::transmute::TRANSMUTE_PTR_TO_PTR_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_bool;
|
||||||
mod transmute_int_to_char;
|
mod transmute_int_to_char;
|
||||||
mod transmute_int_to_float;
|
mod transmute_int_to_float;
|
||||||
|
mod transmute_int_to_non_zero;
|
||||||
mod transmute_null_to_fn;
|
mod transmute_null_to_fn;
|
||||||
mod transmute_num_to_bytes;
|
mod transmute_num_to_bytes;
|
||||||
mod transmute_ptr_to_ptr;
|
mod transmute_ptr_to_ptr;
|
||||||
|
@ -253,6 +254,31 @@ declare_clippy_lint! {
|
||||||
"transmutes from an integer to a float"
|
"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! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Checks for transmutes from a float to an integer.
|
/// Checks for transmutes from a float to an integer.
|
||||||
|
@ -451,6 +477,7 @@ impl_lint_pass!(Transmute => [
|
||||||
TRANSMUTE_BYTES_TO_STR,
|
TRANSMUTE_BYTES_TO_STR,
|
||||||
TRANSMUTE_INT_TO_BOOL,
|
TRANSMUTE_INT_TO_BOOL,
|
||||||
TRANSMUTE_INT_TO_FLOAT,
|
TRANSMUTE_INT_TO_FLOAT,
|
||||||
|
TRANSMUTE_INT_TO_NON_ZERO,
|
||||||
TRANSMUTE_FLOAT_TO_INT,
|
TRANSMUTE_FLOAT_TO_INT,
|
||||||
TRANSMUTE_NUM_TO_BYTES,
|
TRANSMUTE_NUM_TO_BYTES,
|
||||||
UNSOUND_COLLECTION_TRANSMUTE,
|
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_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_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_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_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)
|
| 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