about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-02-12 17:15:27 +0100
committerSamuel Tardieu <sam@rfc1149.net>2025-02-12 17:16:37 +0100
commit39bde6d46a5c7dbebdc66afb8ac166a4e9087231 (patch)
treee418b62ad878830650ee56c79a9e73758548e019
parentff87bead4f4931de38194809b5c9a420cce732e6 (diff)
downloadrust-39bde6d46a5c7dbebdc66afb8ac166a4e9087231.tar.gz
rust-39bde6d46a5c7dbebdc66afb8ac166a4e9087231.zip
Reorganize code in `mem_replace.rs`
Make each lint be more self-contained, and trigger only the next lint
when the previous one didn't already rewrite the expression.
-rw-r--r--clippy_lints/src/mem_replace.rs86
1 files changed, 50 insertions, 36 deletions
diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs
index 41528c5dee3..4f3279d292d 100644
--- a/clippy_lints/src/mem_replace.rs
+++ b/clippy_lints/src/mem_replace.rs
@@ -103,26 +103,31 @@ declare_clippy_lint! {
 impl_lint_pass!(MemReplace =>
     [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]);
 
-fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_span: Span) {
-    // Since this is a late pass (already type-checked),
-    // and we already know that the second argument is an
-    // `Option`, we do not need to check the first
-    // argument's type. All that's left is to get
-    // the replacee's expr after peeling off the `&mut`
-    let sugg_expr = peel_ref_operators(cx, dest);
-    let mut applicability = Applicability::MachineApplicable;
-    span_lint_and_sugg(
-        cx,
-        MEM_REPLACE_OPTION_WITH_NONE,
-        expr_span,
-        "replacing an `Option` with `None`",
-        "consider `Option::take()` instead",
-        format!(
-            "{}.take()",
-            Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par()
-        ),
-        applicability,
-    );
+fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) -> bool {
+    if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
+        // Since this is a late pass (already type-checked),
+        // and we already know that the second argument is an
+        // `Option`, we do not need to check the first
+        // argument's type. All that's left is to get
+        // the replacee's expr after peeling off the `&mut`
+        let sugg_expr = peel_ref_operators(cx, dest);
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            MEM_REPLACE_OPTION_WITH_NONE,
+            expr_span,
+            "replacing an `Option` with `None`",
+            "consider `Option::take()` instead",
+            format!(
+                "{}.take()",
+                Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par()
+            ),
+            applicability,
+        );
+        true
+    } else {
+        false
+    }
 }
 
 fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
@@ -181,27 +186,34 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
     }
 }
 
-fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
-    // disable lint for primitives
-    let expr_type = cx.typeck_results().expr_ty_adjusted(src);
-    if is_non_aggregate_primitive_type(expr_type) {
-        return;
-    }
-    if is_default_equivalent(cx, src) && !expr_span.in_external_macro(cx.tcx.sess.source_map()) {
-        let Some(top_crate) = std_or_core(cx) else { return };
+fn check_replace_with_default(
+    cx: &LateContext<'_>,
+    src: &Expr<'_>,
+    dest: &Expr<'_>,
+    expr: &Expr<'_>,
+    msrv: &Msrv,
+) -> bool {
+    if msrv.meets(msrvs::MEM_TAKE) && is_expr_used_or_unified(cx.tcx, expr)
+        // disable lint for primitives
+        && let expr_type = cx.typeck_results().expr_ty_adjusted(src)
+        && !is_non_aggregate_primitive_type(expr_type)
+        && is_default_equivalent(cx, src)
+        && !expr.span.in_external_macro(cx.tcx.sess.source_map())
+        && let Some(top_crate) = std_or_core(cx)
+    {
         span_lint_and_then(
             cx,
             MEM_REPLACE_WITH_DEFAULT,
-            expr_span,
+            expr.span,
             format!(
                 "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`"
             ),
             |diag| {
-                if !expr_span.from_expansion() {
+                if !expr.span.from_expansion() {
                     let suggestion = format!("{top_crate}::mem::take({})", snippet(cx, dest.span, ""));
 
                     diag.span_suggestion(
-                        expr_span,
+                        expr.span,
                         "consider using",
                         suggestion,
                         Applicability::MachineApplicable,
@@ -209,6 +221,9 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
                 }
             },
         );
+        true
+    } else {
+        false
     }
 }
 
@@ -233,12 +248,11 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
             && cx.tcx.is_diagnostic_item(sym::mem_replace, def_id)
         {
             // Check that second argument is `Option::None`
-            if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
-                check_replace_option_with_none(cx, dest, expr.span);
-            } else if self.msrv.meets(msrvs::MEM_TAKE) && is_expr_used_or_unified(cx.tcx, expr) {
-                check_replace_with_default(cx, src, dest, expr.span);
+            if !check_replace_option_with_none(cx, src, dest, expr.span)
+                && !check_replace_with_default(cx, src, dest, expr, &self.msrv)
+            {
+                check_replace_with_uninit(cx, src, dest, expr.span);
             }
-            check_replace_with_uninit(cx, src, dest, expr.span);
         }
     }
     extract_msrv_attr!(LateContext);