blob: 4c7108af04dda9236c1ae899ebbf8f74d0198775 [file] [edit]
//@aux-build:proc_macros.rs
#![warn(clippy::needless_nonzero_get)]
// the `msrv` functions below deliberately use items newer than their MSRV
#![allow(clippy::incompatible_msrv)]
extern crate proc_macros;
use proc_macros::with_span;
use std::num::{NonZero, NonZeroI32, NonZeroU32};
fn unsigned(nz: NonZero<u32>) {
let _ = nz.get().leading_zeros();
//~^ needless_nonzero_get
let _ = nz.get().trailing_zeros();
//~^ needless_nonzero_get
let _ = nz.get().is_power_of_two();
//~^ needless_nonzero_get
let _ = nz.get().ilog2();
//~^ needless_nonzero_get
let _ = nz.get().ilog10();
//~^ needless_nonzero_get
}
fn signed(nz: NonZero<i32>) {
let _ = nz.get().leading_zeros();
//~^ needless_nonzero_get
let _ = nz.get().trailing_zeros();
//~^ needless_nonzero_get
let _ = nz.get().is_positive();
//~^ needless_nonzero_get
let _ = nz.get().is_negative();
//~^ needless_nonzero_get
}
fn unsigned_widths(a: NonZero<u8>, b: NonZero<u16>, c: NonZero<u64>, d: NonZero<u128>, e: NonZero<usize>) {
let _ = a.get().leading_zeros();
//~^ needless_nonzero_get
let _ = b.get().trailing_zeros();
//~^ needless_nonzero_get
let _ = c.get().ilog2();
//~^ needless_nonzero_get
let _ = d.get().is_power_of_two();
//~^ needless_nonzero_get
let _ = e.get().ilog10();
//~^ needless_nonzero_get
}
fn signed_widths(f: NonZero<i8>, g: NonZero<i16>, h: NonZero<i64>, i: NonZero<i128>, j: NonZero<isize>) {
let _ = f.get().is_negative();
//~^ needless_nonzero_get
let _ = g.get().is_positive();
//~^ needless_nonzero_get
let _ = h.get().leading_zeros();
//~^ needless_nonzero_get
let _ = i.get().trailing_zeros();
//~^ needless_nonzero_get
let _ = j.get().leading_zeros();
//~^ needless_nonzero_get
}
fn aliases_and_receivers(a: NonZeroU32, b: NonZeroI32, r: &NonZero<u32>) {
let _ = a.get().ilog2();
//~^ needless_nonzero_get
let _ = b.get().is_positive();
//~^ needless_nonzero_get
let _ = r.get().leading_zeros();
//~^ needless_nonzero_get
// more complex receiver expressions
let _ = NonZero::new(5u32).unwrap().get().leading_zeros();
//~^ needless_nonzero_get
let _ = (a).get().trailing_zeros();
//~^ needless_nonzero_get
// multi-line chain
let _ = a
.get()
//~^ needless_nonzero_get
.leading_zeros();
}
fn operators(mut value: u32, other: u32, nz: NonZero<u32>) {
let _ = other / nz.get();
//~^ needless_nonzero_get
let _ = other % nz.get();
//~^ needless_nonzero_get
value /= nz.get();
//~^ needless_nonzero_get
value %= nz.get();
//~^ needless_nonzero_get
}
// The `NonZero` operator implementations carry `#[rustc_const_unstable(feature = "const_ops")]`,
// so they are not usable in a `const` context even though `Div`/`Rem` themselves are stable.
const fn const_operators(mut value: u32, nz: NonZero<u32>) -> u32 {
value /= nz.get();
value / nz.get()
}
// `NonZero::leading_zeros` is const-stable since 1.53.0, so the `get` can go even in a `const fn`.
const fn const_methods(nz: NonZero<u32>) -> u32 {
nz.get().leading_zeros()
//~^ needless_nonzero_get
}
fn no_lint(nz: NonZero<u32>, signed: NonZero<i32>, plain: u32) {
// `NonZero`'s version returns `NonZero<u32>` rather than `u32`, so the `get` would only move
// rather than disappear
let _ = nz.get().bit_width();
let _ = nz.get().count_ones();
let _ = nz.get().isqrt();
let _ = nz.get().checked_add(1);
let _ = nz.get().saturating_mul(2);
let _ = signed.get().abs();
let _ = signed.get().cast_unsigned();
let _ = signed.get().unsigned_abs();
let _ = signed.get().wrapping_neg();
let _ = signed.get().overflowing_neg();
// `highest_one`/`lowest_one` return `Option<u32>` on integers but `u32` on `NonZero`
let _ = nz.get().highest_one();
let _ = nz.get().lowest_one();
// no `NonZero` equivalent at all
let _ = nz.get().to_string();
let _ = nz.get().count_zeros();
// `i32::ilog2` exists but `NonZero<i32>::ilog2` does not, so the impls must not cross over
let _ = signed.get().ilog2();
// The `NonZero` division and remainder implementations are unsigned-only.
let signed_value = signed.get();
let _ = signed_value / signed.get();
let _ = signed_value % signed.get();
// Primitive operators forward references, but the `NonZero` operators do not.
let value_ref = &plain;
let _ = value_ref / nz.get();
let _ = value_ref % nz.get();
let nz_ref = &nz;
let _ = plain / nz_ref.get();
let _ = plain % nz_ref.get();
// not a `NonZero` receiver
let _ = plain.leading_zeros();
// `get` is not immediately followed by the method
let x = nz.get();
let _ = x.leading_zeros();
// takes arguments
let _ = nz.get().rotate_left(2);
// a shadowing trait method must not be rewritten
let _ = nz.get().shadowed();
}
trait Shadowed {
fn shadowed(self) -> u32;
}
impl Shadowed for u32 {
fn shadowed(self) -> u32 {
self
}
}
impl Shadowed for NonZero<u32> {
fn shadowed(self) -> u32 {
0
}
}
// `NonZero::leading_zeros` was stabilized in 1.53.0
#[clippy::msrv = "1.52"]
fn below_msrv(nz: NonZero<u32>) {
let _ = nz.get().leading_zeros();
}
#[clippy::msrv = "1.53"]
fn meets_msrv(nz: NonZero<u32>) {
let _ = nz.get().leading_zeros();
//~^ needless_nonzero_get
}
// `NonZero::ilog2` was stabilized in 1.67.0, later than `leading_zeros`
#[clippy::msrv = "1.66"]
fn below_ilog2_msrv(nz: NonZero<u32>) {
let _ = nz.get().ilog2();
let _ = nz.get().leading_zeros();
//~^ needless_nonzero_get
}
// `Div<NonZero<_>>` and `Rem<NonZero<_>>` were stabilized in 1.51.0
#[clippy::msrv = "1.50"]
fn below_nonzero_div_msrv(value: u32, nz: NonZero<u32>) {
let _ = value / nz.get();
let _ = value % nz.get();
}
#[clippy::msrv = "1.51"]
fn meets_nonzero_div_msrv(value: u32, nz: NonZero<u32>) {
let _ = value / nz.get();
//~^ needless_nonzero_get
let _ = value % nz.get();
//~^ needless_nonzero_get
}
// `DivAssign<NonZero<_>>` and `RemAssign<NonZero<_>>` were stabilized in 1.79.0
#[clippy::msrv = "1.78"]
fn below_nonzero_div_assign_msrv(mut value: u32, nz: NonZero<u32>) {
value /= nz.get();
value %= nz.get();
}
#[clippy::msrv = "1.79"]
fn meets_nonzero_div_assign_msrv(mut value: u32, nz: NonZero<u32>) {
value /= nz.get();
//~^ needless_nonzero_get
value %= nz.get();
//~^ needless_nonzero_get
}
// The whole expression is written in the macro, so the suggestion would point at code the caller
// cannot edit.
macro_rules! leading_zeros_of_five {
() => {{
let nz = NonZero::new(5u32).unwrap();
nz.get().leading_zeros()
}};
}
// Only the receiver comes from the macro, so the removal span would start in the expansion and end
// at the call site.
macro_rules! five {
() => {
NonZero::new(5u32).unwrap()
};
}
// Only `.get()` comes from the macro: the receiver is a macro argument and keeps its call site
// span.
macro_rules! get_of {
($nz:expr) => {
$nz.get()
};
}
fn from_macros(nz: NonZero<u32>) {
let _ = leading_zeros_of_five!();
let _ = five!().get().leading_zeros();
let _ = get_of!(nz).leading_zeros();
let _ = with_span!(span nz.get().leading_zeros());
}
fn main() {}