about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-05-02 08:45:02 +0000
committerbors <bors@rust-lang.org>2019-05-02 08:45:02 +0000
commit8151a17422c503ebb52e96d83bf4ce10b2d187e0 (patch)
tree9285a7c1000f17f60cad5474e314b436d985a617
parent1cf5d7f04cc73f99ee19be6b93304666f5845665 (diff)
parentd063516c85a2d0ae368911bd8ffe3a9459a252ba (diff)
downloadrust-8151a17422c503ebb52e96d83bf4ce10b2d187e0.tar.gz
rust-8151a17422c503ebb52e96d83bf4ce10b2d187e0.zip
Auto merge of #4049 - airt:fix-4033-search_is_some, r=flip1995
Fix #4033 search_is_some

Fixes #4033.

Suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` (Lint [search_is_some](https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some))

FnDecl of `find`:

```rust
fn find<P>(&mut self, mut p: P) -> Option<Self::Item> where
    P: FnMut(&Self::Item) -> bool
```

FnDecl of `any`:

```rust
fn any<F>(&mut self, mut f: F) -> bool where
    F: FnMut(Self::Item) -> bool
```

If match on `|&_|` in closure of `find`, only use `|_|` in the suggestion.

PS. It's the first time that I have used the `hir` API, please correct me if there is any mistake 😺
-rw-r--r--clippy_lints/src/methods/mod.rs19
-rw-r--r--tests/ui/methods.stderr2
2 files changed, 18 insertions, 3 deletions
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 2904fd4c98d..4f8d29a88d6 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -2059,6 +2059,19 @@ fn lint_search_is_some<'a, 'tcx>(
         );
         let search_snippet = snippet(cx, search_args[1].span, "..");
         if search_snippet.lines().count() <= 1 {
+            // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
+            let any_search_snippet = if_chain! {
+                if search_method == "find";
+                if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].node;
+                let closure_body = cx.tcx.hir().body(body_id);
+                if let Some(closure_arg) = closure_body.arguments.get(0);
+                if let hir::PatKind::Ref(..) = closure_arg.pat.node;
+                then {
+                    Some(search_snippet.replacen('&', "", 1))
+                } else {
+                    None
+                }
+            };
             // add note if not multi-line
             span_note_and_lint(
                 cx,
@@ -2067,8 +2080,10 @@ fn lint_search_is_some<'a, 'tcx>(
                 &msg,
                 expr.span,
                 &format!(
-                    "replace `{0}({1}).is_some()` with `any({1})`",
-                    search_method, search_snippet
+                    "replace `{0}({1}).is_some()` with `any({2})`",
+                    search_method,
+                    search_snippet,
+                    any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
                 ),
             );
         } else {
diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr
index ba93be5f462..4bf53acf01e 100644
--- a/tests/ui/methods.stderr
+++ b/tests/ui/methods.stderr
@@ -155,7 +155,7 @@ LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::search-is-some` implied by `-D warnings`
-   = note: replace `find(|&x| *x < 0).is_some()` with `any(|&x| *x < 0)`
+   = note: replace `find(|&x| *x < 0).is_some()` with `any(|x| *x < 0)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
   --> $DIR/methods.rs:236:13