1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::{is_expr_path_def_path, is_trait_method, paths};
3 use if_chain::if_chain;
4 use rustc_errors::Applicability;
6 use rustc_lint::LateContext;
7 use rustc_span::{source_map::Span, sym};
9 use super::FLAT_MAP_IDENTITY;
11 /// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient
12 pub(super) fn check<'tcx>(
13 cx: &LateContext<'tcx>,
14 expr: &'tcx hir::Expr<'_>,
15 flat_map_arg: &'tcx hir::Expr<'_>,
18 if is_trait_method(cx, expr, sym::Iterator) {
19 let apply_lint = |message: &str| {
23 flat_map_span.with_hi(expr.span.hi()),
26 "flatten()".to_string(),
27 Applicability::MachineApplicable,
32 if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind;
33 let body = cx.tcx.hir().body(body_id);
35 if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
36 if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind;
38 if path.segments.len() == 1;
39 if path.segments[0].ident.name == binding_ident.name;
42 apply_lint("called `flat_map(|x| x)` on an `Iterator`");
46 if is_expr_path_def_path(cx, flat_map_arg, &paths::CONVERT_IDENTITY) {
47 apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");