Auto merge of #6227 - HMPerson1:collect_map, r=phansch
Add lint for replacing `.map().collect()` with `.try_for_each()` Fixes #6208 changelog: Add `map_collect_result_unit`
This commit is contained in:
commit
c57d8ae515
@ -1803,6 +1803,7 @@ Released 2018-09-13
|
|||||||
[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
|
[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
|
||||||
[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
|
[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
|
||||||
[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
|
[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
|
||||||
|
[`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
|
||||||
[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
|
[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
|
||||||
[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
|
[`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
|
||||||
[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
|
[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
|
||||||
|
@ -702,6 +702,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
&methods::ITER_NTH_ZERO,
|
&methods::ITER_NTH_ZERO,
|
||||||
&methods::ITER_SKIP_NEXT,
|
&methods::ITER_SKIP_NEXT,
|
||||||
&methods::MANUAL_SATURATING_ARITHMETIC,
|
&methods::MANUAL_SATURATING_ARITHMETIC,
|
||||||
|
&methods::MAP_COLLECT_RESULT_UNIT,
|
||||||
&methods::MAP_FLATTEN,
|
&methods::MAP_FLATTEN,
|
||||||
&methods::MAP_UNWRAP_OR,
|
&methods::MAP_UNWRAP_OR,
|
||||||
&methods::NEW_RET_NO_SELF,
|
&methods::NEW_RET_NO_SELF,
|
||||||
@ -1428,6 +1429,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
LintId::of(&methods::ITER_NTH_ZERO),
|
LintId::of(&methods::ITER_NTH_ZERO),
|
||||||
LintId::of(&methods::ITER_SKIP_NEXT),
|
LintId::of(&methods::ITER_SKIP_NEXT),
|
||||||
LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
|
LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
|
||||||
|
LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
|
||||||
LintId::of(&methods::NEW_RET_NO_SELF),
|
LintId::of(&methods::NEW_RET_NO_SELF),
|
||||||
LintId::of(&methods::OK_EXPECT),
|
LintId::of(&methods::OK_EXPECT),
|
||||||
LintId::of(&methods::OPTION_AS_REF_DEREF),
|
LintId::of(&methods::OPTION_AS_REF_DEREF),
|
||||||
@ -1623,6 +1625,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
LintId::of(&methods::ITER_NTH_ZERO),
|
LintId::of(&methods::ITER_NTH_ZERO),
|
||||||
LintId::of(&methods::ITER_SKIP_NEXT),
|
LintId::of(&methods::ITER_SKIP_NEXT),
|
||||||
LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
|
LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
|
||||||
|
LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
|
||||||
LintId::of(&methods::NEW_RET_NO_SELF),
|
LintId::of(&methods::NEW_RET_NO_SELF),
|
||||||
LintId::of(&methods::OK_EXPECT),
|
LintId::of(&methods::OK_EXPECT),
|
||||||
LintId::of(&methods::OPTION_MAP_OR_NONE),
|
LintId::of(&methods::OPTION_MAP_OR_NONE),
|
||||||
|
@ -1349,6 +1349,27 @@ declare_clippy_lint! {
|
|||||||
"using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
|
"using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for usage of `_.map(_).collect::<Result<(),_>()`.
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// (0..3).try_for_each(|t| Err(t));
|
||||||
|
/// ```
|
||||||
|
pub MAP_COLLECT_RESULT_UNIT,
|
||||||
|
style,
|
||||||
|
"using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint_pass!(Methods => [
|
declare_lint_pass!(Methods => [
|
||||||
UNWRAP_USED,
|
UNWRAP_USED,
|
||||||
EXPECT_USED,
|
EXPECT_USED,
|
||||||
@ -1398,6 +1419,7 @@ declare_lint_pass!(Methods => [
|
|||||||
FILETYPE_IS_FILE,
|
FILETYPE_IS_FILE,
|
||||||
OPTION_AS_REF_DEREF,
|
OPTION_AS_REF_DEREF,
|
||||||
UNNECESSARY_LAZY_EVALUATIONS,
|
UNNECESSARY_LAZY_EVALUATIONS,
|
||||||
|
MAP_COLLECT_RESULT_UNIT,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for Methods {
|
impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||||
@ -1479,6 +1501,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||||||
["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
|
["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
|
||||||
["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
|
["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
|
||||||
["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
|
["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
|
||||||
|
["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3445,6 +3468,42 @@ fn lint_option_as_ref_deref<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lint_map_collect(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
expr: &hir::Expr<'_>,
|
||||||
|
map_args: &[hir::Expr<'_>],
|
||||||
|
collect_args: &[hir::Expr<'_>],
|
||||||
|
) {
|
||||||
|
if_chain! {
|
||||||
|
// called on Iterator
|
||||||
|
if let [map_expr] = collect_args;
|
||||||
|
if match_trait_method(cx, map_expr, &paths::ITERATOR);
|
||||||
|
// return of collect `Result<(),_>`
|
||||||
|
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
|
||||||
|
if is_type_diagnostic_item(cx, collect_ret_ty, sym!(result_type));
|
||||||
|
if let ty::Adt(_, substs) = collect_ret_ty.kind();
|
||||||
|
if let Some(result_t) = substs.types().next();
|
||||||
|
if result_t.is_unit();
|
||||||
|
// get parts for snippet
|
||||||
|
if let [iter, map_fn] = map_args;
|
||||||
|
then {
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
MAP_COLLECT_RESULT_UNIT,
|
||||||
|
expr.span,
|
||||||
|
"`.map().collect()` can be replaced with `.try_for_each()`",
|
||||||
|
"try this",
|
||||||
|
format!(
|
||||||
|
"{}.try_for_each({})",
|
||||||
|
snippet(cx, iter.span, ".."),
|
||||||
|
snippet(cx, map_fn.span, "..")
|
||||||
|
),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a `Result<T, E>` type, return its error type (`E`).
|
/// Given a `Result<T, E>` type, return its error type (`E`).
|
||||||
fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
|
fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
|
@ -1229,6 +1229,13 @@ vec![
|
|||||||
deprecation: None,
|
deprecation: None,
|
||||||
module: "map_clone",
|
module: "map_clone",
|
||||||
},
|
},
|
||||||
|
Lint {
|
||||||
|
name: "map_collect_result_unit",
|
||||||
|
group: "style",
|
||||||
|
desc: "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`",
|
||||||
|
deprecation: None,
|
||||||
|
module: "methods",
|
||||||
|
},
|
||||||
Lint {
|
Lint {
|
||||||
name: "map_entry",
|
name: "map_entry",
|
||||||
group: "perf",
|
group: "perf",
|
||||||
|
16
tests/ui/map_collect_result_unit.fixed
Normal file
16
tests/ui/map_collect_result_unit.fixed
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![warn(clippy::map_collect_result_unit)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
{
|
||||||
|
let _ = (0..3).try_for_each(|t| Err(t + 1));
|
||||||
|
let _: Result<(), _> = (0..3).try_for_each(|t| Err(t + 1));
|
||||||
|
|
||||||
|
let _ = (0..3).try_for_each(|t| Err(t + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _ignore() {
|
||||||
|
let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<Vec<i32>, _>>();
|
||||||
|
let _ = (0..3).map(|t| Err(t + 1)).collect::<Vec<Result<(), _>>>();
|
||||||
|
}
|
16
tests/ui/map_collect_result_unit.rs
Normal file
16
tests/ui/map_collect_result_unit.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![warn(clippy::map_collect_result_unit)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
{
|
||||||
|
let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<(), _>>();
|
||||||
|
let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect();
|
||||||
|
|
||||||
|
let _ = (0..3).try_for_each(|t| Err(t + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _ignore() {
|
||||||
|
let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<Vec<i32>, _>>();
|
||||||
|
let _ = (0..3).map(|t| Err(t + 1)).collect::<Vec<Result<(), _>>>();
|
||||||
|
}
|
16
tests/ui/map_collect_result_unit.stderr
Normal file
16
tests/ui/map_collect_result_unit.stderr
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
error: `.map().collect()` can be replaced with `.try_for_each()`
|
||||||
|
--> $DIR/map_collect_result_unit.rs:6:17
|
||||||
|
|
|
||||||
|
LL | let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<(), _>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::map-collect-result-unit` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: `.map().collect()` can be replaced with `.try_for_each()`
|
||||||
|
--> $DIR/map_collect_result_unit.rs:7:32
|
||||||
|
|
|
||||||
|
LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user