Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zero_len_vec_used for iterating, using vec.len(), or slicing after Vec::with_capacity #14146

Open
jakubdabek opened this issue Feb 4, 2025 · 0 comments
Labels
A-lint Area: New lints

Comments

@jakubdabek
Copy link

What it does

Checks for empty Vecs and usage that requires it to be non-empty to make sense.

Similar to read_zero_byte_vec, but more general.

Advantage

  • Catches when someone writes Vec::with_capacity (or Vec::new(), Vec::default(), vec![]) and tries to incorrectly use it as if it was filled.

Drawbacks

  • It could suggest a possible resolution, but it won't work in all cases.
  • Not sure how it should interact with loops

Example

// 1)
let mut v = Vec::with_capacity(100);
let mut rng = rand::rng();
for elem in &mut v {
    *elem = rng::random::<i32>();
}

// 2)
let mut v = Vec::with_capacity(100);
for (i, elem) in v.iter_mut().enumerate() {
    *elem = i;
}

// 3)
let mut v = Vec::with_capacity(100);
// Will always be 0.
foo(v.len());

// 4)
// slice, not `&mut Vec`, this covers `Read::read` case as well
fn foo(_: &mut [T]) {...}
let mut v = Vec::with_capacity(100);
// Will always be empty.
foo(&mut v);

// 5)
let mut v = Vec::<u32>::with_capacity(100);
// Will always be `None`.
foo(v.pop());

// 6)
let mut v = Vec::<u32>::with_capacity(100);
// Will always be false.
if !v.is_empty() {
    foo();
}

// 7)
let mut v = Vec::with_capacity(100);
loop {
    // always 0
    let len = v.len();
    // code that doesn't modify `v`
}

// 8)
// Should this be linted?
let mut v = Vec::with_capacity(100);
loop {
    // always 0 in the first iteration
    let len = v.len();
    // code that *possibly* modifies `v`
}

// 9)
// Possible interaction with `impossible_comparisons`, `never_loop` or something similar.
let mut v = Vec::with_capacity(100);
// Will never enter the loop.
while v.len() > 0 {
    v.pop();
}

// 10)
let mut v = Vec::with_capacity(100);
// Check patterns too.
// Will never enter the loop.
while let [.., last] = &v[..] {
    v.pop();
}

Could be written as:

let mut v = Vec::with_capacity(100);
// Not always applicable with `Default`.
// Also this could be optimized out, but a generic suggestion
// would not be performance-oriented.
v.resize_with(100, Default::default);
let mut rng = rand::rng();
for elem in &mut v {
    *elem = rng::random::<i32>();
}

// 3)
let mut v = Vec::with_capacity(100);
foo(0); // probably incorrect

// 4)
fn foo(_: &mut [T]) {...}
let mut v = Vec::with_capacity(100);
v.resize_with(100, Default::default);
foo(&mut v);
@jakubdabek jakubdabek added the A-lint Area: New lints label Feb 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints
Projects
None yet
Development

No branches or pull requests

1 participant