]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_borrow.rs
Merge pull request #3269 from rust-lang-nursery/relicense
[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
11 //! Checks for needless address of operations (`&`)
12 //!
13 //! This lint is **warn** by default
14
15 use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
16 use crate::rustc::{declare_tool_lint, lint_array};
17 use if_chain::if_chain;
18 use crate::rustc::hir::{BindingAnnotation, Expr, ExprKind, MutImmutable, Pat, PatKind};
19 use crate::rustc::ty;
20 use crate::rustc::ty::adjustment::{Adjust, Adjustment};
21 use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
22 use crate::rustc_errors::Applicability;
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:** This will cause false positives in code generated by `derive`.
36 /// For instance in the following snippet:
37 /// ```rust
38 /// #[derive(Debug)]
39 /// pub enum Error {
40 ///     Type(
41 ///         &'static str,
42 ///     ),
43 /// }
44 /// ```
45 /// A warning will be emitted that `&'static str` should be replaced with `&'static str`,
46 /// however there is nothing that can or should be done to fix this.
47 declare_clippy_lint! {
48     pub NEEDLESS_BORROW,
49     nursery,
50     "taking a reference that is going to be automatically dereferenced"
51 }
52
53 #[derive(Copy, Clone)]
54 pub struct NeedlessBorrow;
55
56 impl LintPass for NeedlessBorrow {
57     fn get_lints(&self) -> LintArray {
58         lint_array!(NEEDLESS_BORROW)
59     }
60 }
61
62 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
63     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
64         if in_macro(e.span) {
65             return;
66         }
67         if let ExprKind::AddrOf(MutImmutable, ref inner) = e.node {
68             if let ty::Ref(..) = cx.tables.expr_ty(inner).sty {
69                 for adj3 in cx.tables.expr_adjustments(e).windows(3) {
70                     if let [Adjustment {
71                         kind: Adjust::Deref(_),
72                         ..
73                     }, Adjustment {
74                         kind: Adjust::Deref(_),
75                         ..
76                     }, Adjustment {
77                         kind: Adjust::Borrow(_),
78                         ..
79                     }] = *adj3
80                     {
81                         span_lint_and_then(
82                             cx,
83                             NEEDLESS_BORROW,
84                             e.span,
85                             "this expression borrows a reference that is immediately dereferenced \
86                              by the compiler",
87                             |db| {
88                                 if let Some(snippet) = snippet_opt(cx, inner.span) {
89                                     db.span_suggestion_with_applicability(
90                                         e.span, 
91                                         "change this to",
92                                         snippet,
93                                         Applicability::MachineApplicable,
94                                     );
95                                 }
96                             },
97                         );
98                     }
99                 }
100             }
101         }
102     }
103     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
104         if in_macro(pat.span) {
105             return;
106         }
107         if_chain! {
108             if let PatKind::Binding(BindingAnnotation::Ref, _, name, _) = pat.node;
109             if let ty::Ref(_, tam, mutbl) = cx.tables.pat_ty(pat).sty;
110             if mutbl == MutImmutable;
111             if let ty::Ref(_, _, mutbl) = tam.sty;
112             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
113             if mutbl == MutImmutable;
114             then {
115                 span_lint_and_then(
116                     cx,
117                     NEEDLESS_BORROW,
118                     pat.span,
119                     "this pattern creates a reference to a reference",
120                     |db| {
121                         if let Some(snippet) = snippet_opt(cx, name.span) {
122                             db.span_suggestion_with_applicability(
123                                 pat.span,
124                                 "change this to",
125                                 snippet,
126                                 Applicability::MachineApplicable,
127                             );
128                         }
129                     }
130                 )
131             }
132         }
133     }
134 }