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