@@ -10,7 +10,6 @@ use crate::utils::{
10
10
} ;
11
11
use crate :: utils:: { is_type_diagnostic_item, qpath_res, same_tys, sext, sugg} ;
12
12
use if_chain:: if_chain;
13
- use itertools:: Itertools ;
14
13
use rustc_ast:: ast;
15
14
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
16
15
use rustc_errors:: Applicability ;
@@ -885,52 +884,39 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, v
885
884
}
886
885
}
887
886
888
- fn get_indexed_assignments < ' a , ' tcx > (
889
- cx : & LateContext < ' a , ' tcx > ,
890
- body : & Expr < ' _ > ,
891
- var : HirId ,
892
- ) -> Vec < ( FixedOffsetVar , FixedOffsetVar ) > {
893
- fn get_assignment < ' a , ' tcx > (
894
- cx : & LateContext < ' a , ' tcx > ,
895
- e : & Expr < ' _ > ,
896
- var : HirId ,
897
- ) -> Option < ( FixedOffsetVar , FixedOffsetVar ) > {
887
+ fn get_assignments < ' a , ' tcx > (
888
+ body : & ' tcx Expr < ' tcx > ,
889
+ ) -> impl Iterator < Item = Option < ( & ' tcx Expr < ' tcx > , & ' tcx Expr < ' tcx > ) > > {
890
+ fn get_assignment < ' a , ' tcx > ( e : & ' tcx Expr < ' tcx > ) -> Option < ( & ' tcx Expr < ' tcx > , & ' tcx Expr < ' tcx > ) > {
898
891
if let ExprKind :: Assign ( lhs, rhs, _) = e. kind {
899
- match (
900
- get_fixed_offset_var ( cx, lhs, var) ,
901
- get_fixed_offset_var ( cx, fetch_cloned_expr ( rhs) , var) ,
902
- ) {
903
- ( Some ( offset_left) , Some ( offset_right) ) => {
904
- // Source and destination must be different
905
- if offset_left. var_name == offset_right. var_name {
906
- None
907
- } else {
908
- Some ( ( offset_left, offset_right) )
909
- }
910
- } ,
911
- _ => None ,
912
- }
892
+ Some ( ( lhs, rhs) )
913
893
} else {
914
894
None
915
895
}
916
896
}
917
897
898
+ // This is one of few ways to return different iterators
899
+ // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434
900
+ let mut iter_a = None ;
901
+ let mut iter_b = None ;
902
+
918
903
if let ExprKind :: Block ( b, _) = body. kind {
919
904
let Block { stmts, expr, .. } = * b;
920
905
921
- stmts
906
+ iter_a = stmts
922
907
. iter ( )
923
908
. filter_map ( |stmt| match stmt. kind {
924
909
StmtKind :: Local ( ..) | StmtKind :: Item ( ..) => None ,
925
910
StmtKind :: Expr ( e) | StmtKind :: Semi ( e) => Some ( e) ,
926
911
} )
927
912
. chain ( expr. into_iter ( ) )
928
- . map ( |op| get_assignment ( cx, op, var) )
929
- . collect :: < Option < Vec < _ > > > ( )
930
- . unwrap_or_default ( )
913
+ . map ( get_assignment)
914
+ . into ( )
931
915
} else {
932
- get_assignment ( cx , body , var ) . into_iter ( ) . collect ( )
916
+ iter_b = Some ( get_assignment ( body ) )
933
917
}
918
+
919
+ iter_a. into_iter ( ) . flatten ( ) . chain ( iter_b. into_iter ( ) )
934
920
}
935
921
936
922
/// Checks for for loops that sequentially copy items from one slice-like
@@ -1003,30 +989,48 @@ fn detect_manual_memcpy<'a, 'tcx>(
1003
989
1004
990
// The only statements in the for loops can be indexed assignments from
1005
991
// indexed retrievals.
1006
- let manual_copies = get_indexed_assignments ( cx, body, canonical_id) ;
1007
-
1008
- let big_sugg = manual_copies
1009
- . into_iter ( )
1010
- . map ( |( dst_var, src_var) | {
1011
- let start_str = snippet ( cx, start. span , "" ) . to_string ( ) ;
1012
- let dst_offset = print_offset ( & start_str, & dst_var. offset ) ;
1013
- let dst_limit = print_limit ( end, dst_var. offset , & dst_var. var_name ) ;
1014
- let src_offset = print_offset ( & start_str, & src_var. offset ) ;
1015
- let src_limit = print_limit ( end, src_var. offset , & src_var. var_name ) ;
1016
- let dst = if dst_offset == "" && dst_limit == "" {
1017
- dst_var. var_name
1018
- } else {
1019
- format ! ( "{}[{}..{}]" , dst_var. var_name, dst_offset, dst_limit)
1020
- } ;
992
+ let big_sugg = get_assignments ( body)
993
+ . map ( |o| {
994
+ o. and_then ( |( lhs, rhs) | {
995
+ let rhs = fetch_cloned_expr ( rhs) ;
996
+ if_chain ! {
997
+ if let Some ( offset_left) = get_fixed_offset_var( cx, lhs, canonical_id) ;
998
+ if let Some ( offset_right) = get_fixed_offset_var( cx, rhs, canonical_id) ;
999
+
1000
+ // Source and destination must be different
1001
+ if offset_left. var_name != offset_right. var_name;
1002
+ then {
1003
+ Some ( ( offset_left, offset_right) )
1004
+ } else {
1005
+ return None
1006
+ }
1007
+ }
1008
+ } )
1009
+ } )
1010
+ . map ( |o| {
1011
+ o. map ( |( dst_var, src_var) | {
1012
+ let start_str = snippet ( cx, start. span , "" ) . to_string ( ) ;
1013
+ let dst_offset = print_offset ( & start_str, & dst_var. offset ) ;
1014
+ let dst_limit = print_limit ( end, dst_var. offset , & dst_var. var_name ) ;
1015
+ let src_offset = print_offset ( & start_str, & src_var. offset ) ;
1016
+ let src_limit = print_limit ( end, src_var. offset , & src_var. var_name ) ;
1017
+ let dst = if dst_offset == "" && dst_limit == "" {
1018
+ dst_var. var_name
1019
+ } else {
1020
+ format ! ( "{}[{}..{}]" , dst_var. var_name, dst_offset, dst_limit)
1021
+ } ;
1021
1022
1022
- format ! (
1023
- "{}.clone_from_slice(&{}[{}..{}])" ,
1024
- dst, src_var. var_name, src_offset, src_limit
1025
- )
1023
+ format ! (
1024
+ "{}.clone_from_slice(&{}[{}..{}])" ,
1025
+ dst, src_var. var_name, src_offset, src_limit
1026
+ )
1027
+ } )
1026
1028
} )
1027
- . join ( "\n " ) ;
1029
+ . collect :: < Option < Vec < _ > > > ( )
1030
+ . filter ( |v| !v. is_empty ( ) )
1031
+ . map ( |v| v. join ( "\n " ) ) ;
1028
1032
1029
- if !big_sugg . is_empty ( ) {
1033
+ if let Some ( big_sugg ) = big_sugg {
1030
1034
span_lint_and_sugg (
1031
1035
cx,
1032
1036
MANUAL_MEMCPY ,
0 commit comments