Skip to content

Commit c7da4c2

Browse files
committed
Implement flat_map lint
1 parent 1fd617d commit c7da4c2

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,7 @@ Released 2018-09-13
947947
[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
948948
[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
949949
[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
950+
[`flat_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map
950951
[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
951952
[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
952953
[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
637637
methods::FILTER_MAP,
638638
methods::FILTER_MAP_NEXT,
639639
methods::FIND_MAP,
640+
methods::FLAT_MAP,
640641
methods::MAP_FLATTEN,
641642
methods::OPTION_MAP_UNWRAP_OR,
642643
methods::OPTION_MAP_UNWRAP_OR_ELSE,

clippy_lints/src/methods/mod.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,26 @@ declare_clippy_lint! {
312312
"using combination of `filter_map` and `next` which can usually be written as a single method call"
313313
}
314314

315+
declare_clippy_lint! {
316+
/// **What it does:** Checks for usage of `flat_map(|x| x)`.
317+
///
318+
/// **Why is this bad?** Readability, this can be written more concisely by using `flatten`.
319+
///
320+
/// **Known problems:** None
321+
///
322+
/// **Example:**
323+
/// ```rust
324+
/// iter.flat_map(|x| x)
325+
/// ```
326+
/// Can be written as
327+
/// ```rust
328+
/// iter.flatten()
329+
/// ```
330+
pub FLAT_MAP,
331+
pedantic,
332+
"call to `flat_map` where `flatten` is sufficient"
333+
}
334+
315335
declare_clippy_lint! {
316336
/// **What it does:** Checks for usage of `_.find(_).map(_)`.
317337
///
@@ -844,6 +864,7 @@ declare_lint_pass!(Methods => [
844864
FILTER_NEXT,
845865
FILTER_MAP,
846866
FILTER_MAP_NEXT,
867+
FLAT_MAP,
847868
FIND_MAP,
848869
MAP_FLATTEN,
849870
ITER_NTH,
@@ -884,6 +905,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
884905
["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
885906
["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
886907
["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
908+
["flat_map", ..] => lint_flat_map(cx, expr, arg_lists[0]),
887909
["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]),
888910
["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0]),
889911
["is_some", "position"] => lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0]),
@@ -2092,6 +2114,30 @@ fn lint_filter_map_flat_map<'a, 'tcx>(
20922114
}
20932115
}
20942116

2117+
/// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient
2118+
fn lint_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, flat_map_args: &'tcx [hir::Expr]) {
2119+
if_chain! {
2120+
if match_trait_method(cx, expr, &paths::ITERATOR);
2121+
2122+
if flat_map_args.len() == 2;
2123+
if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_args[1].node;
2124+
let body = cx.tcx.hir().body(body_id);
2125+
2126+
if body.arguments.len() == 1;
2127+
if let hir::PatKind::Binding(_, _, binding_ident, _) = body.arguments[0].pat.node;
2128+
if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.node;
2129+
2130+
if path.segments.len() == 1;
2131+
if path.segments[0].ident.as_str() == binding_ident.as_str();
2132+
2133+
then {
2134+
let msg = "called `flat_map(|x| x)` on an `Iterator`. \
2135+
This can be simplified by calling `flatten().`";
2136+
span_lint(cx, FLAT_MAP, expr.span, msg);
2137+
}
2138+
}
2139+
}
2140+
20952141
/// lint searching an Iterator followed by `is_some()`
20962142
fn lint_search_is_some<'a, 'tcx>(
20972143
cx: &LateContext<'a, 'tcx>,

src/lintlist/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,13 @@ pub const ALL_LINTS: [Lint; 306] = [
553553
deprecation: None,
554554
module: "methods",
555555
},
556+
Lint {
557+
name: "flat_map",
558+
group: "pedantic",
559+
desc: "call to `flat_map` where `flatten` is sufficient",
560+
deprecation: None,
561+
module: "methods",
562+
},
556563
Lint {
557564
name: "float_arithmetic",
558565
group: "restriction",

0 commit comments

Comments
 (0)