]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
Auto merge of #82680 - jturner314:div_euclid-docs, r=JohnTitor
[rust.git] / src / tools / clippy / clippy_lints / src / methods / map_flatten.rs
1 use crate::utils::{is_type_diagnostic_item, match_trait_method, paths, snippet, span_lint_and_sugg};
2 use rustc_errors::Applicability;
3 use rustc_hir as hir;
4 use rustc_lint::LateContext;
5 use rustc_middle::ty;
6 use rustc_span::symbol::sym;
7
8 use super::MAP_FLATTEN;
9
10 /// lint use of `map().flatten()` for `Iterators` and 'Options'
11 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_args: &'tcx [hir::Expr<'_>]) {
12     // lint if caller of `.map().flatten()` is an Iterator
13     if match_trait_method(cx, expr, &paths::ITERATOR) {
14         let map_closure_ty = cx.typeck_results().expr_ty(&map_args[1]);
15         let is_map_to_option = match map_closure_ty.kind() {
16             ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
17                 let map_closure_sig = match map_closure_ty.kind() {
18                     ty::Closure(_, substs) => substs.as_closure().sig(),
19                     _ => map_closure_ty.fn_sig(cx.tcx),
20                 };
21                 let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output());
22                 is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type)
23             },
24             _ => false,
25         };
26
27         let method_to_use = if is_map_to_option {
28             // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
29             "filter_map"
30         } else {
31             // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
32             "flat_map"
33         };
34         let func_snippet = snippet(cx, map_args[1].span, "..");
35         let hint = format!(".{0}({1})", method_to_use, func_snippet);
36         span_lint_and_sugg(
37             cx,
38             MAP_FLATTEN,
39             expr.span.with_lo(map_args[0].span.hi()),
40             "called `map(..).flatten()` on an `Iterator`",
41             &format!("try using `{}` instead", method_to_use),
42             hint,
43             Applicability::MachineApplicable,
44         );
45     }
46
47     // lint if caller of `.map().flatten()` is an Option
48     if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
49         let func_snippet = snippet(cx, map_args[1].span, "..");
50         let hint = format!(".and_then({})", func_snippet);
51         span_lint_and_sugg(
52             cx,
53             MAP_FLATTEN,
54             expr.span.with_lo(map_args[0].span.hi()),
55             "called `map(..).flatten()` on an `Option`",
56             "try using `and_then` instead",
57             hint,
58             Applicability::MachineApplicable,
59         );
60     }
61 }