@@ -818,13 +818,29 @@ impl Offset {
818
818
sign : OffsetSign :: Positive ,
819
819
}
820
820
}
821
+
822
+ fn empty ( ) -> Self {
823
+ Self :: positive ( "0" . into ( ) )
824
+ }
825
+ }
826
+
827
+ #[ derive( Debug , Clone , Copy ) ]
828
+ enum StartKind < ' hir > {
829
+ Range ,
830
+ Counter { initializer : & ' hir Expr < ' hir > } ,
821
831
}
822
832
823
833
struct IndexExpr < ' hir > {
824
834
base : & ' hir Expr < ' hir > ,
835
+ idx : StartKind < ' hir > ,
825
836
idx_offset : Offset ,
826
837
}
827
838
839
+ struct Start < ' hir > {
840
+ id : HirId ,
841
+ kind : StartKind < ' hir > ,
842
+ }
843
+
828
844
fn is_slice_like < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' _ > ) -> bool {
829
845
let is_slice = match ty. kind ( ) {
830
846
ty:: Ref ( _, subty, _) => is_slice_like ( cx, subty) ,
@@ -845,35 +861,54 @@ fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
845
861
}
846
862
}
847
863
848
- fn get_offset < ' tcx > ( cx : & LateContext < ' tcx > , idx : & Expr < ' _ > , start : HirId ) -> Option < Offset > {
849
- fn extract_offset < ' tcx > ( cx : & LateContext < ' tcx > , e : & Expr < ' _ > , start : HirId ) -> Option < String > {
864
+ fn get_offset < ' tcx > (
865
+ cx : & LateContext < ' tcx > ,
866
+ idx : & Expr < ' _ > ,
867
+ starts : & [ Start < ' tcx > ] ,
868
+ ) -> Option < ( StartKind < ' tcx > , Offset ) > {
869
+ fn extract_start < ' tcx > (
870
+ cx : & LateContext < ' tcx > ,
871
+ expr : & Expr < ' _ > ,
872
+ starts : & [ Start < ' tcx > ] ,
873
+ ) -> Option < StartKind < ' tcx > > {
874
+ starts. iter ( ) . find ( |var| same_var ( cx, expr, var. id ) ) . map ( |v| v. kind )
875
+ }
876
+
877
+ fn extract_offset < ' tcx > (
878
+ cx : & LateContext < ' tcx > ,
879
+ e : & Expr < ' _ > ,
880
+ starts : & [ Start < ' tcx > ] ,
881
+ ) -> Option < String > {
850
882
match & e. kind {
851
883
ExprKind :: Lit ( l) => match l. node {
852
884
ast:: LitKind :: Int ( x, _ty) => Some ( x. to_string ( ) ) ,
853
885
_ => None ,
854
886
} ,
855
- ExprKind :: Path ( ..) if !same_var ( cx, e, start) => Some ( snippet_opt ( cx, e. span ) . unwrap_or_else ( || "??" . into ( ) ) ) ,
887
+ ExprKind :: Path ( ..) if extract_start ( cx, e, starts) . is_none ( ) => {
888
+ Some ( snippet_opt ( cx, e. span ) . unwrap_or_else ( || "??" . into ( ) ) )
889
+ } ,
856
890
_ => None ,
857
891
}
858
892
}
859
893
860
894
match idx. kind {
861
895
ExprKind :: Binary ( op, lhs, rhs) => match op. node {
862
896
BinOpKind :: Add => {
863
- let offset_opt = if same_var ( cx, lhs, start ) {
864
- extract_offset ( cx, rhs, start )
865
- } else if same_var ( cx, rhs, start ) {
866
- extract_offset ( cx, lhs, start )
897
+ let offset_opt = if let Some ( s ) = extract_start ( cx, lhs, starts ) {
898
+ extract_offset ( cx, rhs, starts ) . map ( |o| ( s , o ) )
899
+ } else if let Some ( s ) = extract_start ( cx, rhs, starts ) {
900
+ extract_offset ( cx, lhs, starts ) . map ( |o| ( s , o ) )
867
901
} else {
868
902
None
869
903
} ;
870
904
871
- offset_opt. map ( Offset :: positive)
905
+ offset_opt. map ( | ( s , o ) | ( s , Offset :: positive ( o ) ) )
872
906
} ,
873
- BinOpKind :: Sub if same_var ( cx, lhs, start) => extract_offset ( cx, rhs, start) . map ( Offset :: negative) ,
907
+ BinOpKind :: Sub => extract_start ( cx, lhs, starts)
908
+ . and_then ( |s| extract_offset ( cx, rhs, starts) . map ( |o| ( s, Offset :: negative ( o) ) ) ) ,
874
909
_ => None ,
875
910
} ,
876
- ExprKind :: Path ( ..) if same_var ( cx, idx, start ) => Some ( Offset :: positive ( "0" . into ( ) ) ) ,
911
+ ExprKind :: Path ( ..) => extract_start ( cx, idx, starts ) . map ( |s| ( s , Offset :: empty ( ) ) ) ,
877
912
_ => None ,
878
913
}
879
914
}
@@ -1008,6 +1043,10 @@ fn detect_manual_memcpy<'tcx>(
1008
1043
{
1009
1044
// the var must be a single name
1010
1045
if let PatKind :: Binding ( _, canonical_id, _, _) = pat. kind {
1046
+ let mut starts = vec ! [ Start {
1047
+ id: canonical_id,
1048
+ kind: StartKind :: Range ,
1049
+ } ] ;
1011
1050
// The only statements in the for loops can be indexed assignments from
1012
1051
// indexed retrievals.
1013
1052
let big_sugg = get_assignments ( body)
@@ -1019,14 +1058,14 @@ fn detect_manual_memcpy<'tcx>(
1019
1058
if let ExprKind :: Index ( base_right, idx_right) = rhs. kind;
1020
1059
if is_slice_like( cx, cx. typeck_results( ) . expr_ty( base_left) )
1021
1060
&& is_slice_like( cx, cx. typeck_results( ) . expr_ty( base_right) ) ;
1022
- if let Some ( offset_left) = get_offset( cx, & idx_left, canonical_id ) ;
1023
- if let Some ( offset_right) = get_offset( cx, & idx_right, canonical_id ) ;
1061
+ if let Some ( ( start_left , offset_left) ) = get_offset( cx, & idx_left, & starts ) ;
1062
+ if let Some ( ( start_right , offset_right) ) = get_offset( cx, & idx_right, & starts ) ;
1024
1063
1025
1064
// Source and destination must be different
1026
1065
if var_def_id( cx, base_left) != var_def_id( cx, base_right) ;
1027
1066
then {
1028
- Some ( ( IndexExpr { base: base_left, idx_offset: offset_left } ,
1029
- IndexExpr { base: base_right, idx_offset: offset_right } ) )
1067
+ Some ( ( IndexExpr { base: base_left, idx : start_left , idx_offset: offset_left } ,
1068
+ IndexExpr { base: base_right, idx : start_right , idx_offset: offset_right } ) )
1030
1069
} else {
1031
1070
None
1032
1071
}
0 commit comments