]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_borrow.rs
Rustup to rust-lang/rust#66936
[rust.git] / clippy_lints / src / needless_borrow.rs
1 //! Checks for needless address of operations (`&`)
2 //!
3 //! This lint is **warn** by default
4
5 use crate::utils::{snippet_opt, span_lint_and_then};
6 use if_chain::if_chain;
7 use rustc::hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind};
8 use rustc::impl_lint_pass;
9 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
10 use rustc::ty;
11 use rustc::ty::adjustment::{Adjust, Adjustment};
12 use rustc_errors::Applicability;
13 use rustc_session::declare_tool_lint;
14
15 declare_clippy_lint! {
16     /// **What it does:** Checks for address of operations (`&`) that are going to
17     /// be dereferenced immediately by the compiler.
18     ///
19     /// **Why is this bad?** Suggests that the receiver of the expression borrows
20     /// the expression.
21     ///
22     /// **Example:**
23     /// ```rust
24     /// let x: &i32 = &&&&&&5;
25     /// ```
26     ///
27     /// **Known problems:** None.
28     pub NEEDLESS_BORROW,
29     nursery,
30     "taking a reference that is going to be automatically dereferenced"
31 }
32
33 #[derive(Default)]
34 pub struct NeedlessBorrow {
35     derived_item: Option<HirId>,
36 }
37
38 impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
39
40 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
41     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
42         if e.span.from_expansion() || self.derived_item.is_some() {
43             return;
44         }
45         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, ref inner) = e.kind {
46             if let ty::Ref(..) = cx.tables.expr_ty(inner).kind {
47                 for adj3 in cx.tables.expr_adjustments(e).windows(3) {
48                     if let [Adjustment {
49                         kind: Adjust::Deref(_), ..
50                     }, Adjustment {
51                         kind: Adjust::Deref(_), ..
52                     }, Adjustment {
53                         kind: Adjust::Borrow(_),
54                         ..
55                     }] = *adj3
56                     {
57                         span_lint_and_then(
58                             cx,
59                             NEEDLESS_BORROW,
60                             e.span,
61                             "this expression borrows a reference that is immediately dereferenced \
62                              by the compiler",
63                             |db| {
64                                 if let Some(snippet) = snippet_opt(cx, inner.span) {
65                                     db.span_suggestion(
66                                         e.span,
67                                         "change this to",
68                                         snippet,
69                                         Applicability::MachineApplicable,
70                                     );
71                                 }
72                             },
73                         );
74                     }
75                 }
76             }
77         }
78     }
79     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat<'_>) {
80         if pat.span.from_expansion() || self.derived_item.is_some() {
81             return;
82         }
83         if_chain! {
84             if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
85             if let ty::Ref(_, tam, mutbl) = cx.tables.pat_ty(pat).kind;
86             if mutbl == Mutability::Not;
87             if let ty::Ref(_, _, mutbl) = tam.kind;
88             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
89             if mutbl == Mutability::Not;
90             then {
91                 span_lint_and_then(
92                     cx,
93                     NEEDLESS_BORROW,
94                     pat.span,
95                     "this pattern creates a reference to a reference",
96                     |db| {
97                         if let Some(snippet) = snippet_opt(cx, name.span) {
98                             db.span_suggestion(
99                                 pat.span,
100                                 "change this to",
101                                 snippet,
102                                 Applicability::MachineApplicable,
103                             );
104                         }
105                     }
106                 )
107             }
108         }
109     }
110
111     fn check_item(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
112         if item.attrs.iter().any(|a| a.check_name(sym!(automatically_derived))) {
113             debug_assert!(self.derived_item.is_none());
114             self.derived_item = Some(item.hir_id);
115         }
116     }
117
118     fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
119         if let Some(id) = self.derived_item {
120             if item.hir_id == id {
121                 self.derived_item = None;
122             }
123         }
124     }
125 }