diff options
| author | Jeremy Stucki <stucki.jeremy@gmail.com> | 2019-06-24 15:08:26 +0200 |
|---|---|---|
| committer | Jeremy Stucki <stucki.jeremy@gmail.com> | 2019-07-08 17:11:54 +0200 |
| commit | c7da4c26fbff41c07fe03927847f3fe233d8b5ad (patch) | |
| tree | f7cc7571aa02ee2ecf94c7f019cf276f8672e53a | |
| parent | 1fd617d6df6055516b5cc4b265037e4188806d1d (diff) | |
| download | rust-c7da4c26fbff41c07fe03927847f3fe233d8b5ad.tar.gz rust-c7da4c26fbff41c07fe03927847f3fe233d8b5ad.zip | |
Implement flat_map lint
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 1 | ||||
| -rw-r--r-- | clippy_lints/src/methods/mod.rs | 46 | ||||
| -rw-r--r-- | src/lintlist/mod.rs | 7 |
4 files changed, 55 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 461adb729f9..b907b7f0e79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -947,6 +947,7 @@ Released 2018-09-13 [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next [`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map +[`flat_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map [`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic [`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp [`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d2c9e6b987..5548bb0ab62 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -637,6 +637,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { methods::FILTER_MAP, methods::FILTER_MAP_NEXT, methods::FIND_MAP, + methods::FLAT_MAP, methods::MAP_FLATTEN, methods::OPTION_MAP_UNWRAP_OR, methods::OPTION_MAP_UNWRAP_OR_ELSE, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f689a2d4ef0..1578976ed85 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -313,6 +313,26 @@ declare_clippy_lint! { } declare_clippy_lint! { + /// **What it does:** Checks for usage of `flat_map(|x| x)`. + /// + /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// iter.flat_map(|x| x) + /// ``` + /// Can be written as + /// ```rust + /// iter.flatten() + /// ``` + pub FLAT_MAP, + pedantic, + "call to `flat_map` where `flatten` is sufficient" +} + +declare_clippy_lint! { /// **What it does:** Checks for usage of `_.find(_).map(_)`. /// /// **Why is this bad?** Readability, this can be written more concisely as a @@ -844,6 +864,7 @@ declare_lint_pass!(Methods => [ FILTER_NEXT, FILTER_MAP, FILTER_MAP_NEXT, + FLAT_MAP, FIND_MAP, MAP_FLATTEN, ITER_NTH, @@ -884,6 +905,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods { ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]), ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]), + ["flat_map", ..] => lint_flat_map(cx, expr, arg_lists[0]), ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]), ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0]), ["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>( } } +/// lint use of `flat_map` for `Iterators` where `flatten` would be sufficient +fn lint_flat_map<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, flat_map_args: &'tcx [hir::Expr]) { + if_chain! { + if match_trait_method(cx, expr, &paths::ITERATOR); + + if flat_map_args.len() == 2; + if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_args[1].node; + let body = cx.tcx.hir().body(body_id); + + if body.arguments.len() == 1; + if let hir::PatKind::Binding(_, _, binding_ident, _) = body.arguments[0].pat.node; + if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = body.value.node; + + if path.segments.len() == 1; + if path.segments[0].ident.as_str() == binding_ident.as_str(); + + then { + let msg = "called `flat_map(|x| x)` on an `Iterator`. \ + This can be simplified by calling `flatten().`"; + span_lint(cx, FLAT_MAP, expr.span, msg); + } + } +} + /// lint searching an Iterator followed by `is_some()` fn lint_search_is_some<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8c49a3b1838..a7727258b53 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -554,6 +554,13 @@ pub const ALL_LINTS: [Lint; 306] = [ module: "methods", }, Lint { + name: "flat_map", + group: "pedantic", + desc: "call to `flat_map` where `flatten` is sufficient", + deprecation: None, + module: "methods", + }, + Lint { name: "float_arithmetic", group: "restriction", desc: "any floating-point arithmetic statement", |
