]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_borrow.rs
Remove fix for rustc bug from `needless_borrow`
[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 clippy_utils::diagnostics::span_lint_and_then;
6 use clippy_utils::source::snippet_opt;
7 use if_chain::if_chain;
8 use rustc_errors::Applicability;
9 use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
10 use rustc_lint::{LateContext, LateLintPass};
11 use rustc_middle::ty;
12 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
13 use rustc_session::{declare_tool_lint, impl_lint_pass};
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     /// **Known problems:** None.
23     ///
24     /// **Example:**
25     /// ```rust
26     /// // Bad
27     /// let x: &i32 = &&&&&&5;
28     ///
29     /// // Good
30     /// let x: &i32 = &5;
31     /// ```
32     pub NEEDLESS_BORROW,
33     nursery,
34     "taking a reference that is going to be automatically dereferenced"
35 }
36
37 #[derive(Default)]
38 pub struct NeedlessBorrow;
39
40 impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
41
42 impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
43     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
44         if e.span.from_expansion() {
45             return;
46         }
47         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
48             if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
49                 for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
50                     if let [Adjustment {
51                         kind: Adjust::Deref(_), ..
52                     }, Adjustment {
53                         kind: Adjust::Deref(_), ..
54                     }, Adjustment {
55                         kind: Adjust::Borrow(_),
56                         ..
57                     }] = *adj3
58                     {
59                         span_lint_and_then(
60                             cx,
61                             NEEDLESS_BORROW,
62                             e.span,
63                             &format!(
64                                 "this expression borrows a reference (`&{}`) that is immediately dereferenced \
65                              by the compiler",
66                                 ty
67                             ),
68                             |diag| {
69                                 if let Some(snippet) = snippet_opt(cx, inner.span) {
70                                     diag.span_suggestion(
71                                         e.span,
72                                         "change this to",
73                                         snippet,
74                                         Applicability::MachineApplicable,
75                                     );
76                                 }
77                             },
78                         );
79                     }
80                 }
81             }
82         }
83     }
84     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
85         if pat.span.from_expansion() {
86             return;
87         }
88         if_chain! {
89             if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
90             if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
91             if mutbl == Mutability::Not;
92             if let ty::Ref(_, _, mutbl) = *tam.kind();
93             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
94             if mutbl == Mutability::Not;
95             then {
96                 span_lint_and_then(
97                     cx,
98                     NEEDLESS_BORROW,
99                     pat.span,
100                     "this pattern creates a reference to a reference",
101                     |diag| {
102                         if let Some(snippet) = snippet_opt(cx, name.span) {
103                             diag.span_suggestion(
104                                 pat.span,
105                                 "change this to",
106                                 snippet,
107                                 Applicability::MachineApplicable,
108                             );
109                         }
110                     }
111                 )
112             }
113         }
114     }
115 }