Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 3d121d5

Browse files
committed
Extract roles getting indexes from get_indexed_assignments
1 parent aab80ee commit 3d121d5

File tree

1 file changed

+55
-51
lines changed

1 file changed

+55
-51
lines changed

clippy_lints/src/loops.rs

Lines changed: 55 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::utils::{
1010
};
1111
use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg};
1212
use if_chain::if_chain;
13-
use itertools::Itertools;
1413
use rustc_ast::ast;
1514
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1615
use rustc_errors::Applicability;
@@ -885,52 +884,39 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, v
885884
}
886885
}
887886

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>)> {
898891
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))
913893
} else {
914894
None
915895
}
916896
}
917897

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+
918903
if let ExprKind::Block(b, _) = body.kind {
919904
let Block { stmts, expr, .. } = *b;
920905

921-
stmts
906+
iter_a = stmts
922907
.iter()
923908
.filter_map(|stmt| match stmt.kind {
924909
StmtKind::Local(..) | StmtKind::Item(..) => None,
925910
StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e),
926911
})
927912
.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()
931915
} else {
932-
get_assignment(cx, body, var).into_iter().collect()
916+
iter_b = Some(get_assignment(body))
933917
}
918+
919+
iter_a.into_iter().flatten().chain(iter_b.into_iter())
934920
}
935921

936922
/// Checks for for loops that sequentially copy items from one slice-like
@@ -1003,30 +989,48 @@ fn detect_manual_memcpy<'a, 'tcx>(
1003989

1004990
// The only statements in the for loops can be indexed assignments from
1005991
// 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+
};
10211022

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+
})
10261028
})
1027-
.join("\n ");
1029+
.collect::<Option<Vec<_>>>()
1030+
.filter(|v| !v.is_empty())
1031+
.map(|v| v.join("\n "));
10281032

1029-
if !big_sugg.is_empty() {
1033+
if let Some(big_sugg) = big_sugg {
10301034
span_lint_and_sugg(
10311035
cx,
10321036
MANUAL_MEMCPY,

0 commit comments

Comments
 (0)