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 , BodyId , ExprKind , FnDecl , GenericArg , HirId , HirIdSet , Impl , ItemKind , LangItem ,
13
+ Mutability , 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
@@ -340,3 +343,47 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
340
343
341
344
fn fake_read ( & mut self , _: & rustc_hir_typeck:: expr_use_visitor:: PlaceWithHirId < ' tcx > , _: FakeReadCause , _: HirId ) { }
342
345
}
346
+
347
+ pub fn get_spans (
348
+ cx : & LateContext < ' _ > ,
349
+ opt_body_id : Option < BodyId > ,
350
+ idx : usize ,
351
+ replacements : & [ ( Symbol , & ' static str ) ] ,
352
+ ) -> Option < Vec < ( Span , Cow < ' static , str > ) > > {
353
+ if let Some ( body) = opt_body_id. map ( |id| cx. tcx . hir_body ( id) ) {
354
+ if let PatKind :: Binding ( _, binding_id, _, _) = strip_pat_refs ( body. params [ idx] . pat ) . kind {
355
+ extract_clone_suggestions ( cx, binding_id, replacements, body)
356
+ } else {
357
+ Some ( vec ! [ ] )
358
+ }
359
+ } else {
360
+ Some ( vec ! [ ] )
361
+ }
362
+ }
363
+
364
+ fn extract_clone_suggestions < ' tcx > (
365
+ cx : & LateContext < ' tcx > ,
366
+ id : HirId ,
367
+ replace : & [ ( Symbol , & ' static str ) ] ,
368
+ body : & ' tcx Body < ' _ > ,
369
+ ) -> Option < Vec < ( Span , Cow < ' static , str > ) > > {
370
+ let mut spans = Vec :: new ( ) ;
371
+ for_each_expr_without_closures ( body, |e| {
372
+ if let ExprKind :: MethodCall ( seg, recv, [ ] , _) = e. kind
373
+ && path_to_local_id ( recv, id)
374
+ {
375
+ if seg. ident . name == sym:: capacity {
376
+ return ControlFlow :: Break ( ( ) ) ;
377
+ }
378
+ for & ( fn_name, suffix) in replace {
379
+ if seg. ident . name == fn_name {
380
+ spans. push ( ( e. span , snippet ( cx, recv. span , "_" ) + suffix) ) ;
381
+ return ControlFlow :: Continue ( Descend :: No ) ;
382
+ }
383
+ }
384
+ }
385
+ ControlFlow :: Continue ( Descend :: Yes )
386
+ } )
387
+ . is_none ( )
388
+ . then_some ( spans)
389
+ }
0 commit comments