1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::source
::snippet_with_applicability
;
3 use clippy_utils
::{is_trait_method, path_to_local_id, peel_blocks, strip_pat_refs}
;
4 use if_chain
::if_chain
;
6 use rustc_errors
::Applicability
;
8 use rustc_hir
::PatKind
;
9 use rustc_lint
::LateContext
;
10 use rustc_span
::{source_map::Span, sym}
;
12 use super::UNNECESSARY_FOLD
;
21 fn check_fold_with_op(
27 replacement_method_name
: &str,
28 replacement_has_args
: bool
,
31 // Extract the body of the closure passed to fold
32 if let hir
::ExprKind
::Closure(&hir
::Closure { body, .. }
) = acc
.kind
;
33 let closure_body
= cx
.tcx
.hir().body(body
);
34 let closure_expr
= peel_blocks(closure_body
.value
);
36 // Check if the closure body is of the form `acc <op> some_expr(x)`
37 if let hir
::ExprKind
::Binary(ref bin_op
, left_expr
, right_expr
) = closure_expr
.kind
;
40 // Extract the names of the two arguments to the closure
41 if let [param_a
, param_b
] = closure_body
.params
;
42 if let PatKind
::Binding(_
, first_arg_id
, ..) = strip_pat_refs(param_a
.pat
).kind
;
43 if let PatKind
::Binding(_
, second_arg_id
, second_arg_ident
, _
) = strip_pat_refs(param_b
.pat
).kind
;
45 if path_to_local_id(left_expr
, first_arg_id
);
46 if replacement_has_args
|| path_to_local_id(right_expr
, second_arg_id
);
49 let mut applicability
= Applicability
::MachineApplicable
;
50 let sugg
= if replacement_has_args
{
52 "{replacement_method_name}(|{second_arg_ident}| {r})",
53 r
= snippet_with_applicability(cx
, right_expr
.span
, "EXPR", &mut applicability
),
57 "{replacement_method_name}()",
64 fold_span
.with_hi(expr
.span
.hi()),
65 // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
66 "this `.fold` can be written more succinctly using another method",
75 // Check that this is a call to Iterator::fold rather than just some function called fold
76 if !is_trait_method(cx
, expr
, sym
::Iterator
) {
80 // Check if the first argument to .fold is a suitable literal
81 if let hir
::ExprKind
::Lit(ref lit
) = init
.kind
{
83 ast
::LitKind
::Bool(false) => check_fold_with_op(cx
, expr
, acc
, fold_span
, hir
::BinOpKind
::Or
, "any", true),
84 ast
::LitKind
::Bool(true) => check_fold_with_op(cx
, expr
, acc
, fold_span
, hir
::BinOpKind
::And
, "all", true),
85 ast
::LitKind
::Int(0, _
) => check_fold_with_op(cx
, expr
, acc
, fold_span
, hir
::BinOpKind
::Add
, "sum", false),
86 ast
::LitKind
::Int(1, _
) => {
87 check_fold_with_op(cx
, expr
, acc
, fold_span
, hir
::BinOpKind
::Mul
, "product", false);