]> git.proxmox.com Git - rustc.git/blobdiff - src/tools/clippy/clippy_lints/src/redundant_clone.rs
bump version to 1.79.0+dfsg1-1~bpo12+pve2
[rustc.git] / src / tools / clippy / clippy_lints / src / redundant_clone.rs
index aedbe08e3e46e2e340c0263cc7766f4ab9c50c81..3416a93e3c4ac071a5e8cce746b7f74fd42cacef 100644 (file)
@@ -1,18 +1,17 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap};
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
+use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth};
 use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{def_id, Body, FnDecl, HirId};
+use rustc_hir::{def_id, Body, FnDecl, LangItem};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::{BytePos, Span};
-use rustc_span::sym;
+use rustc_session::declare_lint_pass;
+use rustc_span::def_id::LocalDefId;
+use rustc_span::{sym, BytePos, Span};
 
 macro_rules! unwrap_or_continue {
     ($x:expr) => {
@@ -36,7 +35,7 @@ declare_clippy_lint! {
     /// False-negatives: analysis performed by this lint is conservative and limited.
     ///
     /// ### Example
-    /// ```rust
+    /// ```no_run
     /// # use std::path::Path;
     /// # #[derive(Clone)]
     /// # struct Foo;
@@ -56,7 +55,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.32.0"]
     pub REDUNDANT_CLONE,
-    perf,
+    nursery,
     "`clone()` of an owned value that is going to be dropped immediately"
 }
 
@@ -69,12 +68,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
         cx: &LateContext<'tcx>,
         _: FnKind<'tcx>,
         _: &'tcx FnDecl<'_>,
-        body: &'tcx Body<'_>,
+        _: &'tcx Body<'_>,
         _: Span,
-        _: HirId,
+        def_id: LocalDefId,
     ) {
-        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
-
         // Building MIR for `fn`s with unsatisfiable preds results in ICE.
         if fn_has_unsatisfiable_preds(cx, def_id.to_def_id()) {
             return;
@@ -100,9 +97,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));
 
             let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
-                || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD)
-                || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD)
-                    && is_type_diagnostic_item(cx, arg_ty, sym::String));
+                || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id)
+                || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id)
+                    && is_type_lang_item(cx, arg_ty, LangItem::String));
 
             let from_deref = !from_borrow
                 && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF)
@@ -147,18 +144,16 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 let pred_terminator = mir[ps[0]].terminator();
 
                 // receiver of the `deref()` call
-                let (pred_arg, deref_clone_ret) = if_chain! {
-                    if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, res)) =
-                        is_call_with_ref_arg(cx, mir, &pred_terminator.kind);
-                    if res == cloned;
-                    if cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id);
-                    if is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf)
-                        || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString);
-                    then {
-                        (pred_arg, res)
-                    } else {
-                        continue;
-                    }
+                let (pred_arg, deref_clone_ret) = if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, res)) =
+                    is_call_with_ref_arg(cx, mir, &pred_terminator.kind)
+                    && res == cloned
+                    && cx.tcx.is_diagnostic_item(sym::deref_method, pred_fn_def_id)
+                    && (is_type_diagnostic_item(cx, pred_arg_ty, sym::PathBuf)
+                        || is_type_diagnostic_item(cx, pred_arg_ty, sym::OsString))
+                {
+                    (pred_arg, res)
+                } else {
+                    continue;
                 };
 
                 let (local, cannot_move_out) =
@@ -213,45 +208,37 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 .assert_crate_local()
                 .lint_root;
 
-            if_chain! {
-                if let Some(snip) = snippet_opt(cx, span);
-                if let Some(dot) = snip.rfind('.');
-                then {
-                    let sugg_span = span.with_lo(
-                        span.lo() + BytePos(u32::try_from(dot).unwrap())
-                    );
-                    let mut app = Applicability::MaybeIncorrect;
-
-                    let call_snip = &snip[dot + 1..];
-                    // Machine applicable when `call_snip` looks like `foobar()`
-                    if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
-                        if call_snip.as_bytes().iter().all(|b| b.is_ascii_alphabetic() || *b == b'_') {
-                            app = Applicability::MachineApplicable;
-                        }
+            if let Some(snip) = snippet_opt(cx, span)
+                && let Some(dot) = snip.rfind('.')
+            {
+                let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap()));
+                let mut app = Applicability::MaybeIncorrect;
+
+                let call_snip = &snip[dot + 1..];
+                // Machine applicable when `call_snip` looks like `foobar()`
+                if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
+                    if call_snip
+                        .as_bytes()
+                        .iter()
+                        .all(|b| b.is_ascii_alphabetic() || *b == b'_')
+                    {
+                        app = Applicability::MachineApplicable;
                     }
+                }
 
-                    span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| {
-                        diag.span_suggestion(
-                            sugg_span,
-                            "remove this",
-                            "",
-                            app,
+                span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| {
+                    diag.span_suggestion(sugg_span, "remove this", "", app);
+                    if clone_usage.cloned_used {
+                        diag.span_note(span, "cloned value is neither consumed nor mutated");
+                    } else {
+                        diag.span_note(
+                            span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
+                            "this value is dropped without further use",
                         );
-                        if clone_usage.cloned_used {
-                            diag.span_note(
-                                span,
-                                "cloned value is neither consumed nor mutated",
-                            );
-                        } else {
-                            diag.span_note(
-                                span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
-                                "this value is dropped without further use",
-                            );
-                        }
-                    });
-                } else {
-                    span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
-                }
+                    }
+                });
+            } else {
+                span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
             }
         }
     }
@@ -263,18 +250,21 @@ fn is_call_with_ref_arg<'tcx>(
     mir: &'tcx mir::Body<'tcx>,
     kind: &'tcx mir::TerminatorKind<'tcx>,
 ) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, mir::Local)> {
-    if_chain! {
-        if let mir::TerminatorKind::Call { func, args, destination, .. } = kind;
-        if args.len() == 1;
-        if let mir::Operand::Move(mir::Place { local, .. }) = &args[0];
-        if let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind();
-        if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(mir, cx.tcx));
-        if !is_copy(cx, inner_ty);
-        then {
-            Some((def_id, *local, inner_ty, destination.as_local()?))
-        } else {
-            None
-        }
+    if let mir::TerminatorKind::Call {
+        func,
+        args,
+        destination,
+        ..
+    } = kind
+        && args.len() == 1
+        && let mir::Operand::Move(mir::Place { local, .. }) = &args[0].node
+        && let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind()
+        && let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].node.ty(mir, cx.tcx))
+        && !is_copy(cx, inner_ty)
+    {
+        Some((def_id, *local, inner_ty, destination.as_local()?))
+    } else {
+        None
     }
 }
 
@@ -321,8 +311,6 @@ fn base_local_and_movability<'tcx>(
     mir: &mir::Body<'tcx>,
     place: mir::Place<'tcx>,
 ) -> (mir::Local, CannotMoveOut) {
-    use rustc_middle::mir::PlaceRef;
-
     // Dereference. You cannot move things out from a borrowed value.
     let mut deref = false;
     // Accessing a field of an ADT that has `Drop`. Moving the field out will cause E0509.
@@ -331,17 +319,14 @@ fn base_local_and_movability<'tcx>(
     // underlying type implements Copy
     let mut slice = false;
 
-    let PlaceRef { local, mut projection } = place.as_ref();
-    while let [base @ .., elem] = projection {
-        projection = base;
+    for (base, elem) in place.as_ref().iter_projections() {
+        let base_ty = base.ty(&mir.local_decls, cx.tcx).ty;
         deref |= matches!(elem, mir::ProjectionElem::Deref);
-        field |= matches!(elem, mir::ProjectionElem::Field(..))
-            && has_drop(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
-        slice |= matches!(elem, mir::ProjectionElem::Index(..))
-            && !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
+        field |= matches!(elem, mir::ProjectionElem::Field(..)) && has_drop(cx, base_ty);
+        slice |= matches!(elem, mir::ProjectionElem::Index(..)) && !is_copy(cx, base_ty);
     }
 
-    (local, deref || field || slice)
+    (place.local, deref || field || slice)
 }
 
 #[derive(Default)]