]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_borrow.rs
Auto merge of #3558 - russelltg:new_without_default_merge, r=flip1995
[rust.git] / clippy_lints / src / needless_borrow.rs
1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 //! Checks for needless address of operations (`&`)
11 //!
12 //! This lint is **warn** by default
13
14 use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
15 use if_chain::if_chain;
16 use rustc::hir::{BindingAnnotation, Expr, ExprKind, Item, MutImmutable, Pat, PatKind};
17 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
18 use rustc::ty;
19 use rustc::ty::adjustment::{Adjust, Adjustment};
20 use rustc::{declare_tool_lint, lint_array};
21 use rustc_errors::Applicability;
22 use syntax::ast::NodeId;
23
24 /// **What it does:** Checks for address of operations (`&`) that are going to
25 /// be dereferenced immediately by the compiler.
26 ///
27 /// **Why is this bad?** Suggests that the receiver of the expression borrows
28 /// the expression.
29 ///
30 /// **Example:**
31 /// ```rust
32 /// let x: &i32 = &&&&&&5;
33 /// ```
34 ///
35 /// **Known problems:** None.
36 declare_clippy_lint! {
37     pub NEEDLESS_BORROW,
38     nursery,
39     "taking a reference that is going to be automatically dereferenced"
40 }
41
42 #[derive(Default)]
43 pub struct NeedlessBorrow {
44     derived_item: Option<NodeId>,
45 }
46
47 impl LintPass for NeedlessBorrow {
48     fn get_lints(&self) -> LintArray {
49         lint_array!(NEEDLESS_BORROW)
50     }
51 }
52
53 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
54     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
55         if in_macro(e.span) || self.derived_item.is_some() {
56             return;
57         }
58         if let ExprKind::AddrOf(MutImmutable, ref inner) = e.node {
59             if let ty::Ref(..) = cx.tables.expr_ty(inner).sty {
60                 for adj3 in cx.tables.expr_adjustments(e).windows(3) {
61                     if let [Adjustment {
62                         kind: Adjust::Deref(_), ..
63                     }, Adjustment {
64                         kind: Adjust::Deref(_), ..
65                     }, Adjustment {
66                         kind: Adjust::Borrow(_),
67                         ..
68                     }] = *adj3
69                     {
70                         span_lint_and_then(
71                             cx,
72                             NEEDLESS_BORROW,
73                             e.span,
74                             "this expression borrows a reference that is immediately dereferenced \
75                              by the compiler",
76                             |db| {
77                                 if let Some(snippet) = snippet_opt(cx, inner.span) {
78                                     db.span_suggestion_with_applicability(
79                                         e.span,
80                                         "change this to",
81                                         snippet,
82                                         Applicability::MachineApplicable,
83                                     );
84                                 }
85                             },
86                         );
87                     }
88                 }
89             }
90         }
91     }
92     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
93         if in_macro(pat.span) || self.derived_item.is_some() {
94             return;
95         }
96         if_chain! {
97             if let PatKind::Binding(BindingAnnotation::Ref, _, name, _) = pat.node;
98             if let ty::Ref(_, tam, mutbl) = cx.tables.pat_ty(pat).sty;
99             if mutbl == MutImmutable;
100             if let ty::Ref(_, _, mutbl) = tam.sty;
101             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
102             if mutbl == MutImmutable;
103             then {
104                 span_lint_and_then(
105                     cx,
106                     NEEDLESS_BORROW,
107                     pat.span,
108                     "this pattern creates a reference to a reference",
109                     |db| {
110                         if let Some(snippet) = snippet_opt(cx, name.span) {
111                             db.span_suggestion_with_applicability(
112                                 pat.span,
113                                 "change this to",
114                                 snippet,
115                                 Applicability::MachineApplicable,
116                             );
117                         }
118                     }
119                 )
120             }
121         }
122     }
123
124     fn check_item(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
125         if item.attrs.iter().any(|a| a.check_name("automatically_derived")) {
126             debug_assert!(self.derived_item.is_none());
127             self.derived_item = Some(item.id);
128         }
129     }
130
131     fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
132         if let Some(id) = self.derived_item {
133             if item.id == id {
134                 self.derived_item = None;
135             }
136         }
137     }
138 }