about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/slow_vector_initialization.rs12
-rw-r--r--tests/ui/slow_vector_initialization.rs16
-rw-r--r--tests/ui/slow_vector_initialization.stderr12
3 files changed, 36 insertions, 4 deletions
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index c9ab622ad25..9db18c2976c 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<InitializedSize<'tcx>> {
+        // 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)
         {
@@ -205,7 +215,7 @@ impl SlowVectorInit {
 
         span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
             diag.span_suggestion(
-                vec_alloc.allocation_expr.span,
+                vec_alloc.allocation_expr.span.source_callsite(),
                 "consider replacing this with",
                 format!("vec![0; {len_expr}]"),
                 Applicability::Unspecified,
diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs
index f8d85ed38cd..5c3086c9d69 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 4800e6e4418..73a9cb55eb9 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