about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/non_zero_suggestions.rs22
-rw-r--r--tests/ui/non_zero_suggestions.fixed69
-rw-r--r--tests/ui/non_zero_suggestions.rs83
-rw-r--r--tests/ui/non_zero_suggestions.stderr59
4 files changed, 198 insertions, 35 deletions
diff --git a/clippy_lints/src/non_zero_suggestions.rs b/clippy_lints/src/non_zero_suggestions.rs
index b9e7053db90..715d9eda6ee 100644
--- a/clippy_lints/src/non_zero_suggestions.rs
+++ b/clippy_lints/src/non_zero_suggestions.rs
@@ -9,16 +9,34 @@ use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for conversions from `NonZero` types to regular integer types,
+    /// and suggests using `NonZero` types for the target as well.
     ///
     /// ### Why is this bad?
+    /// Converting from `NonZero` types to regular integer types and then back to `NonZero`
+    /// types is less efficient and loses the type-safety guarantees provided by `NonZero` types.
+    /// Using `NonZero` types consistently can lead to more optimized code and prevent
+    /// certain classes of errors related to zero values.
     ///
     /// ### Example
     /// ```no_run
-    /// // example code where clippy issues a warning
+    /// use std::num::{NonZeroU32, NonZeroU64};
+    ///
+    /// fn example(x: u64, y: NonZeroU32) {
+    ///     // Bad: Converting NonZeroU32 to u64 unnecessarily
+    ///     let r1 = x / u64::from(y.get());
+    ///     let r2 = x % u64::from(y.get());
+    /// }
     /// ```
     /// Use instead:
     /// ```no_run
-    /// // example code which does not raise clippy warning
+    /// use std::num::{NonZeroU32, NonZeroU64};
+    ///
+    /// fn example(x: u64, y: NonZeroU32) {
+    ///     // Good: Preserving the NonZero property
+    ///     let r1 = x / NonZeroU64::from(y);
+    ///     let r2 = x % NonZeroU64::from(y);
+    /// }
     /// ```
     #[clippy::version = "1.81.0"]
     pub NON_ZERO_SUGGESTIONS,
diff --git a/tests/ui/non_zero_suggestions.fixed b/tests/ui/non_zero_suggestions.fixed
new file mode 100644
index 00000000000..b33de1ef03f
--- /dev/null
+++ b/tests/ui/non_zero_suggestions.fixed
@@ -0,0 +1,69 @@
+#![warn(clippy::non_zero_suggestions)]
+
+use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
+
+fn main() {
+    // Positive test cases (lint should trigger)
+
+    // U32 -> U64
+    let x: u64 = 100;
+    let y = NonZeroU32::new(10).unwrap();
+    let r1 = x / NonZeroU64::from(y);
+    let r2 = x % NonZeroU64::from(y);
+
+    // U16 -> U32
+    let a: u32 = 50;
+    let b = NonZeroU16::new(5).unwrap();
+    let r3 = a / NonZeroU32::from(b);
+
+    // I8 -> I16
+    let c: i16 = 25;
+    let d = NonZeroI8::new(3).unwrap();
+    let r4 = NonZeroI16::from(d);
+
+    // Different operations
+    let m: u64 = 400;
+    let n = NonZeroU32::new(20).unwrap();
+    let r5 = m / NonZeroU64::from(n);
+
+    // Edge cases
+
+    // Using the max value of a type
+    let max_u32 = NonZeroU32::new(u32::MAX).unwrap();
+    let r6 = NonZeroU64::from(max_u32);
+
+    // Chained method calls
+    let _ = NonZeroU64::from(NonZeroU32::new(10).unwrap());
+
+    // Negative test cases (lint should not trigger)
+
+    // Same size types
+    let e: u32 = 200;
+    let f = NonZeroU32::new(20).unwrap();
+    let r10 = e / f.get();
+
+    // Smaller to larger, but not NonZero
+    let g: u64 = 1000;
+    let h: u32 = 50;
+    let r11 = g / u64::from(h);
+
+    // Using From correctly
+    let k: u64 = 300;
+    let l = NonZeroU32::new(15).unwrap();
+    let r12 = k / NonZeroU64::from(l);
+}
+
+// Additional function to test the lint in a different context
+fn divide_numbers(x: u64, y: NonZeroU32) -> u64 {
+    x / NonZeroU64::from(y)
+}
+
+struct Calculator {
+    value: u64,
+}
+
+impl Calculator {
+    fn divide(&self, divisor: NonZeroU32) -> u64 {
+        self.value / NonZeroU64::from(divisor)
+    }
+}
diff --git a/tests/ui/non_zero_suggestions.rs b/tests/ui/non_zero_suggestions.rs
index 1a5ee40dc3d..27089eaf86e 100644
--- a/tests/ui/non_zero_suggestions.rs
+++ b/tests/ui/non_zero_suggestions.rs
@@ -1,52 +1,69 @@
 #![warn(clippy::non_zero_suggestions)]
 
-use std::num::{
-    NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, NonZeroU16, NonZeroU32,
-    NonZeroU64, NonZeroU8, NonZeroUsize,
-};
+use std::num::{NonZeroI16, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
 
 fn main() {
-    // Basic cases
-    let _ = u8::try_from(NonZeroU8::new(5).unwrap().get());
+    // Positive test cases (lint should trigger)
 
-    let _ = u16::from(NonZeroU16::new(10).unwrap().get());
+    // U32 -> U64
+    let x: u64 = 100;
+    let y = NonZeroU32::new(10).unwrap();
+    let r1 = x / u64::from(y.get());
+    let r2 = x % u64::from(y.get());
 
-    // Different integer types
-    let _ = u32::from(NonZeroU32::new(15).unwrap().get());
+    // U16 -> U32
+    let a: u32 = 50;
+    let b = NonZeroU16::new(5).unwrap();
+    let r3 = a / u32::from(b.get());
 
-    let _ = u64::from(NonZeroU64::new(20).unwrap().get());
+    // I8 -> I16
+    let c: i16 = 25;
+    let d = NonZeroI8::new(3).unwrap();
+    let r4 = i16::from(d.get());
 
-    let _ = u128::from(NonZeroU128::new(25).unwrap().get());
+    // Different operations
+    let m: u64 = 400;
+    let n = NonZeroU32::new(20).unwrap();
+    let r5 = m / u64::from(n.get());
 
-    let _ = usize::from(NonZeroUsize::new(30).unwrap().get());
+    // Edge cases
 
-    // Signed integer types
-    let _ = i8::try_from(NonZeroI8::new(-5).unwrap().get());
+    // Using the max value of a type
+    let max_u32 = NonZeroU32::new(u32::MAX).unwrap();
+    let r6 = u64::from(max_u32.get());
 
-    let _ = i16::from(NonZeroI16::new(-10).unwrap().get());
+    // Chained method calls
+    let _ = u64::from(NonZeroU32::new(10).unwrap().get());
 
-    let _ = i32::from(NonZeroI32::new(-15).unwrap().get());
+    // Negative test cases (lint should not trigger)
 
-    // Edge cases
+    // Same size types
+    let e: u32 = 200;
+    let f = NonZeroU32::new(20).unwrap();
+    let r10 = e / f.get();
 
-    // Complex expression
-    let _ = u8::from(NonZeroU8::new(5).unwrap().get() + 1);
+    // Smaller to larger, but not NonZero
+    let g: u64 = 1000;
+    let h: u32 = 50;
+    let r11 = g / u64::from(h);
 
-    // Function call
-    fn get_non_zero() -> NonZeroU8 {
-        NonZeroU8::new(42).unwrap()
-    }
-    let _ = u8::from(get_non_zero().get());
+    // Using From correctly
+    let k: u64 = 300;
+    let l = NonZeroU32::new(15).unwrap();
+    let r12 = k / NonZeroU64::from(l);
+}
 
-    // Method chaining
-    let _ = u16::from(NonZeroU16::new(100).unwrap().get().checked_add(1).unwrap());
-    // This should not trigger the lint
+// Additional function to test the lint in a different context
+fn divide_numbers(x: u64, y: NonZeroU32) -> u64 {
+    x / u64::from(y.get())
+}
 
-    // Different conversion methods
-    let _ = u32::try_from(NonZeroU32::new(200).unwrap().get()).unwrap();
+struct Calculator {
+    value: u64,
+}
 
-    // Cases that should not trigger the lint
-    let _ = u8::from(5);
-    let _ = u16::from(10u8);
-    let _ = i32::try_from(40u32).unwrap();
+impl Calculator {
+    fn divide(&self, divisor: NonZeroU32) -> u64 {
+        self.value / u64::from(divisor.get())
+    }
 }
diff --git a/tests/ui/non_zero_suggestions.stderr b/tests/ui/non_zero_suggestions.stderr
new file mode 100644
index 00000000000..b30f9dd1e5c
--- /dev/null
+++ b/tests/ui/non_zero_suggestions.stderr
@@ -0,0 +1,59 @@
+error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:11:18
+   |
+LL |     let r1 = x / u64::from(y.get());
+   |                  ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)`
+   |
+   = note: `-D clippy::non-zero-suggestions` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::non_zero_suggestions)]`
+
+error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:12:18
+   |
+LL |     let r2 = x % u64::from(y.get());
+   |                  ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)`
+
+error: Consider using `NonZeroU32::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:17:18
+   |
+LL |     let r3 = a / u32::from(b.get());
+   |                  ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU32::from(b)`
+
+error: Consider using `NonZeroI16::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:22:14
+   |
+LL |     let r4 = i16::from(d.get());
+   |              ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroI16::from(d)`
+
+error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:27:18
+   |
+LL |     let r5 = m / u64::from(n.get());
+   |                  ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(n)`
+
+error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:33:14
+   |
+LL |     let r6 = u64::from(max_u32.get());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(max_u32)`
+
+error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:36:13
+   |
+LL |     let _ = u64::from(NonZeroU32::new(10).unwrap().get());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(NonZeroU32::new(10).unwrap())`
+
+error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:58:9
+   |
+LL |     x / u64::from(y.get())
+   |         ^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(y)`
+
+error: Consider using `NonZeroU64::from()` for more efficient and type-safe conversion
+  --> tests/ui/non_zero_suggestions.rs:67:22
+   |
+LL |         self.value / u64::from(divisor.get())
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: Replace with: `NonZeroU64::from(divisor)`
+
+error: aborting due to 9 previous errors
+