|
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