| //@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.leading_zeros(); |
| //~^ needless_nonzero_get |
| let _ = nz.trailing_zeros(); |
| //~^ needless_nonzero_get |
| let _ = nz.is_power_of_two(); |
| //~^ needless_nonzero_get |
| let _ = nz.ilog2(); |
| //~^ needless_nonzero_get |
| let _ = nz.ilog10(); |
| //~^ needless_nonzero_get |
| } |
| |
| fn signed(nz: NonZero<i32>) { |
| let _ = nz.leading_zeros(); |
| //~^ needless_nonzero_get |
| let _ = nz.trailing_zeros(); |
| //~^ needless_nonzero_get |
| let _ = nz.is_positive(); |
| //~^ needless_nonzero_get |
| let _ = nz.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.leading_zeros(); |
| //~^ needless_nonzero_get |
| let _ = b.trailing_zeros(); |
| //~^ needless_nonzero_get |
| let _ = c.ilog2(); |
| //~^ needless_nonzero_get |
| let _ = d.is_power_of_two(); |
| //~^ needless_nonzero_get |
| let _ = e.ilog10(); |
| //~^ needless_nonzero_get |
| } |
| |
| fn signed_widths(f: NonZero<i8>, g: NonZero<i16>, h: NonZero<i64>, i: NonZero<i128>, j: NonZero<isize>) { |
| let _ = f.is_negative(); |
| //~^ needless_nonzero_get |
| let _ = g.is_positive(); |
| //~^ needless_nonzero_get |
| let _ = h.leading_zeros(); |
| //~^ needless_nonzero_get |
| let _ = i.trailing_zeros(); |
| //~^ needless_nonzero_get |
| let _ = j.leading_zeros(); |
| //~^ needless_nonzero_get |
| } |
| |
| fn aliases_and_receivers(a: NonZeroU32, b: NonZeroI32, r: &NonZero<u32>) { |
| let _ = a.ilog2(); |
| //~^ needless_nonzero_get |
| let _ = b.is_positive(); |
| //~^ needless_nonzero_get |
| let _ = r.leading_zeros(); |
| //~^ needless_nonzero_get |
| |
| // more complex receiver expressions |
| let _ = NonZero::new(5u32).unwrap().leading_zeros(); |
| //~^ needless_nonzero_get |
| let _ = (a).trailing_zeros(); |
| //~^ needless_nonzero_get |
| |
| // multi-line chain |
| let _ = a |
| //~^ needless_nonzero_get |
| .leading_zeros(); |
| } |
| |
| fn operators(mut value: u32, other: u32, nz: NonZero<u32>) { |
| let _ = other / nz; |
| //~^ needless_nonzero_get |
| let _ = other % nz; |
| //~^ needless_nonzero_get |
| value /= nz; |
| //~^ needless_nonzero_get |
| value %= nz; |
| //~^ 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.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.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.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; |
| //~^ needless_nonzero_get |
| let _ = value % nz; |
| //~^ 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; |
| //~^ needless_nonzero_get |
| value %= nz; |
| //~^ 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() {} |