]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/needless_pass_by_value.rs
Merge branch 'macro-use' into HEAD
[rust.git] / clippy_lints / src / needless_pass_by_value.rs
index f7c93e7907a3b469571b45b95f9ce70bd981ea2f..7463ea2d9c3db8282add6b6b5287d60633392c3b 100644 (file)
@@ -1,17 +1,21 @@
+use matches::matches;
 use rustc::hir::*;
 use rustc::hir::map::*;
 use rustc::hir::intravisit::FnKind;
 use rustc::lint::*;
+use rustc::{declare_lint, lint_array};
+use if_chain::if_chain;
 use rustc::ty::{self, RegionKind, TypeFoldable};
 use rustc::traits;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
+use rustc_target::spec::abi::Abi;
 use syntax::ast::NodeId;
 use syntax_pos::Span;
 use syntax::errors::DiagnosticBuilder;
-use utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
+use crate::utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
             snippet, snippet_opt, span_lint_and_then};
-use utils::ptr::get_spans;
+use crate::utils::ptr::get_spans;
 use std::collections::{HashMap, HashSet};
 use std::borrow::Cow;
 
@@ -38,9 +42,9 @@
 ///     assert_eq!(v.len(), 42);
 /// }
 /// ```
-declare_lint! {
+declare_clippy_lint! {
     pub NEEDLESS_PASS_BY_VALUE,
-    Warn,
+    style,
     "functions taking arguments by value, but not consuming them in its body"
 }
 
@@ -71,12 +75,12 @@ fn check_fn(
         }
 
         match kind {
-            FnKind::ItemFn(.., attrs) => for a in attrs {
-                if_chain! {
-                    if a.meta_item_list().is_some();
-                    if let Some(name) = a.name();
-                    if name == "proc_macro_derive";
-                    then {
+            FnKind::ItemFn(.., header, _, attrs) => {
+                if header.abi != Abi::Rust {
+                    return;
+                }
+                for a in attrs {
+                    if a.meta_item_list().is_some() && a.name() == "proc_macro_derive" {
                         return;
                     }
                 }
@@ -87,8 +91,8 @@ fn check_fn(
 
         // Exclude non-inherent impls
         if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(node_id)) {
-            if matches!(item.node, ItemImpl(_, _, _, _, Some(_), _, _) |
-                ItemTrait(..))
+            if matches!(item.node, ItemKind::Impl(_, _, _, _, Some(_), _, _) |
+                ItemKind::Trait(..))
             {
                 return;
             }
@@ -96,10 +100,11 @@ fn check_fn(
 
         // Allow `Borrow` or functions to be taken by value
         let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));
-        let fn_traits = [
+        let whitelisted_traits = [
             need!(cx.tcx.lang_items().fn_trait()),
             need!(cx.tcx.lang_items().fn_once_trait()),
             need!(cx.tcx.lang_items().fn_mut_trait()),
+            need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT))
         ];
 
         let sized_trait = need!(cx.tcx.lang_items().sized_trait());
@@ -150,8 +155,8 @@ fn check_fn(
 
             // Ignore `self`s.
             if idx == 0 {
-                if let PatKind::Binding(_, _, name, ..) = arg.pat.node {
-                    if name.node.as_str() == "self" {
+                if let PatKind::Binding(_, _, ident, ..) = arg.pat.node {
+                    if ident.as_str() == "self" {
                         continue;
                     }
                 }
@@ -173,7 +178,11 @@ fn check_fn(
                             cx,
                             cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty),
                             t.def_id(),
-                            &t.skip_binder().input_types().skip(1).collect::<Vec<_>>(),
+                            &t.skip_binder()
+                                .input_types()
+                                .skip(1)
+                                .map(|ty| ty.into())
+                                .collect::<Vec<_>>(),
                         )
                     }),
                 )
@@ -183,7 +192,7 @@ fn check_fn(
                 if !is_self(arg);
                 if !ty.is_mutable_pointer();
                 if !is_copy(cx, ty);
-                if !fn_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
+                if !whitelisted_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
                 if !implements_borrow_trait;
                 if !all_borrowable_trait;
 
@@ -196,16 +205,27 @@ fn check_fn(
 
                     // Dereference suggestion
                     let sugg = |db: &mut DiagnosticBuilder| {
+                        if let ty::TypeVariants::TyAdt(def, ..) = ty.sty {
+                            if let Some(span) = cx.tcx.hir.span_if_local(def.did) {
+                                if cx.param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
+                                    db.span_help(span, "consider marking this type as Copy");
+                                }
+                            }
+                        }
+
                         let deref_span = spans_need_deref.get(&canonical_id);
                         if_chain! {
                             if match_type(cx, ty, &paths::VEC);
                             if let Some(clone_spans) =
                                 get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
-                            if let TyPath(QPath::Resolved(_, ref path)) = input.node;
+                            if let TyKind::Path(QPath::Resolved(_, ref path)) = input.node;
                             if let Some(elem_ty) = path.segments.iter()
-                                .find(|seg| seg.name == "Vec")
-                                .and_then(|ps| ps.parameters.as_ref())
-                                .map(|params| &params.types[0]);
+                                .find(|seg| seg.ident.name == "Vec")
+                                .and_then(|ps| ps.args.as_ref())
+                                .map(|params| params.args.iter().find_map(|arg| match arg {
+                                    GenericArg::Type(ty) => Some(ty),
+                                    GenericArg::Lifetime(_) => None,
+                                }).unwrap());
                             then {
                                 let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
                                 db.span_suggestion(input.span,
@@ -291,13 +311,13 @@ struct MovedVariablesCtxt<'a, 'tcx: 'a> {
 impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
     fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
         Self {
-            cx: cx,
+            cx,
             moved_vars: HashSet::new(),
             spans_need_deref: HashMap::new(),
         }
     }
 
-    fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: mc::cmt<'tcx>) {
+    fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: &mc::cmt_<'tcx>) {
         let cmt = unwrap_downcast_or_interior(cmt);
 
         if let mc::Categorization::Local(vid) = cmt.cat {
@@ -305,7 +325,7 @@ fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: mc::cmt<'tcx>)
         }
     }
 
-    fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
+    fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: &mc::cmt_<'tcx>) {
         let cmt = unwrap_downcast_or_interior(cmt);
 
         if let mc::Categorization::Local(vid) = cmt.cat {
@@ -322,7 +342,7 @@ fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
                     match node {
                         map::Node::NodeExpr(e) => {
                             // `match` and `if let`
-                            if let ExprMatch(ref c, ..) = e.node {
+                            if let ExprKind::Match(ref c, ..) = e.node {
                                 self.spans_need_deref
                                     .entry(vid)
                                     .or_insert_with(HashSet::new)
@@ -333,8 +353,8 @@ fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
                         map::Node::NodeStmt(s) => {
                             // `let <pat> = x;`
                             if_chain! {
-                                if let StmtDecl(ref decl, _) = s.node;
-                                if let DeclLocal(ref local) = decl.node;
+                                if let StmtKind::Decl(ref decl, _) = s.node;
+                                if let DeclKind::Local(ref local) = decl.node;
                                 then {
                                     self.spans_need_deref
                                         .entry(vid)
@@ -356,13 +376,13 @@ fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
-    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
+    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) {
         if let euv::ConsumeMode::Move(_) = mode {
             self.move_common(consume_id, consume_span, cmt);
         }
     }
 
-    fn matched_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::MatchMode) {
+    fn matched_pat(&mut self, matched_pat: &Pat, cmt: &mc::cmt_<'tcx>, mode: euv::MatchMode) {
         if let euv::MatchMode::MovingMatch = mode {
             self.move_common(matched_pat.id, matched_pat.span, cmt);
         } else {
@@ -370,27 +390,27 @@ fn matched_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::Matc
         }
     }
 
-    fn consume_pat(&mut self, consume_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
+    fn consume_pat(&mut self, consume_pat: &Pat, cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) {
         if let euv::ConsumeMode::Move(_) = mode {
             self.move_common(consume_pat.id, consume_pat.span, cmt);
         }
     }
 
-    fn borrow(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {}
+    fn borrow(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {}
 
-    fn mutate(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: euv::MutateMode) {}
+    fn mutate(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: euv::MutateMode) {}
 
     fn decl_without_init(&mut self, _: NodeId, _: Span) {}
 }
 
 
-fn unwrap_downcast_or_interior(mut cmt: mc::cmt) -> mc::cmt {
+fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt_<'tcx> {
     loop {
-        match cmt.cat.clone() {
-            mc::Categorization::Downcast(c, _) | mc::Categorization::Interior(c, _) => {
+        match cmt.cat {
+            mc::Categorization::Downcast(ref c, _) | mc::Categorization::Interior(ref c, _) => {
                 cmt = c;
             },
-            _ => return cmt,
+            _ => return (*cmt).clone(),
         }
-    }
+    };
 }