Skip to content

Commit 582614f

Browse files
committed
Extract building the suggestion of manual_memcpy
1 parent 9fc6f37 commit 582614f

File tree

1 file changed

+80
-74
lines changed

1 file changed

+80
-74
lines changed

clippy_lints/src/loops.rs

Lines changed: 80 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
910989
fn 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

Comments
 (0)