@@ -905,6 +905,85 @@ fn get_assignments<'a, 'tcx>(
905905 iter_a. into_iter ( ) . flatten ( ) . chain ( iter_b. into_iter ( ) )
906906}
907907
908+ fn build_manual_memcpy_suggestion < ' a , ' tcx > (
909+ cx : & LateContext < ' a , ' tcx > ,
910+ start : & Expr < ' _ > ,
911+ end : & Expr < ' _ > ,
912+ limits : ast:: RangeLimits ,
913+ dst_var : FixedOffsetVar < ' _ > ,
914+ src_var : FixedOffsetVar < ' _ > ,
915+ ) -> String {
916+ fn print_sum ( arg1 : & str , arg2 : & Offset ) -> String {
917+ match ( arg1, & arg2. value [ ..] , arg2. sign ) {
918+ ( "0" , "0" , _) => "0" . into ( ) ,
919+ ( "0" , x, OffsetSign :: Positive ) | ( x, "0" , _) => x. into ( ) ,
920+ ( "0" , x, OffsetSign :: Negative ) => format ! ( "-{}" , x) ,
921+ ( x, y, OffsetSign :: Positive ) => format ! ( "({} + {})" , x, y) ,
922+ ( x, y, OffsetSign :: Negative ) => {
923+ if x == y {
924+ "0" . into ( )
925+ } else {
926+ format ! ( "({} - {})" , x, y)
927+ }
928+ } ,
929+ }
930+ }
931+
932+ fn print_offset ( start_str : & str , inline_offset : & Offset ) -> String {
933+ let offset = print_sum ( start_str, inline_offset) ;
934+ if offset. as_str ( ) == "0" {
935+ "" . into ( )
936+ } else {
937+ offset
938+ }
939+ }
940+
941+ let print_limit = |end : & Expr < ' _ > , offset : Offset , var : & Expr < ' _ > | {
942+ if_chain ! {
943+ if let ExprKind :: MethodCall ( method, _, len_args) = end. kind;
944+ if method. ident. name == sym!( len) ;
945+ if len_args. len( ) == 1 ;
946+ if let Some ( arg) = len_args. get( 0 ) ;
947+ if var_def_id( cx, arg) == var_def_id( cx, var) ;
948+ then {
949+ match offset. sign {
950+ OffsetSign :: Negative => format!( "({} - {})" , snippet( cx, end. span, "<src>.len()" ) , offset. value) ,
951+ OffsetSign :: Positive => "" . into( ) ,
952+ }
953+ } else {
954+ let end_str = match limits {
955+ ast:: RangeLimits :: Closed => {
956+ let end = sugg:: Sugg :: hir( cx, end, "<count>" ) ;
957+ format!( "{}" , end + sugg:: ONE )
958+ } ,
959+ ast:: RangeLimits :: HalfOpen => format!( "{}" , snippet( cx, end. span, ".." ) ) ,
960+ } ;
961+
962+ print_sum( & end_str, & offset)
963+ }
964+ }
965+ } ;
966+
967+ let start_str = snippet ( cx, start. span , "" ) . to_string ( ) ;
968+ let dst_offset = print_offset ( & start_str, & dst_var. offset ) ;
969+ let dst_limit = print_limit ( end, dst_var. offset , dst_var. var ) ;
970+ let src_offset = print_offset ( & start_str, & src_var. offset ) ;
971+ let src_limit = print_limit ( end, src_var. offset , src_var. var ) ;
972+
973+ let dst_var_name = snippet_opt ( cx, dst_var. var . span ) . unwrap_or_else ( || "???" . into ( ) ) ;
974+ let src_var_name = snippet_opt ( cx, src_var. var . span ) . unwrap_or_else ( || "???" . into ( ) ) ;
975+
976+ let dst = if dst_offset == "" && dst_limit == "" {
977+ dst_var_name
978+ } else {
979+ format ! ( "{}[{}..{}]" , dst_var_name, dst_offset, dst_limit)
980+ } ;
981+
982+ format ! (
983+ "{}.clone_from_slice(&{}[{}..{}])" ,
984+ dst, src_var_name, src_offset, src_limit
985+ )
986+ }
908987/// Checks for for loops that sequentially copy items from one slice-like
909988/// object to another.
910989fn detect_manual_memcpy < ' a , ' tcx > (
@@ -922,57 +1001,6 @@ fn detect_manual_memcpy<'a, 'tcx>(
9221001 {
9231002 // the var must be a single name
9241003 if let PatKind :: Binding ( _, canonical_id, _, _) = pat. kind {
925- fn print_sum ( arg1 : & str , arg2 : & Offset ) -> String {
926- match ( arg1, & arg2. value [ ..] , arg2. sign ) {
927- ( "0" , "0" , _) => "0" . into ( ) ,
928- ( "0" , x, OffsetSign :: Positive ) | ( x, "0" , _) => x. into ( ) ,
929- ( "0" , x, OffsetSign :: Negative ) => format ! ( "-{}" , x) ,
930- ( x, y, OffsetSign :: Positive ) => format ! ( "({} + {})" , x, y) ,
931- ( x, y, OffsetSign :: Negative ) => {
932- if x == y {
933- "0" . into ( )
934- } else {
935- format ! ( "({} - {})" , x, y)
936- }
937- } ,
938- }
939- }
940-
941- fn print_offset ( start_str : & str , inline_offset : & Offset ) -> String {
942- let offset = print_sum ( start_str, inline_offset) ;
943- if offset. as_str ( ) == "0" {
944- "" . into ( )
945- } else {
946- offset
947- }
948- }
949-
950- let print_limit = |end : & Expr < ' _ > , offset : Offset , var : & Expr < ' _ > | {
951- if_chain ! {
952- if let ExprKind :: MethodCall ( method, _, len_args) = end. kind;
953- if method. ident. name == sym!( len) ;
954- if len_args. len( ) == 1 ;
955- if let Some ( arg) = len_args. get( 0 ) ;
956- if var_def_id( cx, arg) == var_def_id( cx, var) ;
957- then {
958- match offset. sign {
959- OffsetSign :: Negative => format!( "({} - {})" , snippet( cx, end. span, "<src>.len()" ) , offset. value) ,
960- OffsetSign :: Positive => "" . into( ) ,
961- }
962- } else {
963- let end_str = match limits {
964- ast:: RangeLimits :: Closed => {
965- let end = sugg:: Sugg :: hir( cx, end, "<count>" ) ;
966- format!( "{}" , end + sugg:: ONE )
967- } ,
968- ast:: RangeLimits :: HalfOpen => format!( "{}" , snippet( cx, end. span, ".." ) ) ,
969- } ;
970-
971- print_sum( & end_str, & offset)
972- }
973- }
974- } ;
975-
9761004 // The only statements in the for loops can be indexed assignments from
9771005 // indexed retrievals.
9781006 let big_sugg = get_assignments ( body)
@@ -998,29 +1026,7 @@ fn detect_manual_memcpy<'a, 'tcx>(
9981026 }
9991027 } )
10001028 } )
1001- . map ( |o| {
1002- o. map ( |( dst_var, src_var) | {
1003- let start_str = snippet ( cx, start. span , "" ) . to_string ( ) ;
1004- let dst_offset = print_offset ( & start_str, & dst_var. offset ) ;
1005- let dst_limit = print_limit ( end, dst_var. offset , dst_var. var ) ;
1006- let src_offset = print_offset ( & start_str, & src_var. offset ) ;
1007- let src_limit = print_limit ( end, src_var. offset , src_var. var ) ;
1008-
1009- let dst_var_name = snippet_opt ( cx, dst_var. var . span ) . unwrap_or_else ( || "???" . into ( ) ) ;
1010- let src_var_name = snippet_opt ( cx, src_var. var . span ) . unwrap_or_else ( || "???" . into ( ) ) ;
1011-
1012- let dst = if dst_offset == "" && dst_limit == "" {
1013- dst_var_name
1014- } else {
1015- format ! ( "{}[{}..{}]" , dst_var_name, dst_offset, dst_limit)
1016- } ;
1017-
1018- format ! (
1019- "{}.clone_from_slice(&{}[{}..{}])" ,
1020- dst, src_var_name, src_offset, src_limit
1021- )
1022- } )
1023- } )
1029+ . map ( |o| o. map ( |( dst, src) | build_manual_memcpy_suggestion ( cx, start, end, limits, dst, src) ) )
10241030 . collect :: < Option < Vec < _ > > > ( )
10251031 . filter ( |v| !v. is_empty ( ) )
10261032 . map ( |v| v. join ( "\n " ) ) ;
0 commit comments