about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCameron Steffen <cam.steffen94@gmail.com>2021-05-05 16:05:16 -0500
committerCameron Steffen <cam.steffen94@gmail.com>2021-05-05 16:44:00 -0500
commitd66d37303c7074e8e26a0f67bba5a36cd6b12e29 (patch)
tree057d56fe93f699f0b87bddacec1ced923f109003
parenta8f28b636515cd859d8c9cc78dd17794f8a3c0ad (diff)
downloadrust-d66d37303c7074e8e26a0f67bba5a36cd6b12e29.tar.gz
rust-d66d37303c7074e8e26a0f67bba5a36cd6b12e29.zip
Fix unnecessary_filter_map false positive
-rw-r--r--clippy_lints/src/methods/unnecessary_filter_map.rs40
-rw-r--r--tests/ui/unnecessary_filter_map.rs4
2 files changed, 26 insertions, 18 deletions
diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs
index b61c4ffe9b3..8b66587bfd1 100644
--- a/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -6,6 +6,7 @@ use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
+use rustc_middle::ty::{self, TyS};
 use rustc_span::sym;
 
 use super::UNNECESSARY_FILTER_MAP;
@@ -28,25 +29,28 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
         found_mapping |= return_visitor.found_mapping;
         found_filtering |= return_visitor.found_filtering;
 
-        if !found_filtering {
-            span_lint(
-                cx,
-                UNNECESSARY_FILTER_MAP,
-                expr.span,
-                "this `.filter_map` can be written more simply using `.map`",
-            );
-            return;
-        }
-
-        if !found_mapping && !mutates_arg {
-            span_lint(
-                cx,
-                UNNECESSARY_FILTER_MAP,
-                expr.span,
-                "this `.filter_map` can be written more simply using `.filter`",
-            );
+        let sugg = if !found_filtering {
+            "map"
+        } else if !found_mapping && !mutates_arg {
+            let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
+            match cx.typeck_results().expr_ty(&body.value).kind() {
+                ty::Adt(adt, subst)
+                    if cx.tcx.is_diagnostic_item(sym::option_type, adt.did)
+                        && TyS::same_type(in_ty, subst.type_at(0)) =>
+                {
+                    "filter"
+                },
+                _ => return,
+            }
+        } else {
             return;
-        }
+        };
+        span_lint(
+            cx,
+            UNNECESSARY_FILTER_MAP,
+            expr.span,
+            &format!("this `.filter_map` can be written more simply using `.{}`", sugg),
+        );
     }
 }
 
diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs
index af858e4abcf..c58181f518d 100644
--- a/tests/ui/unnecessary_filter_map.rs
+++ b/tests/ui/unnecessary_filter_map.rs
@@ -15,3 +15,7 @@ fn main() {
 
     let _ = (0..4).filter_map(i32::checked_abs);
 }
+
+fn filter_map_none_changes_item_type() -> impl Iterator<Item = bool> {
+    "".chars().filter_map(|_| None)
+}