Merge pull request #1861 from CBenoit/master

Add example for needless borrowed ref lint and register it
This commit is contained in:
Oliver Schneider 2017-08-28 14:34:30 +02:00 committed by GitHub
commit 23bc6508bb
5 changed files with 134 additions and 14 deletions

View File

@ -264,6 +264,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box mutex_atomic::MutexAtomic);
reg.register_late_lint_pass(box needless_update::Pass);
reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow);
reg.register_late_lint_pass(box needless_borrowed_ref::NeedlessBorrowedRef);
reg.register_late_lint_pass(box no_effect::Pass);
reg.register_late_lint_pass(box map_clone::Pass);
reg.register_late_lint_pass(box temporary_assignment::Pass);

View File

@ -4,16 +4,31 @@
use rustc::lint::*;
use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation};
use rustc::ty;
use utils::{span_lint, in_macro};
use utils::{span_lint_and_then, in_macro, snippet};
/// **What it does:** Checks for useless borrowed references.
///
/// **Why is this bad?** It is completely useless and make the code look more
/// complex than it
/// **Why is this bad?** It is mostly useless and make the code look more complex than it
/// actually is.
///
/// **Known problems:** None.
/// **Known problems:** It seems that the `&ref` pattern is sometimes useful.
/// For instance in the following snippet:
/// ```rust
/// enum Animal {
/// Cat(u64),
/// Dog(u64),
/// }
///
/// fn foo(a: &Animal, b: &Animal) {
/// match (a, b) {
/// (&Animal::Cat(v), k) | (k, &Animal::Cat(v)) => (), // lifetime mismatch error
/// (&Animal::Dog(ref c), &Animal::Dog(_)) => ()
/// }
/// }
/// ```
/// There is a lifetime mismatch error for `k` (indeed a and b have distinct lifetime).
/// This can be fixed by using the `&ref` pattern.
/// However, the code can also be fixed by much cleaner ways
///
/// **Example:**
/// ```rust
@ -47,15 +62,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
}
if_let_chain! {[
// Pat is a pattern whose node
// is a binding which "involves" a immutable reference...
let PatKind::Binding(BindingAnnotation::Ref, ..) = pat.node,
// Pattern's type is a reference. Get the type and mutability of referenced value (tam: TypeAndMut).
let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
// This is an immutable reference.
tam.mutbl == MutImmutable,
// Only lint immutable refs, because `&mut ref T` may be useful.
let PatKind::Ref(ref sub_pat, MutImmutable) = pat.node,
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
let PatKind::Binding(BindingAnnotation::Ref, _, spanned_name, ..) = sub_pat.node,
], {
span_lint(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, "this pattern takes a reference on something that is being de-referenced")
span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span,
"this pattern takes a reference on something that is being de-referenced",
|db| {
let hint = snippet(cx, spanned_name.span, "..").into_owned();
db.span_suggestion(pat.span, "try removing the `&ref` part and just keep", hint);
});
}}
}
}

View File

@ -0,0 +1,48 @@
#![feature(plugin)]
#![plugin(clippy)]
#[warn(needless_borrowed_reference)]
#[allow(unused_variables)]
fn main() {
let mut v = Vec::<String>::new();
let _ = v.iter_mut().filter(|&ref a| a.is_empty());
// ^ should be linted
let var = 3;
let thingy = Some(&var);
if let Some(&ref v) = thingy {
// ^ should be linted
}
let mut var2 = 5;
let thingy2 = Some(&mut var2);
if let Some(&mut ref mut v) = thingy2 {
// ^ should *not* be linted
// v is borrowed as mutable.
*v = 10;
}
if let Some(&mut ref v) = thingy2 {
// ^ should *not* be linted
// here, v is borrowed as immutable.
// can't do that:
//*v = 15;
}
}
#[allow(dead_code)]
enum Animal {
Cat(u64),
Dog(u64),
}
#[allow(unused_variables)]
#[allow(dead_code)]
fn foo(a: &Animal, b: &Animal) {
match (a, b) {
(&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
// ^ and ^ should *not* be linted
(&Animal::Dog(ref a), &Animal::Dog(_)) => ()
// ^ should *not* be linted
}
}

View File

@ -0,0 +1,38 @@
error: this pattern takes a reference on something that is being de-referenced
--> needless_borrowed_ref.rs:8:34
|
8 | let _ = v.iter_mut().filter(|&ref a| a.is_empty());
| ^^^^^^ help: try removing the `&ref` part and just keep `a`
|
= note: `-D needless-borrowed-reference` implied by `-D warnings`
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
error: this pattern takes a reference on something that is being de-referenced
--> needless_borrowed_ref.rs:13:17
|
13 | if let Some(&ref v) = thingy {
| ^^^^^^ help: try removing the `&ref` part and just keep `v`
|
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
error: this pattern takes a reference on something that is being de-referenced
--> needless_borrowed_ref.rs:42:27
|
42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
| ^^^^^^ help: try removing the `&ref` part and just keep `k`
|
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
error: this pattern takes a reference on something that is being de-referenced
--> needless_borrowed_ref.rs:42:38
|
42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
| ^^^^^^ help: try removing the `&ref` part and just keep `k`
|
= help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#needless_borrowed_reference
error: aborting due to previous error(s)
error: Could not compile `clippy_tests`.
To learn more, run the command again with --verbose.

View File

@ -18,11 +18,25 @@ error: this expression borrows a reference that is immediately dereferenced by t
27 | 46 => &&a,
| ^^^
error: this pattern takes a reference on something that is being de-referenced
--> $DIR/needless_borrow.rs:49:34
|
49 | let _ = v.iter_mut().filter(|&ref a| a.is_empty());
| ^^^^^^ help: try removing the `&ref` part and just keep: `a`
|
= note: `-D needless-borrowed-reference` implied by `-D warnings`
error: this pattern takes a reference on something that is being de-referenced
--> $DIR/needless_borrow.rs:50:30
|
50 | let _ = v.iter().filter(|&ref a| a.is_empty());
| ^^^^^^ help: try removing the `&ref` part and just keep: `a`
error: this pattern creates a reference to a reference
--> $DIR/needless_borrow.rs:50:31
|
50 | let _ = v.iter().filter(|&ref a| a.is_empty());
| ^^^^^
error: aborting due to 4 previous errors
error: aborting due to 6 previous errors