11use clippy_utils:: diagnostics:: span_lint_and_sugg;
2- use clippy_utils:: res:: { MaybeDef , MaybeResPath , MaybeTypeckRes } ;
2+ use clippy_utils:: res:: { MaybeDef , MaybeQPath , MaybeResPath , MaybeTypeckRes } ;
33use clippy_utils:: source:: snippet_with_applicability;
44use clippy_utils:: { peel_blocks, strip_pat_refs} ;
55use rustc_ast:: ast;
66use rustc_data_structures:: packed:: Pu128 ;
77use rustc_errors:: Applicability ;
88use rustc_hir as hir;
99use rustc_hir:: PatKind ;
10+ use rustc_hir:: def:: { DefKind , Res } ;
1011use rustc_lint:: LateContext ;
1112use rustc_middle:: ty;
12- use rustc_span:: { Span , sym} ;
13+ use rustc_span:: { Span , Symbol , sym} ;
1314
1415use super :: UNNECESSARY_FOLD ;
1516
@@ -41,6 +42,18 @@ fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
4142 return false ;
4243 }
4344
45+ // - the final expression in the body of a function with a simple return type
46+ if let hir:: Node :: Block ( block) = parent
47+ && let mut parents = cx. tcx . hir_parent_iter ( block. hir_id ) . map ( |( _, def_id) | def_id)
48+ && let Some ( hir:: Node :: Expr ( _) ) = parents. next ( )
49+ && let Some ( hir:: Node :: Item ( enclosing_item) ) = parents. next ( )
50+ && let hir:: ItemKind :: Fn { sig, .. } = enclosing_item. kind
51+ && let hir:: FnRetTy :: Return ( fn_return_ty) = sig. decl . output
52+ && matches ! ( fn_return_ty. kind, hir:: TyKind :: Path ( ..) )
53+ {
54+ return false ;
55+ }
56+
4457 // if it's neither of those, stay on the safe side and suggest turbofish,
4558 // even if it could work!
4659 true
@@ -60,7 +73,7 @@ fn check_fold_with_op(
6073 fold_span : Span ,
6174 op : hir:: BinOpKind ,
6275 replacement : Replacement ,
63- ) {
76+ ) -> bool {
6477 if let hir:: ExprKind :: Closure ( & hir:: Closure { body, .. } ) = acc. kind
6578 // Extract the body of the closure passed to fold
6679 && let closure_body = cx. tcx . hir_body ( body)
@@ -93,7 +106,7 @@ fn check_fold_with_op(
93106 r = snippet_with_applicability( cx, right_expr. span, "EXPR" , & mut applicability) ,
94107 )
95108 } else {
96- format ! ( "{method}{turbofish}()" , method = replacement. method_name, )
109+ format ! ( "{method}{turbofish}()" , method = replacement. method_name)
97110 } ;
98111
99112 span_lint_and_sugg (
@@ -105,6 +118,41 @@ fn check_fold_with_op(
105118 sugg,
106119 applicability,
107120 ) ;
121+ return true ;
122+ }
123+ false
124+ }
125+
126+ fn check_fold_with_method (
127+ cx : & LateContext < ' _ > ,
128+ expr : & hir:: Expr < ' _ > ,
129+ acc : & hir:: Expr < ' _ > ,
130+ fold_span : Span ,
131+ method : Symbol ,
132+ replacement : Replacement ,
133+ ) {
134+ // Extract the name of the function passed to `fold`
135+ if let Res :: Def ( DefKind :: AssocFn , fn_did) = acc. res_if_named ( cx, method)
136+ // Check if the function belongs to the operator
137+ && cx. tcx . is_diagnostic_item ( method, fn_did)
138+ {
139+ let applicability = Applicability :: MachineApplicable ;
140+
141+ let turbofish = if replacement. has_generic_return {
142+ format ! ( "::<{}>" , cx. typeck_results( ) . expr_ty( expr) )
143+ } else {
144+ String :: new ( )
145+ } ;
146+
147+ span_lint_and_sugg (
148+ cx,
149+ UNNECESSARY_FOLD ,
150+ fold_span. with_hi ( expr. span . hi ( ) ) ,
151+ "this `.fold` can be written more succinctly using another method" ,
152+ "try" ,
153+ format ! ( "{method}{turbofish}()" , method = replacement. method_name) ,
154+ applicability,
155+ ) ;
108156 }
109157}
110158
@@ -124,60 +172,40 @@ pub(super) fn check(
124172 if let hir:: ExprKind :: Lit ( lit) = init. kind {
125173 match lit. node {
126174 ast:: LitKind :: Bool ( false ) => {
127- check_fold_with_op (
128- cx,
129- expr,
130- acc,
131- fold_span,
132- hir:: BinOpKind :: Or ,
133- Replacement {
134- method_name : "any" ,
135- has_args : true ,
136- has_generic_return : false ,
137- } ,
138- ) ;
175+ let replacement = Replacement {
176+ method_name : "any" ,
177+ has_args : true ,
178+ has_generic_return : false ,
179+ } ;
180+ check_fold_with_op ( cx, expr, acc, fold_span, hir:: BinOpKind :: Or , replacement) ;
139181 } ,
140182 ast:: LitKind :: Bool ( true ) => {
141- check_fold_with_op (
142- cx,
143- expr,
144- acc,
145- fold_span,
146- hir:: BinOpKind :: And ,
147- Replacement {
148- method_name : "all" ,
149- has_args : true ,
150- has_generic_return : false ,
151- } ,
152- ) ;
183+ let replacement = Replacement {
184+ method_name : "all" ,
185+ has_args : true ,
186+ has_generic_return : false ,
187+ } ;
188+ check_fold_with_op ( cx, expr, acc, fold_span, hir:: BinOpKind :: And , replacement) ;
153189 } ,
154190 ast:: LitKind :: Int ( Pu128 ( 0 ) , _) => {
155- check_fold_with_op (
156- cx,
157- expr,
158- acc,
159- fold_span,
160- hir:: BinOpKind :: Add ,
161- Replacement {
162- method_name : "sum" ,
163- has_args : false ,
164- has_generic_return : needs_turbofish ( cx, expr) ,
165- } ,
166- ) ;
191+ let replacement = Replacement {
192+ method_name : "sum" ,
193+ has_args : false ,
194+ has_generic_return : needs_turbofish ( cx, expr) ,
195+ } ;
196+ if !check_fold_with_op ( cx, expr, acc, fold_span, hir:: BinOpKind :: Add , replacement) {
197+ check_fold_with_method ( cx, expr, acc, fold_span, sym:: add, replacement) ;
198+ }
167199 } ,
168200 ast:: LitKind :: Int ( Pu128 ( 1 ) , _) => {
169- check_fold_with_op (
170- cx,
171- expr,
172- acc,
173- fold_span,
174- hir:: BinOpKind :: Mul ,
175- Replacement {
176- method_name : "product" ,
177- has_args : false ,
178- has_generic_return : needs_turbofish ( cx, expr) ,
179- } ,
180- ) ;
201+ let replacement = Replacement {
202+ method_name : "product" ,
203+ has_args : false ,
204+ has_generic_return : needs_turbofish ( cx, expr) ,
205+ } ;
206+ if !check_fold_with_op ( cx, expr, acc, fold_span, hir:: BinOpKind :: Mul , replacement) {
207+ check_fold_with_method ( cx, expr, acc, fold_span, sym:: mul, replacement) ;
208+ }
181209 } ,
182210 _ => ( ) ,
183211 }
0 commit comments