11use clippy_utils:: diagnostics:: span_lint_and_then;
2- use clippy_utils:: ptr:: get_spans;
32use clippy_utils:: source:: { SpanRangeExt , snippet} ;
43use clippy_utils:: ty:: {
54 implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
65} ;
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} ;
88use rustc_abi:: ExternAbi ;
99use rustc_errors:: { Applicability , Diag } ;
1010use rustc_hir:: intravisit:: FnKind ;
1111use 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 ,
1414} ;
1515use rustc_hir_typeck:: expr_use_visitor as euv;
1616use rustc_lint:: { LateContext , LateLintPass } ;
@@ -19,10 +19,13 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
1919use rustc_session:: declare_lint_pass;
2020use rustc_span:: def_id:: LocalDefId ;
2121use rustc_span:: symbol:: kw;
22- use rustc_span:: { Span , sym } ;
22+ use rustc_span:: { Span , Symbol } ;
2323use rustc_trait_selection:: traits;
2424use rustc_trait_selection:: traits:: misc:: type_allowed_to_implement_copy;
2525
26+ use std:: borrow:: Cow ;
27+ use std:: ops:: ControlFlow ;
28+
2629declare_clippy_lint ! {
2730 /// ### What it does
2831 /// Checks for functions taking arguments by value, but not
@@ -217,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
217220 }
218221
219222 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()" ) ] )
221224 && let TyKind :: Path ( QPath :: Resolved ( _, path) ) = input. kind
222225 && let Some ( elem_ty) = path
223226 . segments
@@ -260,12 +263,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
260263 }
261264
262265 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, "" ) ] )
269268 {
270269 diag. span_suggestion (
271270 input. span ,
@@ -340,3 +339,43 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
340339
341340 fn fake_read ( & mut self , _: & rustc_hir_typeck:: expr_use_visitor:: PlaceWithHirId < ' tcx > , _: FakeReadCause , _: HirId ) { }
342341}
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