|  | 
| 4 | 4 | 
 | 
| 5 | 5 | use rustc::lint::*; | 
| 6 | 6 | use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation}; | 
| 7 |  | -use rustc::ty; | 
| 8 |  | -use utils::{span_lint, in_macro}; | 
|  | 7 | +use utils::{span_lint_and_then, in_macro, snippet}; | 
| 9 | 8 | 
 | 
| 10 | 9 | /// **What it does:** Checks for useless borrowed references. | 
| 11 | 10 | /// | 
| 12 |  | -/// **Why is this bad?** It is completely useless and make the code look more | 
| 13 |  | -/// complex than it | 
|  | 11 | +/// **Why is this bad?** It is mostly useless and make the code look more complex than it | 
| 14 | 12 | /// actually is. | 
| 15 | 13 | /// | 
| 16 |  | -/// **Known problems:** None. | 
|  | 14 | +/// **Known problems:** It seems that the `&ref` pattern is sometimes useful. | 
|  | 15 | +/// For instance in the following snippet: | 
|  | 16 | +/// ```rust | 
|  | 17 | +/// enum Animal { | 
|  | 18 | +///     Cat(u64), | 
|  | 19 | +///     Dog(u64), | 
|  | 20 | +/// } | 
|  | 21 | +/// | 
|  | 22 | +/// fn foo(a: &Animal, b: &Animal) { | 
|  | 23 | +///     match (a, b) { | 
|  | 24 | +///         (&Animal::Cat(v), k) | (k, &Animal::Cat(v)) => (), // lifetime mismatch error | 
|  | 25 | +///         (&Animal::Dog(ref c), &Animal::Dog(_)) => () | 
|  | 26 | +///     } | 
|  | 27 | +/// } | 
|  | 28 | +/// ``` | 
|  | 29 | +/// There is a lifetime mismatch error for `k` (indeed a and b have distinct lifetime). | 
|  | 30 | +/// This can be fixed by using the `&ref` pattern. | 
|  | 31 | +/// However, the code can also be fixed by much cleaner ways | 
| 17 | 32 | /// | 
| 18 | 33 | /// **Example:** | 
| 19 | 34 | /// ```rust | 
| @@ -47,15 +62,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef { | 
| 47 | 62 |         } | 
| 48 | 63 | 
 | 
| 49 | 64 |         if_let_chain! {[ | 
| 50 |  | -            // Pat is a pattern whose node | 
| 51 |  | -            // is a binding which "involves" a immutable reference... | 
| 52 |  | -            let PatKind::Binding(BindingAnnotation::Ref, ..) = pat.node, | 
| 53 |  | -            // Pattern's type is a reference. Get the type and mutability of referenced value (tam: TypeAndMut). | 
| 54 |  | -            let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty, | 
| 55 |  | -            // This is an immutable reference. | 
| 56 |  | -            tam.mutbl == MutImmutable, | 
|  | 65 | +            // Only lint immutable refs, because `&mut ref T` may be useful. | 
|  | 66 | +            let PatKind::Ref(ref sub_pat, MutImmutable) = pat.node, | 
|  | 67 | + | 
|  | 68 | +            // Check sub_pat got a `ref` keyword (excluding `ref mut`). | 
|  | 69 | +            let PatKind::Binding(BindingAnnotation::Ref, _, spanned_name, ..) = sub_pat.node, | 
| 57 | 70 |         ], { | 
| 58 |  | -            span_lint(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, "this pattern takes a reference on something that is being de-referenced") | 
|  | 71 | +            span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, | 
|  | 72 | +                               "this pattern takes a reference on something that is being de-referenced", | 
|  | 73 | +                               |db| { | 
|  | 74 | +                                   let hint = snippet(cx, spanned_name.span, "..").into_owned(); | 
|  | 75 | +                                   db.span_suggestion(pat.span, "try removing the `&ref` part and just keep", hint); | 
|  | 76 | +                               }); | 
| 59 | 77 |         }} | 
| 60 | 78 |     } | 
| 61 | 79 | } | 
|  | 80 | + | 
0 commit comments