id: for-range-len
language: rust
severity: warning
rule:
any:
- pattern: |
for $I in 0..$V.len() {
$$$
}
- pattern: |
for $I in 0..=$V.len() {
$$$
}
- pattern: |
for $I in $START..$V.len() {
$$$
}
- pattern: |
for $I in $START..=$V.len() {
$$$
}
- pattern: |
for $I in 0..$V.len() - $N {
$$$
}
- pattern: |
for $I in 0..=$V.len() - $N {
$$$
}
ignores:
- "crates/**/tests/**"
- "crates/**/benches/**"
- "benches/**"
- "tests/**"
- "examples/**"
- "tracehealth-api/tests/**"
- "tracehealth-api/benches/**"
- "vendor/**"
- ".claude/worktrees/**"
- "target/**"
- "tracehealth-ios/**"
message: |
Index-based iteration — use an iterator instead of a `..v.len()` range.
note: |
Replace:
for i in 0..v.len() { ... v[i] ... }
with one of:
for x in &v { ... } — when you don't need the index
for (i, x) in v.iter().enumerate() { ... }
for x in v.iter_mut() { ... } — when you need to mutate
for w in v.windows(2) { ... w[0], w[1] ... } — for `0..v.len() - 1`
for w in v.chunks(n) { ... } — for chunked passes
When the range starts at a non-zero offset:
for x in &v[start..] { ... } — slice + iterate
for (i, x) in v.iter().enumerate().skip(start) { ... }
Index iteration sidesteps bounds-check elision and prevents the borrow
checker from helping you.