about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-07-03 20:22:18 +0200
committerSamuel Tardieu <sam@rfc1149.net>2025-07-03 22:14:00 +0200
commita8ab02c4641de4e3ec634b3479fddb60e4ad7763 (patch)
treea6ec346ca3f015191e64a460af4c3c2f8e921f0c /clippy_lints/src
parent83148cb28343bf15ed469f946915c73deeaa9a28 (diff)
Fix several issues with `manual_is_multiple_of`
- `&a % &b == 0` compiles, but requires dereferencing `b` when
  replacing with `a.is_multiple_of(b)`.
- In `a % b == 0`, if type of `a` is not certain,
  `a.is_multiple_of(b)` might not be typable.
- In `a % b == 0`, `a` and `b` must be unsigned integers, not any
  arbitrary types implementing `Rem` and outputing an integer.
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/operators/manual_is_multiple_of.rs25
1 files changed, 23 insertions, 2 deletions
diff --git a/clippy_lints/src/operators/manual_is_multiple_of.rs b/clippy_lints/src/operators/manual_is_multiple_of.rs
index 821178a4315..55bb78cfce5 100644
--- a/clippy_lints/src/operators/manual_is_multiple_of.rs
+++ b/clippy_lints/src/operators/manual_is_multiple_of.rs
@@ -2,11 +2,12 @@ use clippy_utils::consts::is_zero_integer_const;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::expr_type_is_certain;
 use rustc_ast::BinOpKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 
 use super::MANUAL_IS_MULTIPLE_OF;
 
@@ -22,9 +23,21 @@ pub(super) fn check<'tcx>(
         && let Some(operand) = uint_compare_to_zero(cx, op, lhs, rhs)
         && let ExprKind::Binary(operand_op, operand_left, operand_right) = operand.kind
         && operand_op.node == BinOpKind::Rem
+        && matches!(
+            cx.typeck_results().expr_ty_adjusted(operand_left).peel_refs().kind(),
+            ty::Uint(_)
+        )
+        && matches!(
+            cx.typeck_results().expr_ty_adjusted(operand_right).peel_refs().kind(),
+            ty::Uint(_)
+        )
+        && expr_type_is_certain(cx, operand_left)
     {
         let mut app = Applicability::MachineApplicable;
-        let divisor = Sugg::hir_with_applicability(cx, operand_right, "_", &mut app);
+        let divisor = deref_sugg(
+            Sugg::hir_with_applicability(cx, operand_right, "_", &mut app),
+            cx.typeck_results().expr_ty_adjusted(operand_right),
+        );
         span_lint_and_sugg(
             cx,
             MANUAL_IS_MULTIPLE_OF,
@@ -64,3 +77,11 @@ fn uint_compare_to_zero<'tcx>(
 
     matches!(cx.typeck_results().expr_ty_adjusted(operand).kind(), ty::Uint(_)).then_some(operand)
 }
+
+fn deref_sugg<'a>(sugg: Sugg<'a>, ty: Ty<'_>) -> Sugg<'a> {
+    if let ty::Ref(_, target_ty, _) = ty.kind() {
+        deref_sugg(sugg.deref(), *target_ty)
+    } else {
+        sugg
+    }
+}