Skip to content

Commit 34a9551

Browse files
committed
Lint needless_collect on non-std collection types
1 parent 13cb2b5 commit 34a9551

File tree

8 files changed

+418
-144
lines changed

8 files changed

+418
-144
lines changed

clippy_lints/src/methods/manual_str_repeat.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ pub(super) fn check(
5959
if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
6060
if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
6161
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String);
62-
if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
6362
if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
6463
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
65-
if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
6664
if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
6765
if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
6866
let ctxt = collect_expr.span.ctxt();

clippy_lints/src/methods/map_collect_result_unit.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::is_trait_method;
32
use clippy_utils::source::snippet;
43
use clippy_utils::ty::is_type_diagnostic_item;
54
use if_chain::if_chain;
@@ -11,18 +10,10 @@ use rustc_span::symbol::sym;
1110

1211
use super::MAP_COLLECT_RESULT_UNIT;
1312

14-
pub(super) fn check(
15-
cx: &LateContext<'_>,
16-
expr: &hir::Expr<'_>,
17-
iter: &hir::Expr<'_>,
18-
map_fn: &hir::Expr<'_>,
19-
collect_recv: &hir::Expr<'_>,
20-
) {
13+
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, iter: &hir::Expr<'_>, map_fn: &hir::Expr<'_>) {
14+
// return of collect `Result<(),_>`
15+
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
2116
if_chain! {
22-
// called on Iterator
23-
if is_trait_method(cx, collect_recv, sym::Iterator);
24-
// return of collect `Result<(),_>`
25-
let collect_ret_ty = cx.typeck_results().expr_ty(expr);
2617
if is_type_diagnostic_item(cx, collect_ret_ty, sym::Result);
2718
if let ty::Adt(_, substs) = collect_ret_ty.kind();
2819
if let Some(result_t) = substs.types().next();

clippy_lints/src/methods/mod.rs

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ use bind_instead_of_map::BindInsteadOfMap;
7979
use clippy_utils::consts::{constant, Constant};
8080
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
8181
use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
82-
use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
82+
use clippy_utils::{
83+
contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty,
84+
};
8385
use if_chain::if_chain;
8486
use rustc_hir as hir;
8587
use rustc_hir::def::Res;
@@ -2314,11 +2316,11 @@ impl_lint_pass!(Methods => [
23142316
]);
23152317

23162318
/// Extracts a method call name, args, and `Span` of the method name.
2317-
fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
2318-
if let ExprKind::MethodCall(path, args, _) = recv.kind {
2319+
fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span, Span)> {
2320+
if let ExprKind::MethodCall(path, args, call_span) = recv.kind {
23192321
if !args.iter().any(|e| e.span.from_expansion()) {
23202322
let name = path.ident.name.as_str();
2321-
return Some((name, args, path.ident.span));
2323+
return Some((name, args, path.ident.span, call_span));
23222324
}
23232325
}
23242326
None
@@ -2359,8 +2361,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
23592361
},
23602362
_ => (),
23612363
}
2362-
2363-
needless_collect::check(expr, cx);
23642364
}
23652365

23662366
#[allow(clippy::too_many_lines)]
@@ -2533,7 +2533,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
25332533

25342534
#[allow(clippy::too_many_lines)]
25352535
fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
2536-
if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
2536+
if let Some((name, [recv, args @ ..], span, call_span)) = method_call(expr) {
25372537
match (name, args) {
25382538
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
25392539
zst_offset::check(cx, expr, recv);
@@ -2552,34 +2552,37 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
25522552
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
25532553
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
25542554
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
2555-
("collect", []) => match method_call(recv) {
2556-
Some((name @ ("cloned" | "copied"), [recv2], _)) => {
2557-
iter_cloned_collect::check(cx, name, expr, recv2);
2558-
},
2559-
Some(("map", [m_recv, m_arg], _)) => {
2560-
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
2561-
},
2562-
Some(("take", [take_self_arg, take_arg], _)) => {
2563-
if meets_msrv(msrv, &msrvs::STR_REPEAT) {
2564-
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
2565-
}
2566-
},
2567-
_ => {},
2555+
("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
2556+
needless_collect::check(cx, span, expr, recv, call_span);
2557+
match method_call(recv) {
2558+
Some((name @ ("cloned" | "copied"), [recv2], _, _)) => {
2559+
iter_cloned_collect::check(cx, name, expr, recv2);
2560+
},
2561+
Some(("map", [m_recv, m_arg], _, _)) => {
2562+
map_collect_result_unit::check(cx, expr, m_recv, m_arg);
2563+
},
2564+
Some(("take", [take_self_arg, take_arg], _, _)) => {
2565+
if meets_msrv(msrv, &msrvs::STR_REPEAT) {
2566+
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
2567+
}
2568+
},
2569+
_ => {},
2570+
}
25682571
},
25692572
(name @ "count", args @ []) => match method_call(recv) {
2570-
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
2571-
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
2573+
Some(("cloned", [recv2], _, _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
2574+
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _, _)) => {
25722575
iter_count::check(cx, expr, recv2, name2);
25732576
},
2574-
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
2577+
Some(("map", [_, arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
25752578
_ => {},
25762579
},
25772580
("drain", [arg]) => {
25782581
iter_with_drain::check(cx, expr, recv, span, arg);
25792582
},
25802583
("expect", [_]) => match method_call(recv) {
2581-
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
2582-
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, msrv, span, err_span),
2584+
Some(("ok", [recv], _, _)) => ok_expect::check(cx, expr, recv),
2585+
Some(("err", [recv], err_span, _)) => err_expect::check(cx, expr, recv, msrv, span, err_span),
25832586
_ => expect_used::check(cx, expr, recv),
25842587
},
25852588
("extend", [arg]) => {
@@ -2598,13 +2601,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
25982601
flat_map_option::check(cx, expr, arg, span);
25992602
},
26002603
(name @ "flatten", args @ []) => match method_call(recv) {
2601-
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
2602-
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
2604+
Some(("map", [recv, map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
2605+
Some(("cloned", [recv2], _, _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
26032606
_ => {},
26042607
},
26052608
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
26062609
("for_each", [_]) => {
2607-
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
2610+
if let Some(("inspect", [_, _], span2, _)) = method_call(recv) {
26082611
inspect_for_each::check(cx, expr, span2);
26092612
}
26102613
},
@@ -2614,19 +2617,19 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
26142617
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
26152618
("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
26162619
("join", [join_arg]) => {
2617-
if let Some(("collect", _, span)) = method_call(recv) {
2620+
if let Some(("collect", _, span, _)) = method_call(recv) {
26182621
unnecessary_join::check(cx, expr, recv, join_arg, span);
26192622
}
26202623
},
26212624
("last", args @ []) | ("skip", args @ [_]) => {
2622-
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
2625+
if let Some((name2, [recv2, args2 @ ..], _span2, _)) = method_call(recv) {
26232626
if let ("cloned", []) = (name2, args2) {
26242627
iter_overeager_cloned::check(cx, expr, recv2, name, args);
26252628
}
26262629
}
26272630
},
26282631
(name @ ("map" | "map_err"), [m_arg]) => {
2629-
if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
2632+
if let Some((name, [recv2, args @ ..], span2, _)) = method_call(recv) {
26302633
match (name, args) {
26312634
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
26322635
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
@@ -2641,7 +2644,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
26412644
},
26422645
("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
26432646
(name @ "next", args @ []) => {
2644-
if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
2647+
if let Some((name2, [recv2, args2 @ ..], _, _)) = method_call(recv) {
26452648
match (name2, args2) {
26462649
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
26472650
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
@@ -2654,10 +2657,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
26542657
}
26552658
},
26562659
("nth", args @ [n_arg]) => match method_call(recv) {
2657-
Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
2658-
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
2659-
Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
2660-
Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
2660+
Some(("bytes", [recv2], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
2661+
Some(("cloned", [recv2], _, _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
2662+
Some(("iter", [recv2], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
2663+
Some(("iter_mut", [recv2], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
26612664
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
26622665
},
26632666
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
@@ -2679,7 +2682,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
26792682
},
26802683
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
26812684
("take", args @ [_arg]) => {
2682-
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
2685+
if let Some((name2, [recv2, args2 @ ..], _span2, _)) = method_call(recv) {
26832686
if let ("cloned", []) = (name2, args2) {
26842687
iter_overeager_cloned::check(cx, expr, recv2, name, args);
26852688
}
@@ -2691,30 +2694,31 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
26912694
},
26922695
("unwrap", []) => {
26932696
match method_call(recv) {
2694-
Some(("get", [recv, get_arg], _)) => {
2697+
Some(("get", [recv, get_arg], _, _)) => {
26952698
get_unwrap::check(cx, expr, recv, get_arg, false);
26962699
},
2697-
Some(("get_mut", [recv, get_arg], _)) => {
2700+
Some(("get_mut", [recv, get_arg], _, _)) => {
26982701
get_unwrap::check(cx, expr, recv, get_arg, true);
26992702
},
2700-
Some(("or", [recv, or_arg], or_span)) => {
2703+
Some(("or", [recv, or_arg], or_span, _)) => {
27012704
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
27022705
},
27032706
_ => {},
27042707
}
27052708
unwrap_used::check(cx, expr, recv);
27062709
},
27072710
("unwrap_or", [u_arg]) => match method_call(recv) {
2708-
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
2711+
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _, _)) => {
27092712
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
27102713
},
2711-
Some(("map", [m_recv, m_arg], span)) => {
2714+
Some(("map", [m_recv, m_arg], span, _)) => {
27122715
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
27132716
},
27142717
_ => {},
27152718
},
27162719
("unwrap_or_else", [u_arg]) => match method_call(recv) {
2717-
Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
2720+
Some(("map", [recv, map_arg], _, _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {
2721+
},
27182722
_ => {
27192723
unwrap_or_else_default::check(cx, expr, recv, u_arg);
27202724
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
@@ -2726,7 +2730,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
27262730
}
27272731

27282732
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
2729-
if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
2733+
if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span, _)) = method_call(recv) {
27302734
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
27312735
}
27322736
}

0 commit comments

Comments
 (0)