]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/redundant_clone.rs
Fix breakage due to rust-lang/rust#60913
[rust.git] / clippy_lints / src / redundant_clone.rs
index 086c76c20b6340e456f1a59a9e9b7a890b33fe9a..d24a20b079d1d64c683f63f2fc0e23417cae6531 100644 (file)
@@ -1,6 +1,6 @@
 use crate::utils::{
-    has_drop, in_macro, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir, span_lint_hir_and_then,
-    walk_ptrs_ty_depth,
+    has_drop, in_macro_or_desugar, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir,
+    span_lint_hir_and_then, walk_ptrs_ty_depth,
 };
 use if_chain::if_chain;
 use matches::matches;
@@ -13,7 +13,7 @@
     TerminatorKind,
 };
 use rustc::ty::{self, Ty};
-use rustc::{declare_tool_lint, lint_array};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use rustc_errors::Applicability;
 use std::convert::TryFrom;
 use syntax::source_map::{BytePos, Span};
@@ -64,17 +64,7 @@ macro_rules! unwrap_or_continue {
     "`clone()` of an owned value that is going to be dropped immediately"
 }
 
-pub struct RedundantClone;
-
-impl LintPass for RedundantClone {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(REDUNDANT_CLONE)
-    }
-
-    fn name(&self) -> &'static str {
-        "RedundantClone"
-    }
-}
+declare_lint_pass!(RedundantClone => [REDUNDANT_CLONE]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone {
     #[allow(clippy::too_many_lines)]
@@ -93,7 +83,7 @@ fn check_fn(
         for (bb, bbdata) in mir.basic_blocks().iter_enumerated() {
             let terminator = bbdata.terminator();
 
-            if in_macro(terminator.source_info.span) {
+            if in_macro_or_desugar(terminator.source_info.span) {
                 continue;
             }
 
@@ -104,14 +94,13 @@ fn check_fn(
 
             let (fn_def_id, arg, arg_ty, _) = unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));
 
-            let from_borrow = match_def_path(cx.tcx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
-                || match_def_path(cx.tcx, fn_def_id, &paths::TO_OWNED_METHOD)
-                || (match_def_path(cx.tcx, fn_def_id, &paths::TO_STRING_METHOD)
-                    && match_type(cx, arg_ty, &paths::STRING));
+            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) && match_type(cx, arg_ty, &paths::STRING));
 
             let from_deref = !from_borrow
-                && (match_def_path(cx.tcx, fn_def_id, &paths::PATH_TO_PATH_BUF)
-                    || match_def_path(cx.tcx, fn_def_id, &paths::OS_STR_TO_OS_STRING));
+                && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF)
+                    || match_def_path(cx, fn_def_id, &paths::OS_STR_TO_OS_STRING));
 
             if !from_borrow && !from_deref {
                 continue;
@@ -143,8 +132,8 @@ fn check_fn(
                 let pred_arg = if_chain! {
                     if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, Some(res))) =
                         is_call_with_ref_arg(cx, mir, &pred_terminator.kind);
-                    if *res == mir::Place::Base(mir::PlaceBase::Local(cloned));
-                    if match_def_path(cx.tcx, pred_fn_def_id, &paths::DEREF_TRAIT_METHOD);
+                    if res.base == mir::PlaceBase::Local(cloned);
+                    if match_def_path(cx, pred_fn_def_id, &paths::DEREF_TRAIT_METHOD);
                     if match_type(cx, pred_arg_ty, &paths::PATH_BUF)
                         || match_type(cx, pred_arg_ty, &paths::OS_STRING);
                     then {
@@ -223,13 +212,13 @@ fn check_fn(
 /// If `kind` is `y = func(x: &T)` where `T: !Copy`, returns `(DefId of func, x, T, y)`.
 fn is_call_with_ref_arg<'tcx>(
     cx: &LateContext<'_, 'tcx>,
-    mir: &'tcx mir::Mir<'tcx>,
+    mir: &'tcx mir::Body<'tcx>,
     kind: &'tcx mir::TerminatorKind<'tcx>,
 ) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, Option<&'tcx mir::Place<'tcx>>)> {
     if_chain! {
         if let TerminatorKind::Call { func, args, destination, .. } = kind;
         if args.len() == 1;
-        if let mir::Operand::Move(mir::Place::Base(mir::PlaceBase::Local(local))) = &args[0];
+        if let mir::Operand::Move(mir::Place { base: mir::PlaceBase::Local(local), .. }) = &args[0];
         if let ty::FnDef(def_id, _) = func.ty(&*mir, cx.tcx).sty;
         if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx));
         if !is_copy(cx, inner_ty);
@@ -247,7 +236,7 @@ fn is_call_with_ref_arg<'tcx>(
 /// ``Some((from, [`true` if `from` cannot be moved out]))``.
 fn find_stmt_assigns_to<'a, 'tcx: 'a>(
     cx: &LateContext<'_, 'tcx>,
-    mir: &mir::Mir<'tcx>,
+    mir: &mir::Body<'tcx>,
     to: mir::Local,
     by_ref: bool,
     stmts: impl DoubleEndedIterator<Item = &'a mir::Statement<'tcx>>,
@@ -255,7 +244,14 @@ fn find_stmt_assigns_to<'a, 'tcx: 'a>(
     stmts
         .rev()
         .find_map(|stmt| {
-            if let mir::StatementKind::Assign(mir::Place::Base(mir::PlaceBase::Local(local)), v) = &stmt.kind {
+            if let mir::StatementKind::Assign(
+                mir::Place {
+                    base: mir::PlaceBase::Local(local),
+                    ..
+                },
+                v,
+            ) = &stmt.kind
+            {
                 if *local == to {
                     return Some(v);
                 }
@@ -281,29 +277,35 @@ fn find_stmt_assigns_to<'a, 'tcx: 'a>(
 /// Also reports whether given `place` cannot be moved out.
 fn base_local_and_movability<'tcx>(
     cx: &LateContext<'_, 'tcx>,
-    mir: &mir::Mir<'tcx>,
-    mut place: &mir::Place<'tcx>,
+    mir: &mir::Body<'tcx>,
+    place: &mir::Place<'tcx>,
 ) -> Option<(mir::Local, CannotMoveOut)> {
-    use rustc::mir::Place::*;
+    use rustc::mir::Place;
     use rustc::mir::PlaceBase;
+    use rustc::mir::PlaceRef;
+    use rustc::mir::Projection;
 
     // 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.
     let mut field = false;
 
-    loop {
-        match place {
-            Base(PlaceBase::Local(local)) => return Some((*local, deref || field)),
-            Projection(proj) => {
-                place = &proj.base;
-                deref = deref || matches!(proj.elem, mir::ProjectionElem::Deref);
-                if !field && matches!(proj.elem, mir::ProjectionElem::Field(..)) {
-                    field = has_drop(cx, place.ty(&mir.local_decls, cx.tcx).to_ty(cx.tcx));
-                }
-            },
-            _ => return None,
+    let PlaceRef {
+        base: place_base,
+        mut projection,
+    } = place.as_place_ref();
+    if let PlaceBase::Local(local) = place_base {
+        while let Some(box Projection { base, elem }) = projection {
+            projection = base;
+            deref = matches!(elem, mir::ProjectionElem::Deref);
+            field = !field
+                && matches!(elem, mir::ProjectionElem::Field(..))
+                && has_drop(cx, Place::ty_from(place_base, projection, &mir.local_decls, cx.tcx).ty);
         }
+
+        Some((*local, deref || field))
+    } else {
+        None
     }
 }
 
@@ -316,7 +318,7 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
     fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
         let statements = &data.statements;
         for (statement_index, statement) in statements.iter().enumerate() {
-            self.visit_statement(block, statement, mir::Location { block, statement_index });
+            self.visit_statement(statement, mir::Location { block, statement_index });
 
             // Once flagged, skip remaining statements
             if self.used_other_than_drop {
@@ -325,7 +327,6 @@ fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBl
         }
 
         self.visit_terminator(
-            block,
             data.terminator(),
             mir::Location {
                 block,
@@ -334,7 +335,7 @@ fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBl
         );
     }
 
-    fn visit_local(&mut self, local: &mir::Local, ctx: PlaceContext<'tcx>, _: mir::Location) {
+    fn visit_local(&mut self, local: &mir::Local, ctx: PlaceContext, _: mir::Location) {
         match ctx {
             PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_) => return,
             _ => {},