]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/needless_borrowed_ref.rs
Improve needless_borrowed_ref lint: remove the hand rolled span part.
[rust.git] / clippy_lints / src / needless_borrowed_ref.rs
1 //! Checks for useless borrowed references.
2 //!
3 //! This lint is **warn** by default
4
5 use rustc::lint::*;
6 <<<<<<< HEAD
7 use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation};
8 =======
9 use rustc::hir::{MutImmutable, Pat, PatKind};
10 <<<<<<< HEAD
11 >>>>>>> e30bf721... Improve needless_borrowed_ref and add suggestion to it.
12 use rustc::ty;
13 =======
14 >>>>>>> 4ae45c87... Improve needless_borrowed_ref lint: remove the hand rolled span part.
15 use utils::{span_lint_and_then, in_macro, snippet};
16 use rustc::hir::BindingMode::BindByRef;
17
18 /// **What it does:** Checks for useless borrowed references.
19 ///
20 /// **Why is this bad?** It is completely useless and make the code look more
21 /// complex than it
22 /// actually is.
23 ///
24 /// **Known problems:** None.
25 ///
26 /// **Example:**
27 /// ```rust
28 ///     let mut v = Vec::<String>::new();
29 ///     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
30 /// ```
31 /// This clojure takes a reference on something that has been matched as a
32 /// reference and
33 /// de-referenced.
34 /// As such, it could just be |a| a.is_empty()
35 declare_lint! {
36     pub NEEDLESS_BORROWED_REFERENCE,
37     Warn,
38     "taking a needless borrowed reference"
39 }
40
41 #[derive(Copy, Clone)]
42 pub struct NeedlessBorrowedRef;
43
44 impl LintPass for NeedlessBorrowedRef {
45     fn get_lints(&self) -> LintArray {
46         lint_array!(NEEDLESS_BORROWED_REFERENCE)
47     }
48 }
49
50 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
51     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
52         if in_macro(pat.span) {
53             // OK, simple enough, lints doesn't check in macro.
54             return;
55         }
56
57         if_let_chain! {[
58             // Pat is a pattern whose node
59             // is a binding which "involves" an immutable reference...
60             let PatKind::Binding(BindingAnnotation::Ref, ..) = pat.node,
61             // Pattern's type is a reference. Get the type and mutability of referenced value (tam: TypeAndMut).
62             let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
63             // Only lint immutable refs, because `&mut ref T` may be useful.
64             let PatKind::Ref(ref sub_pat, MutImmutable) = pat.node,
65
66             // Check sub_pat got a `ref` keyword (excluding `ref mut`).
67             let PatKind::Binding(BindByRef(MutImmutable), _, spanned_name, ..) = sub_pat.node,
68         ], {
69             span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span,
70                                "this pattern takes a reference on something that is being de-referenced",
71                                |db| {
72                                    let hint = snippet(cx, spanned_name.span, "..").into_owned();
73                                    db.span_suggestion(pat.span, "try removing the `&ref` part and just keep", hint);
74                                });
75         }}
76     }
77 }