Skip to content

Commit 23bc650

Browse files
authored
Merge pull request #1861 from CBenoit/master
Add example for needless borrowed ref lint and register it
2 parents 9f3b3b7 + c3ef220 commit 23bc650

File tree

5 files changed

+134
-14
lines changed

5 files changed

+134
-14
lines changed

clippy_lints/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
264264
reg.register_late_lint_pass(box mutex_atomic::MutexAtomic);
265265
reg.register_late_lint_pass(box needless_update::Pass);
266266
reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow);
267+
reg.register_late_lint_pass(box needless_borrowed_ref::NeedlessBorrowedRef);
267268
reg.register_late_lint_pass(box no_effect::Pass);
268269
reg.register_late_lint_pass(box map_clone::Pass);
269270
reg.register_late_lint_pass(box temporary_assignment::Pass);

clippy_lints/src/needless_borrowed_ref.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,31 @@
44
55
use rustc::lint::*;
66
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};
98

109
/// **What it does:** Checks for useless borrowed references.
1110
///
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
1412
/// actually is.
1513
///
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
1732
///
1833
/// **Example:**
1934
/// ```rust
@@ -47,15 +62,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
4762
}
4863

4964
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,
5770
], {
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+
});
5977
}}
6078
}
6179
}
80+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#![feature(plugin)]
2+
#![plugin(clippy)]
3+
4+
#[warn(needless_borrowed_reference)]
5+
#[allow(unused_variables)]
6+
fn main() {
7+
let mut v = Vec::<String>::new();
8+
let _ = v.iter_mut().filter(|&ref a| a.is_empty());
9+
// ^ should be linted
10+
11+
let var = 3;
12+
let thingy = Some(&var);
13+
if let Some(&ref v) = thingy {
14+
// ^ should be linted
15+
}
16+
17+
let mut var2 = 5;
18+
let thingy2 = Some(&mut var2);
19+
if let Some(&mut ref mut v) = thingy2 {
20+
// ^ should *not* be linted
21+
// v is borrowed as mutable.
22+
*v = 10;
23+
}
24+
if let Some(&mut ref v) = thingy2 {
25+
// ^ should *not* be linted
26+
// here, v is borrowed as immutable.
27+
// can't do that:
28+
//*v = 15;
29+
}
30+
}
31+
32+
#[allow(dead_code)]
33+
enum Animal {
34+
Cat(u64),
35+
Dog(u64),
36+
}
37+
38+
#[allow(unused_variables)]
39+
#[allow(dead_code)]
40+
fn foo(a: &Animal, b: &Animal) {
41+
match (a, b) {
42+
(&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
43+
// ^ and ^ should *not* be linted
44+
(&Animal::Dog(ref a), &Animal::Dog(_)) => ()
45+
// ^ should *not* be linted
46+
}
47+
}
48+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error: this pattern takes a reference on something that is being de-referenced
2+
--> needless_borrowed_ref.rs:8:34
3+
|
4+
8 | let _ = v.iter_mut().filter(|&ref a| a.is_empty());
5+
| ^^^^^^ help: try removing the `&ref` part and just keep `a`
6+
|
7+
= note: `-D needless-borrowed-reference` implied by `-D warnings`
8+
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
9+
10+
error: this pattern takes a reference on something that is being de-referenced
11+
--> needless_borrowed_ref.rs:13:17
12+
|
13+
13 | if let Some(&ref v) = thingy {
14+
| ^^^^^^ help: try removing the `&ref` part and just keep `v`
15+
|
16+
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
17+
18+
error: this pattern takes a reference on something that is being de-referenced
19+
--> needless_borrowed_ref.rs:42:27
20+
|
21+
42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
22+
| ^^^^^^ help: try removing the `&ref` part and just keep `k`
23+
|
24+
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
25+
26+
error: this pattern takes a reference on something that is being de-referenced
27+
--> needless_borrowed_ref.rs:42:38
28+
|
29+
42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
30+
| ^^^^^^ help: try removing the `&ref` part and just keep `k`
31+
|
32+
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
33+
34+
error: aborting due to previous error(s)
35+
36+
error: Could not compile `clippy_tests`.
37+
38+
To learn more, run the command again with --verbose.

tests/ui/needless_borrow.stderr

+15-1
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,25 @@ error: this expression borrows a reference that is immediately dereferenced by t
1818
27 | 46 => &&a,
1919
| ^^^
2020

21+
error: this pattern takes a reference on something that is being de-referenced
22+
--> $DIR/needless_borrow.rs:49:34
23+
|
24+
49 | let _ = v.iter_mut().filter(|&ref a| a.is_empty());
25+
| ^^^^^^ help: try removing the `&ref` part and just keep: `a`
26+
|
27+
= note: `-D needless-borrowed-reference` implied by `-D warnings`
28+
29+
error: this pattern takes a reference on something that is being de-referenced
30+
--> $DIR/needless_borrow.rs:50:30
31+
|
32+
50 | let _ = v.iter().filter(|&ref a| a.is_empty());
33+
| ^^^^^^ help: try removing the `&ref` part and just keep: `a`
34+
2135
error: this pattern creates a reference to a reference
2236
--> $DIR/needless_borrow.rs:50:31
2337
|
2438
50 | let _ = v.iter().filter(|&ref a| a.is_empty());
2539
| ^^^^^
2640

27-
error: aborting due to 4 previous errors
41+
error: aborting due to 6 previous errors
2842

0 commit comments

Comments
 (0)