about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkyoto7250 <50972773+kyoto7250@users.noreply.github.com>2022-06-02 00:57:08 +0900
committerkyoto7250 <50972773+kyoto7250@users.noreply.github.com>2022-06-02 09:54:14 +0900
commit007fae10ed8c8fa51b396bcc02071fe792f2c288 (patch)
treed5736bf47d5a61562153a6d5f02d1a4395593d86
parent39231b4b503955626c1ccf965b8328ac67c523bb (diff)
downloadrust-007fae10ed8c8fa51b396bcc02071fe792f2c288.tar.gz
rust-007fae10ed8c8fa51b396bcc02071fe792f2c288.zip
fix(manual_find_map and manual_filter_map): check clone method
-rw-r--r--clippy_lints/src/methods/filter_map.rs10
-rw-r--r--tests/ui/manual_filter_map.fixed22
-rw-r--r--tests/ui/manual_filter_map.rs23
-rw-r--r--tests/ui/manual_filter_map.stderr16
-rw-r--r--tests/ui/manual_find_map.fixed20
-rw-r--r--tests/ui/manual_find_map.rs20
-rw-r--r--tests/ui/manual_find_map.stderr14
7 files changed, 122 insertions, 3 deletions
diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs
index 558cb6bd64e..04ca295dc69 100644
--- a/clippy_lints/src/methods/filter_map.rs
+++ b/clippy_lints/src/methods/filter_map.rs
@@ -155,7 +155,15 @@ pub(super) fn check<'tcx>(
                 }
                 false
             };
-            if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
+
+            if match map_arg.kind {
+                ExprKind::MethodCall(clone, [original_arg], _) => {
+                    clone.ident.name == sym::clone
+                        && SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, original_arg)
+                },
+                _ => SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg)
+            };
+
             then {
                 let span = filter_span.with_hi(expr.span.hi());
                 let (filter_name, lint) = if is_find {
diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed
index fc8f58f8ea5..c88a4f43de2 100644
--- a/tests/ui/manual_filter_map.fixed
+++ b/tests/ui/manual_filter_map.fixed
@@ -35,3 +35,25 @@ fn to_opt<T>(_: T) -> Option<T> {
 fn to_res<T>(_: T) -> Result<T, ()> {
     unimplemented!()
 }
+
+struct OptionFoo {
+    field: Option<String>,
+}
+
+struct ResultFoo {
+    field: Result<String, ()>,
+}
+
+fn issue_8920() {
+    let vec = vec![OptionFoo {
+        field: Some(String::from("str")),
+    }];
+    let _ = vec
+        .iter()
+        .filter_map(|f| f.field.clone());
+
+    let vec = vec![ResultFoo {
+        field: Ok(String::from("str")),
+    }];
+    let _ = vec.iter().filter_map(|f| f.field.clone().ok());
+}
diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs
index 3af4bbee3bf..bb859ebe315 100644
--- a/tests/ui/manual_filter_map.rs
+++ b/tests/ui/manual_filter_map.rs
@@ -35,3 +35,26 @@ fn to_opt<T>(_: T) -> Option<T> {
 fn to_res<T>(_: T) -> Result<T, ()> {
     unimplemented!()
 }
+
+struct OptionFoo {
+    field: Option<String>,
+}
+
+struct ResultFoo {
+    field: Result<String, ()>,
+}
+
+fn issue_8920() {
+    let vec = vec![OptionFoo {
+        field: Some(String::from("str")),
+    }];
+    let _ = vec
+        .iter()
+        .filter(|f| f.field.is_some())
+        .map(|f| f.field.clone().unwrap());
+
+    let vec = vec![ResultFoo {
+        field: Ok(String::from("str")),
+    }];
+    let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap());
+}
diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr
index 4d4e2d5c12f..a78343e882f 100644
--- a/tests/ui/manual_filter_map.stderr
+++ b/tests/ui/manual_filter_map.stderr
@@ -18,5 +18,19 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)`
 LL |     let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
 
-error: aborting due to 3 previous errors
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+  --> $DIR/manual_filter_map.rs:53:10
+   |
+LL |           .filter(|f| f.field.is_some())
+   |  __________^
+LL | |         .map(|f| f.field.clone().unwrap());
+   | |__________________________________________^ help: try: `filter_map(|f| f.field.clone())`
+
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+  --> $DIR/manual_filter_map.rs:59:24
+   |
+LL |     let _ = vec.iter().filter(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap());
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|f| f.field.clone().ok())`
+
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed
index 95e97c4fd1f..d78d72d8e8f 100644
--- a/tests/ui/manual_find_map.fixed
+++ b/tests/ui/manual_find_map.fixed
@@ -35,3 +35,23 @@ fn to_opt<T>(_: T) -> Option<T> {
 fn to_res<T>(_: T) -> Result<T, ()> {
     unimplemented!()
 }
+
+struct OptionFoo {
+    field: Option<String>,
+}
+
+struct ResultFoo {
+    field: Result<String, ()>,
+}
+
+fn issue_8920() {
+    let vec = vec![OptionFoo {
+        field: Some(String::from("str")),
+    }];
+    let _ = vec.iter().find_map(|f| f.field.clone());
+
+    let vec = vec![ResultFoo {
+        field: Ok(String::from("str")),
+    }];
+    let _ = vec.iter().find_map(|f| f.field.clone().ok());
+}
diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs
index cd3c82e3b25..74e8e52ed16 100644
--- a/tests/ui/manual_find_map.rs
+++ b/tests/ui/manual_find_map.rs
@@ -35,3 +35,23 @@ fn to_opt<T>(_: T) -> Option<T> {
 fn to_res<T>(_: T) -> Result<T, ()> {
     unimplemented!()
 }
+
+struct OptionFoo {
+    field: Option<String>,
+}
+
+struct ResultFoo {
+    field: Result<String, ()>,
+}
+
+fn issue_8920() {
+    let vec = vec![OptionFoo {
+        field: Some(String::from("str")),
+    }];
+    let _ = vec.iter().find(|f| f.field.is_some()).map(|f| f.field.clone().unwrap());
+
+    let vec = vec![ResultFoo {
+        field: Ok(String::from("str")),
+    }];
+    let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap());
+}
diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr
index 9e7f798df45..0b1465a8422 100644
--- a/tests/ui/manual_find_map.stderr
+++ b/tests/ui/manual_find_map.stderr
@@ -18,5 +18,17 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
 LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())`
 
-error: aborting due to 3 previous errors
+error: `find(..).map(..)` can be simplified as `find_map(..)`
+  --> $DIR/manual_find_map.rs:51:24
+   |
+LL |     let _ = vec.iter().find(|f| f.field.is_some()).map(|f| f.field.clone().unwrap());
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.clone())`
+
+error: `find(..).map(..)` can be simplified as `find_map(..)`
+  --> $DIR/manual_find_map.rs:56:24
+   |
+LL |     let _ = vec.iter().find(|f| f.field.is_ok()).map(|f| f.field.clone().unwrap());
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|f| f.field.clone().ok())`
+
+error: aborting due to 5 previous errors