@@ -905,6 +905,85 @@ fn get_assignments<'a, 'tcx>(
905
905
iter_a. into_iter ( ) . flatten ( ) . chain ( iter_b. into_iter ( ) )
906
906
}
907
907
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
+ }
908
987
/// Checks for for loops that sequentially copy items from one slice-like
909
988
/// object to another.
910
989
fn detect_manual_memcpy < ' a , ' tcx > (
@@ -922,57 +1001,6 @@ fn detect_manual_memcpy<'a, 'tcx>(
922
1001
{
923
1002
// the var must be a single name
924
1003
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
-
976
1004
// The only statements in the for loops can be indexed assignments from
977
1005
// indexed retrievals.
978
1006
let big_sugg = get_assignments ( body)
@@ -998,29 +1026,7 @@ fn detect_manual_memcpy<'a, 'tcx>(
998
1026
}
999
1027
} )
1000
1028
} )
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) ) )
1024
1030
. collect :: < Option < Vec < _ > > > ( )
1025
1031
. filter ( |v| !v. is_empty ( ) )
1026
1032
. map ( |v| v. join ( "\n " ) ) ;
0 commit comments