1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
- use clippy_utils:: ptr:: get_spans;
3
2
use clippy_utils:: source:: { SpanRangeExt , snippet} ;
4
3
use clippy_utils:: ty:: {
5
4
implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
6
5
} ;
7
- use clippy_utils:: { is_self, peel_hir_ty_options} ;
6
+ use clippy_utils:: visitors:: { Descend , for_each_expr_without_closures} ;
7
+ use clippy_utils:: { is_self, path_to_local_id, peel_hir_ty_options, strip_pat_refs, sym} ;
8
8
use rustc_abi:: ExternAbi ;
9
9
use rustc_errors:: { Applicability , Diag } ;
10
10
use rustc_hir:: intravisit:: FnKind ;
11
11
use rustc_hir:: {
12
- Attribute , BindingMode , Body , FnDecl , GenericArg , HirId , HirIdSet , Impl , ItemKind , LangItem , Mutability , Node ,
13
- PatKind , QPath , TyKind ,
12
+ Attribute , BindingMode , Body , ExprKind , FnDecl , GenericArg , HirId , HirIdSet , Impl , ItemKind , LangItem , Mutability ,
13
+ Node , PatKind , QPath , TyKind ,
14
14
} ;
15
15
use rustc_hir_typeck:: expr_use_visitor as euv;
16
16
use rustc_lint:: { LateContext , LateLintPass } ;
@@ -19,10 +19,13 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
19
19
use rustc_session:: declare_lint_pass;
20
20
use rustc_span:: def_id:: LocalDefId ;
21
21
use rustc_span:: symbol:: kw;
22
- use rustc_span:: { Span , sym } ;
22
+ use rustc_span:: { Span , Symbol } ;
23
23
use rustc_trait_selection:: traits;
24
24
use rustc_trait_selection:: traits:: misc:: type_allowed_to_implement_copy;
25
25
26
+ use std:: borrow:: Cow ;
27
+ use std:: ops:: ControlFlow ;
28
+
26
29
declare_clippy_lint ! {
27
30
/// ### What it does
28
31
/// Checks for functions taking arguments by value, but not
@@ -217,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
217
220
}
218
221
219
222
if is_type_diagnostic_item ( cx, ty, sym:: Vec )
220
- && let Some ( clone_spans) = get_spans ( cx, Some ( body. id ( ) ) , idx, & [ ( sym:: clone, ".to_owned()" ) ] )
223
+ && let Some ( clone_spans) = get_spans ( cx, body, idx, & [ ( sym:: clone, ".to_owned()" ) ] )
221
224
&& let TyKind :: Path ( QPath :: Resolved ( _, path) ) = input. kind
222
225
&& let Some ( elem_ty) = path
223
226
. segments
@@ -260,12 +263,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
260
263
}
261
264
262
265
if is_type_lang_item ( cx, ty, LangItem :: String )
263
- && let Some ( clone_spans) = get_spans (
264
- cx,
265
- Some ( body. id ( ) ) ,
266
- idx,
267
- & [ ( sym:: clone, ".to_string()" ) , ( sym:: as_str, "" ) ] ,
268
- )
266
+ && let Some ( clone_spans) =
267
+ get_spans ( cx, body, idx, & [ ( sym:: clone, ".to_string()" ) , ( sym:: as_str, "" ) ] )
269
268
{
270
269
diag. span_suggestion (
271
270
input. span ,
@@ -340,3 +339,43 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
340
339
341
340
fn fake_read ( & mut self , _: & rustc_hir_typeck:: expr_use_visitor:: PlaceWithHirId < ' tcx > , _: FakeReadCause , _: HirId ) { }
342
341
}
342
+
343
+ fn get_spans < ' tcx > (
344
+ cx : & LateContext < ' tcx > ,
345
+ body : & ' tcx Body < ' _ > ,
346
+ idx : usize ,
347
+ replacements : & [ ( Symbol , & ' static str ) ] ,
348
+ ) -> Option < Vec < ( Span , Cow < ' static , str > ) > > {
349
+ if let PatKind :: Binding ( _, binding_id, _, _) = strip_pat_refs ( body. params [ idx] . pat ) . kind {
350
+ extract_clone_suggestions ( cx, binding_id, replacements, body)
351
+ } else {
352
+ Some ( vec ! [ ] )
353
+ }
354
+ }
355
+
356
+ fn extract_clone_suggestions < ' tcx > (
357
+ cx : & LateContext < ' tcx > ,
358
+ id : HirId ,
359
+ replace : & [ ( Symbol , & ' static str ) ] ,
360
+ body : & ' tcx Body < ' _ > ,
361
+ ) -> Option < Vec < ( Span , Cow < ' static , str > ) > > {
362
+ let mut spans = Vec :: new ( ) ;
363
+ for_each_expr_without_closures ( body, |e| {
364
+ if let ExprKind :: MethodCall ( seg, recv, [ ] , _) = e. kind
365
+ && path_to_local_id ( recv, id)
366
+ {
367
+ if seg. ident . name == sym:: capacity {
368
+ return ControlFlow :: Break ( ( ) ) ;
369
+ }
370
+ for & ( fn_name, suffix) in replace {
371
+ if seg. ident . name == fn_name {
372
+ spans. push ( ( e. span , snippet ( cx, recv. span , "_" ) + suffix) ) ;
373
+ return ControlFlow :: Continue ( Descend :: No ) ;
374
+ }
375
+ }
376
+ }
377
+ ControlFlow :: Continue ( Descend :: Yes )
378
+ } )
379
+ . is_none ( )
380
+ . then_some ( spans)
381
+ }
0 commit comments