@@ -40,6 +40,7 @@ mod string_extend_chars;
4040mod suspicious_map;
4141mod uninit_assumed_init;
4242mod unnecessary_filter_map;
43+ mod unnecessary_fold;
4344mod unnecessary_lazy_eval;
4445mod unwrap_used;
4546mod useless_asref;
@@ -53,7 +54,7 @@ use if_chain::if_chain;
5354use rustc_ast:: ast;
5455use rustc_errors:: Applicability ;
5556use rustc_hir as hir;
56- use rustc_hir:: { PatKind , TraitItem , TraitItemKind } ;
57+ use rustc_hir:: { TraitItem , TraitItemKind } ;
5758use rustc_lint:: { LateContext , LateLintPass , Lint , LintContext } ;
5859use rustc_middle:: lint:: in_external_macro;
5960use rustc_middle:: ty:: { self , TraitRef , Ty , TyS } ;
@@ -67,10 +68,9 @@ use crate::utils::eager_or_lazy::is_lazyness_candidate;
6768use crate :: utils:: usage:: mutated_variables;
6869use crate :: utils:: {
6970 contains_return, contains_ty, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of,
70- is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method,
71- match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, remove_blocks, return_ty,
72- single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
73- span_lint_and_help, span_lint_and_sugg, strip_pat_refs, SpanlessEq ,
71+ is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_type, meets_msrv,
72+ method_calls, method_chain_args, paths, return_ty, single_segment_path, snippet, snippet_with_applicability,
73+ snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq ,
7474} ;
7575
7676declare_clippy_lint ! {
@@ -1736,7 +1736,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
17361736 [ "collect" , "cloned" ] => iter_cloned_collect:: check ( cx, expr, arg_lists[ 1 ] ) ,
17371737 [ "as_ref" ] => useless_asref:: check ( cx, expr, "as_ref" , arg_lists[ 0 ] ) ,
17381738 [ "as_mut" ] => useless_asref:: check ( cx, expr, "as_mut" , arg_lists[ 0 ] ) ,
1739- [ "fold" , ..] => lint_unnecessary_fold ( cx, expr, arg_lists[ 0 ] , method_spans[ 0 ] ) ,
1739+ [ "fold" , ..] => unnecessary_fold :: check ( cx, expr, arg_lists[ 0 ] , method_spans[ 0 ] ) ,
17401740 [ "filter_map" , ..] => {
17411741 unnecessary_filter_map:: check ( cx, expr, arg_lists[ 0 ] ) ;
17421742 filter_map_identity:: check ( cx, expr, arg_lists[ 0 ] , method_spans[ 0 ] ) ;
@@ -2324,94 +2324,6 @@ fn lint_expect_fun_call(
23242324 ) ;
23252325}
23262326
2327- fn lint_unnecessary_fold ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , fold_args : & [ hir:: Expr < ' _ > ] , fold_span : Span ) {
2328- fn check_fold_with_op (
2329- cx : & LateContext < ' _ > ,
2330- expr : & hir:: Expr < ' _ > ,
2331- fold_args : & [ hir:: Expr < ' _ > ] ,
2332- fold_span : Span ,
2333- op : hir:: BinOpKind ,
2334- replacement_method_name : & str ,
2335- replacement_has_args : bool ,
2336- ) {
2337- if_chain ! {
2338- // Extract the body of the closure passed to fold
2339- if let hir:: ExprKind :: Closure ( _, _, body_id, _, _) = fold_args[ 2 ] . kind;
2340- let closure_body = cx. tcx. hir( ) . body( body_id) ;
2341- let closure_expr = remove_blocks( & closure_body. value) ;
2342-
2343- // Check if the closure body is of the form `acc <op> some_expr(x)`
2344- if let hir:: ExprKind :: Binary ( ref bin_op, ref left_expr, ref right_expr) = closure_expr. kind;
2345- if bin_op. node == op;
2346-
2347- // Extract the names of the two arguments to the closure
2348- if let [ param_a, param_b] = closure_body. params;
2349- if let PatKind :: Binding ( _, first_arg_id, ..) = strip_pat_refs( & param_a. pat) . kind;
2350- if let PatKind :: Binding ( _, second_arg_id, second_arg_ident, _) = strip_pat_refs( & param_b. pat) . kind;
2351-
2352- if path_to_local_id( left_expr, first_arg_id) ;
2353- if replacement_has_args || path_to_local_id( right_expr, second_arg_id) ;
2354-
2355- then {
2356- let mut applicability = Applicability :: MachineApplicable ;
2357- let sugg = if replacement_has_args {
2358- format!(
2359- "{replacement}(|{s}| {r})" ,
2360- replacement = replacement_method_name,
2361- s = second_arg_ident,
2362- r = snippet_with_applicability( cx, right_expr. span, "EXPR" , & mut applicability) ,
2363- )
2364- } else {
2365- format!(
2366- "{replacement}()" ,
2367- replacement = replacement_method_name,
2368- )
2369- } ;
2370-
2371- span_lint_and_sugg(
2372- cx,
2373- UNNECESSARY_FOLD ,
2374- fold_span. with_hi( expr. span. hi( ) ) ,
2375- // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
2376- "this `.fold` can be written more succinctly using another method" ,
2377- "try" ,
2378- sugg,
2379- applicability,
2380- ) ;
2381- }
2382- }
2383- }
2384-
2385- // Check that this is a call to Iterator::fold rather than just some function called fold
2386- if !match_trait_method ( cx, expr, & paths:: ITERATOR ) {
2387- return ;
2388- }
2389-
2390- assert ! (
2391- fold_args. len( ) == 3 ,
2392- "Expected fold_args to have three entries - the receiver, the initial value and the closure"
2393- ) ;
2394-
2395- // Check if the first argument to .fold is a suitable literal
2396- if let hir:: ExprKind :: Lit ( ref lit) = fold_args[ 1 ] . kind {
2397- match lit. node {
2398- ast:: LitKind :: Bool ( false ) => {
2399- check_fold_with_op ( cx, expr, fold_args, fold_span, hir:: BinOpKind :: Or , "any" , true )
2400- } ,
2401- ast:: LitKind :: Bool ( true ) => {
2402- check_fold_with_op ( cx, expr, fold_args, fold_span, hir:: BinOpKind :: And , "all" , true )
2403- } ,
2404- ast:: LitKind :: Int ( 0 , _) => {
2405- check_fold_with_op ( cx, expr, fold_args, fold_span, hir:: BinOpKind :: Add , "sum" , false )
2406- } ,
2407- ast:: LitKind :: Int ( 1 , _) => {
2408- check_fold_with_op ( cx, expr, fold_args, fold_span, hir:: BinOpKind :: Mul , "product" , false )
2409- } ,
2410- _ => ( ) ,
2411- }
2412- }
2413- }
2414-
24152327fn derefs_to_slice < ' tcx > (
24162328 cx : & LateContext < ' tcx > ,
24172329 expr : & ' tcx hir:: Expr < ' tcx > ,
0 commit comments