diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 5a5dfcfdc8a..35db45e2b0c 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -18,6 +18,13 @@ declare_clippy_lint! { /// ### What it does /// Checks for calls to `push` immediately after creating a new `Vec`. /// + /// If the `Vec` is created using `with_capacity` this will only lint if the capacity is a + /// constant and the number of pushes is greater than or equal to the initial capacity. + /// + /// If the `Vec` is extended after the initial sequence of pushes and it was default initialized + /// then this will only lint after there were at least four pushes. This number may change in + /// the future. + /// /// ### Why is this bad? /// The `vec![]` macro is both more performant and easier to read than /// multiple `push` calls. @@ -56,7 +63,7 @@ struct VecPushSearcher { } impl VecPushSearcher { fn display_err(&self, cx: &LateContext<'_>) { - let min_pushes_for_extension = match self.init { + let required_pushes_before_extension = match self.init { _ if self.found == 0 => return, VecInitKind::WithConstCapacity(x) if x > self.found => return, VecInitKind::WithConstCapacity(x) => x, @@ -98,6 +105,8 @@ impl VecPushSearcher { && adjusted_mut == Mutability::Mut && !adjusted_ty.peel_refs().is_slice() => { + // No need to set `needs_mut` to true. The receiver will be either explicitly borrowed, or it will + // be implicitly borrowed via an adjustment. Both of these cases are already handled by this point. return ControlFlow::Break(true); }, ExprKind::Assign(lhs, ..) if e.hir_id == lhs.hir_id => { @@ -110,7 +119,7 @@ impl VecPushSearcher { }); // Avoid allocating small `Vec`s when they'll be extended right after. - if res == ControlFlow::Break(true) && self.found <= min_pushes_for_extension { + if res == ControlFlow::Break(true) && self.found <= required_pushes_before_extension { return; } diff --git a/tests/ui/vec_init_then_push.rs b/tests/ui/vec_init_then_push.rs index 768ea3e668a..531745424a7 100644 --- a/tests/ui/vec_init_then_push.rs +++ b/tests/ui/vec_init_then_push.rs @@ -29,6 +29,12 @@ fn main() { // no lint vec.push(1); } + + let mut vec = Vec::with_capacity(5); + vec.push(1); + vec.push(2); + vec.push(3); + vec.push(4); } pub fn no_lint() -> Vec { @@ -84,5 +90,17 @@ fn _cond_push_with_large_start(x: bool) -> Vec { if x { v.push(1); } - v + + let mut v2 = Vec::new(); + v2.push(0); + v2.push(1); + v2.push(0); + v2.push(1); + v2.push(0); + v2.push(0); + v2.push(1); + v2.push(0); + v2.extend(&v); + + v2 } diff --git a/tests/ui/vec_init_then_push.stderr b/tests/ui/vec_init_then_push.stderr index 362c9603bbf..50b029fc337 100644 --- a/tests/ui/vec_init_then_push.stderr +++ b/tests/ui/vec_init_then_push.stderr @@ -31,7 +31,7 @@ LL | | new_err.push(0); | |____________________^ help: consider using the `vec![]` macro: `new_err = vec![..];` error: calls to `push` immediately after creation - --> $DIR/vec_init_then_push.rs:67:5 + --> $DIR/vec_init_then_push.rs:73:5 | LL | / let mut v = Vec::new(); LL | | v.push(x); @@ -39,7 +39,7 @@ LL | | v.push(1); | |______________^ help: consider using the `vec![]` macro: `let mut v = vec![..];` error: calls to `push` immediately after creation - --> $DIR/vec_init_then_push.rs:75:5 + --> $DIR/vec_init_then_push.rs:81:5 | LL | / let mut v = Vec::new(); LL | | v.push(0); @@ -50,5 +50,17 @@ LL | | v.push(1); LL | | v.push(0); | |______________^ help: consider using the `vec![]` macro: `let mut v = vec![..];` -error: aborting due to 6 previous errors +error: calls to `push` immediately after creation + --> $DIR/vec_init_then_push.rs:94:5 + | +LL | / let mut v2 = Vec::new(); +LL | | v2.push(0); +LL | | v2.push(1); +LL | | v2.push(0); +... | +LL | | v2.push(1); +LL | | v2.push(0); + | |_______________^ help: consider using the `vec![]` macro: `let mut v2 = vec![..];` + +error: aborting due to 7 previous errors