diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 0ef7e05de..9db18c297 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::macros::root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local, @@ -148,6 +149,15 @@ impl SlowVectorInit { /// - `Some(InitializedSize::Uninitialized)` for `Vec::new()` /// - `None` for other, unrelated kinds of expressions fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option> { + // Generally don't warn if the vec initializer comes from an expansion, except for the vec! macro. + // This lets us still warn on `vec![]`, while ignoring other kinds of macros that may output an + // empty vec + if expr.span.from_expansion() + && root_macro_call(expr.span).map(|m| m.def_id) != cx.tcx.get_diagnostic_item(sym::vec_macro) + { + return None; + } + if let ExprKind::Call(func, [len_expr]) = expr.kind && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY) { diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs index f8d85ed38..5c3086c9d 100644 --- a/tests/ui/slow_vector_initialization.rs +++ b/tests/ui/slow_vector_initialization.rs @@ -1,5 +1,5 @@ -use std::iter::repeat; //@no-rustfix +use std::iter::repeat; fn main() { resize_vector(); extend_vector(); @@ -86,6 +86,20 @@ fn from_empty_vec() { vec1 = Vec::new(); vec1.resize(10, 0); //~^ ERROR: slow zero-filling initialization + + vec1 = vec![]; + vec1.resize(10, 0); + //~^ ERROR: slow zero-filling initialization + + macro_rules! x { + () => { + vec![] + }; + } + + // `vec![]` comes from another macro, don't warn + vec1 = x!(); + vec1.resize(10, 0); } fn do_stuff(vec: &mut [u8]) {} diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr index 4800e6e44..73a9cb55e 100644 --- a/tests/ui/slow_vector_initialization.stderr +++ b/tests/ui/slow_vector_initialization.stderr @@ -96,13 +96,21 @@ LL | vec1 = Vec::new(); LL | vec1.resize(10, 0); | ^^^^^^^^^^^^^^^^^^ +error: slow zero-filling initialization + --> $DIR/slow_vector_initialization.rs:91:5 + | +LL | vec1 = vec![]; + | ------ help: consider replacing this with: `vec![0; 10]` +LL | vec1.resize(10, 0); + | ^^^^^^^^^^^^^^^^^^ + error: this argument is a mutable reference, but not used mutably - --> $DIR/slow_vector_initialization.rs:91:18 + --> $DIR/slow_vector_initialization.rs:105:18 | LL | fn do_stuff(vec: &mut [u8]) {} | ^^^^^^^^^ help: consider changing to: `&[u8]` | = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors