Skip to content

Commit b4b4da1

Browse files
committed
Introduce Start and StartKind
1 parent 1026b42 commit b4b4da1

File tree

1 file changed

+53
-14
lines changed

1 file changed

+53
-14
lines changed

clippy_lints/src/loops.rs

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -818,13 +818,29 @@ impl Offset {
818818
sign: OffsetSign::Positive,
819819
}
820820
}
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> },
821831
}
822832

823833
struct IndexExpr<'hir> {
824834
base: &'hir Expr<'hir>,
835+
idx: StartKind<'hir>,
825836
idx_offset: Offset,
826837
}
827838

839+
struct Start<'hir> {
840+
id: HirId,
841+
kind: StartKind<'hir>,
842+
}
843+
828844
fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool {
829845
let is_slice = match ty.kind() {
830846
ty::Ref(_, subty, _) => is_slice_like(cx, subty),
@@ -845,35 +861,54 @@ fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
845861
}
846862
}
847863

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> {
850882
match &e.kind {
851883
ExprKind::Lit(l) => match l.node {
852884
ast::LitKind::Int(x, _ty) => Some(x.to_string()),
853885
_ => None,
854886
},
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+
},
856890
_ => None,
857891
}
858892
}
859893

860894
match idx.kind {
861895
ExprKind::Binary(op, lhs, rhs) => match op.node {
862896
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))
867901
} else {
868902
None
869903
};
870904

871-
offset_opt.map(Offset::positive)
905+
offset_opt.map(|(s, o)| (s, Offset::positive(o)))
872906
},
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)))),
874909
_ => None,
875910
},
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())),
877912
_ => None,
878913
}
879914
}
@@ -1008,6 +1043,10 @@ fn detect_manual_memcpy<'tcx>(
10081043
{
10091044
// the var must be a single name
10101045
if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
1046+
let mut starts = vec![Start {
1047+
id: canonical_id,
1048+
kind: StartKind::Range,
1049+
}];
10111050
// The only statements in the for loops can be indexed assignments from
10121051
// indexed retrievals.
10131052
let big_sugg = get_assignments(body)
@@ -1019,14 +1058,14 @@ fn detect_manual_memcpy<'tcx>(
10191058
if let ExprKind::Index(base_right, idx_right) = rhs.kind;
10201059
if is_slice_like(cx, cx.typeck_results().expr_ty(base_left))
10211060
&& 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);
10241063

10251064
// Source and destination must be different
10261065
if var_def_id(cx, base_left) != var_def_id(cx, base_right);
10271066
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 }))
10301069
} else {
10311070
None
10321071
}

0 commit comments

Comments
 (0)