about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLzu Tao <taolzu@gmail.com>2024-07-17 11:27:42 +0000
committerLzu Tao <taolzu@gmail.com>2024-07-17 18:33:36 +0700
commit5540060d5d29aa56842cb004e5f1c2aa30d7b091 (patch)
treecf8a110b63ade180a0e5f8164dfd96d61e8a0ff7
parentc65ddb8728de895b53557b0aaf7df1873417f916 (diff)
downloadrust-5540060d5d29aa56842cb004e5f1c2aa30d7b091.tar.gz
rust-5540060d5d29aa56842cb004e5f1c2aa30d7b091.zip
Skip linting if array length is from a macro.
-rw-r--r--clippy_lints/src/zero_repeat_side_effects.rs41
-rw-r--r--tests/ui/zero_repeat_side_effects.fixed8
-rw-r--r--tests/ui/zero_repeat_side_effects.rs4
-rw-r--r--tests/ui/zero_repeat_side_effects.stderr14
4 files changed, 42 insertions, 25 deletions
diff --git a/clippy_lints/src/zero_repeat_side_effects.rs b/clippy_lints/src/zero_repeat_side_effects.rs
index ad041e55bda..6f2bfab1a30 100644
--- a/clippy_lints/src/zero_repeat_side_effects.rs
+++ b/clippy_lints/src/zero_repeat_side_effects.rs
@@ -4,7 +4,8 @@ use clippy_utils::source::snippet;
 use clippy_utils::visitors::for_each_expr_without_closures;
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{ExprKind, Node};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{ArrayLen, ExprKind, ItemKind, Node, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, ConstKind, Ty};
 use rustc_session::declare_lint_pass;
@@ -45,7 +46,8 @@ declare_clippy_lint! {
 declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]);
 
 impl LateLintPass<'_> for ZeroRepeatSideEffects {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>) {
+        let hir_map = cx.tcx.hir();
         if let Some(args) = VecArgs::hir(cx, expr)
             && let VecArgs::Repeat(inner_expr, len) = args
             && let ExprKind::Lit(l) = len.kind
@@ -53,12 +55,35 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects {
             && i.0 == 0
         {
             inner_check(cx, expr, inner_expr, true);
-        } else if let ExprKind::Repeat(inner_expr, _) = expr.kind
-            && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind()
-            && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
-            && element_count.to_target_usize(cx.tcx) == 0
-        {
-            inner_check(cx, expr, inner_expr, false);
+        } else {
+            let ExprKind::Repeat(inner_expr, length) = expr.kind else {
+                return;
+            };
+            // Skip if the length is from a macro.
+            if let ArrayLen::Body(anon_const) = length {
+                let length_expr = hir_map.body(anon_const.body).value;
+                if !length_expr.span.eq_ctxt(expr.span) {
+                    return;
+                }
+
+                // Get the initialization span of a const item and compare it with the span at use-site.
+                if let ExprKind::Path(QPath::Resolved(None, path)) = length_expr.kind
+                    && let Res::Def(DefKind::Const, def_id) = path.res
+                    && let Some(def_id) = def_id.as_local()
+                    && let Node::Item(item) = cx.tcx.hir_node_by_def_id(def_id)
+                    && let ItemKind::Const(_ty, _, body_id) = item.kind
+                    && let init_span = hir_map.span_with_body(body_id.hir_id)
+                    && !init_span.eq_ctxt(length_expr.span)
+                {
+                    return;
+                }
+            }
+            if let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind()
+                && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
+                && element_count.to_target_usize(cx.tcx) == 0
+            {
+                inner_check(cx, expr, inner_expr, false);
+            }
         }
     }
 }
diff --git a/tests/ui/zero_repeat_side_effects.fixed b/tests/ui/zero_repeat_side_effects.fixed
index ce6a46b8a60..75ebc6f35d1 100644
--- a/tests/ui/zero_repeat_side_effects.fixed
+++ b/tests/ui/zero_repeat_side_effects.fixed
@@ -60,11 +60,13 @@ fn main() {
 }
 
 macro_rules! LEN {
-    () => {0};
+    () => {
+        0
+    };
 }
 
 fn issue_13110() {
-    f(); let _data: [i32; 0] = [];
+    let _data = [f(); LEN!()];
     const LENGTH: usize = LEN!();
-    f(); let _data: [i32; 0] = [];
+    let _data = [f(); LENGTH];
 }
diff --git a/tests/ui/zero_repeat_side_effects.rs b/tests/ui/zero_repeat_side_effects.rs
index d68667dda31..1a1a9f93d1f 100644
--- a/tests/ui/zero_repeat_side_effects.rs
+++ b/tests/ui/zero_repeat_side_effects.rs
@@ -60,7 +60,9 @@ fn main() {
 }
 
 macro_rules! LEN {
-    () => {0};
+    () => {
+        0
+    };
 }
 
 fn issue_13110() {
diff --git a/tests/ui/zero_repeat_side_effects.stderr b/tests/ui/zero_repeat_side_effects.stderr
index 6f31242a252..afdc6054253 100644
--- a/tests/ui/zero_repeat_side_effects.stderr
+++ b/tests/ui/zero_repeat_side_effects.stderr
@@ -73,17 +73,5 @@ error: function or method calls as the initial value in zero-sized array initial
 LL |     [f(); N];
    |     ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }`
 
-error: function or method calls as the initial value in zero-sized array initializers may cause side effects
-  --> tests/ui/zero_repeat_side_effects.rs:67:5
-   |
-LL |     let _data = [f(); LEN!()];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let _data: [i32; 0] = [];`
-
-error: function or method calls as the initial value in zero-sized array initializers may cause side effects
-  --> tests/ui/zero_repeat_side_effects.rs:69:5
-   |
-LL |     let _data = [f(); LENGTH];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let _data: [i32; 0] = [];`
-
-error: aborting due to 14 previous errors
+error: aborting due to 12 previous errors