Skip to content

Commit 649d443

Browse files
committed
Replace expr_visitor with for_each_expr
1 parent bef93d3 commit 649d443

10 files changed

+206
-267
lines changed

clippy_lints/src/implicit_return.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use clippy_utils::{
22
diagnostics::span_lint_hir_and_then,
33
get_async_fn_body, is_async_fn,
44
source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
5-
visitors::expr_visitor_no_bodies,
5+
visitors::for_each_expr,
66
};
7+
use core::ops::ControlFlow;
78
use rustc_errors::Applicability;
8-
use rustc_hir::intravisit::{FnKind, Visitor};
9+
use rustc_hir::intravisit::FnKind;
910
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
1011
use rustc_lint::{LateContext, LateLintPass, LintContext};
1112
use rustc_middle::lint::in_external_macro;
@@ -152,7 +153,7 @@ fn lint_implicit_returns(
152153

153154
ExprKind::Loop(block, ..) => {
154155
let mut add_return = false;
155-
expr_visitor_no_bodies(|e| {
156+
let _: Option<!> = for_each_expr(block, |e| {
156157
if let ExprKind::Break(dest, sub_expr) = e.kind {
157158
if dest.target_id.ok() == Some(expr.hir_id) {
158159
if call_site_span.is_none() && e.span.ctxt() == ctxt {
@@ -167,9 +168,8 @@ fn lint_implicit_returns(
167168
}
168169
}
169170
}
170-
true
171-
})
172-
.visit_block(block);
171+
ControlFlow::Continue(())
172+
});
173173
if add_return {
174174
#[expect(clippy::option_if_let_else)]
175175
if let Some(span) = call_site_span {

clippy_lints/src/methods/str_splitn.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use clippy_utils::consts::{constant, Constant};
22
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
33
use clippy_utils::source::snippet_with_context;
44
use clippy_utils::usage::local_used_after_expr;
5-
use clippy_utils::visitors::expr_visitor;
5+
use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
66
use clippy_utils::{is_diag_item_method, match_def_path, meets_msrv, msrvs, path_to_local_id, paths};
7+
use core::ops::ControlFlow;
78
use if_chain::if_chain;
89
use rustc_errors::Applicability;
9-
use rustc_hir::intravisit::Visitor;
1010
use rustc_hir::{
1111
BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
1212
};
@@ -211,7 +211,7 @@ fn indirect_usage<'tcx>(
211211
binding: HirId,
212212
ctxt: SyntaxContext,
213213
) -> Option<IndirectUsage<'tcx>> {
214-
if let StmtKind::Local(Local {
214+
if let StmtKind::Local(&Local {
215215
pat: Pat {
216216
kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
217217
..
@@ -222,14 +222,12 @@ fn indirect_usage<'tcx>(
222222
}) = stmt.kind
223223
{
224224
let mut path_to_binding = None;
225-
expr_visitor(cx, |expr| {
226-
if path_to_local_id(expr, binding) {
227-
path_to_binding = Some(expr);
225+
let _: Option<!> = for_each_expr_with_closures(cx, init_expr, |e| {
226+
if path_to_local_id(e, binding) {
227+
path_to_binding = Some(e);
228228
}
229-
230-
path_to_binding.is_none()
231-
})
232-
.visit_expr(init_expr);
229+
ControlFlow::Continue(Descend::from(path_to_binding.is_none()))
230+
});
233231

234232
let mut parents = cx.tcx.hir().parent_iter(path_to_binding?.hir_id);
235233
let iter_usage = parse_iter_usage(cx, ctxt, &mut parents)?;
@@ -250,7 +248,7 @@ fn indirect_usage<'tcx>(
250248
..
251249
} = iter_usage
252250
{
253-
if parent_id == *local_hir_id {
251+
if parent_id == local_hir_id {
254252
return Some(IndirectUsage {
255253
name: ident.name,
256254
span: stmt.span,

clippy_lints/src/needless_late_init.rs

+14-20
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::path_to_local;
33
use clippy_utils::source::snippet_opt;
44
use clippy_utils::ty::needs_ordered_drop;
5-
use clippy_utils::visitors::{expr_visitor, expr_visitor_no_bodies, is_local_used};
5+
use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_local_used};
6+
use core::ops::ControlFlow;
67
use rustc_errors::{Applicability, MultiSpan};
7-
use rustc_hir::intravisit::Visitor;
88
use rustc_hir::{
99
BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
1010
StmtKind,
@@ -64,31 +64,25 @@ declare_clippy_lint! {
6464
declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]);
6565

6666
fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool {
67-
let mut seen = false;
68-
expr_visitor(cx, |expr| {
69-
if let ExprKind::Assign(..) = expr.kind {
70-
seen = true;
67+
for_each_expr_with_closures(cx, stmt, |e| {
68+
if matches!(e.kind, ExprKind::Assign(..)) {
69+
ControlFlow::Break(())
70+
} else {
71+
ControlFlow::Continue(())
7172
}
72-
73-
!seen
7473
})
75-
.visit_stmt(stmt);
76-
77-
seen
74+
.is_some()
7875
}
7976

8077
fn contains_let(cond: &Expr<'_>) -> bool {
81-
let mut seen = false;
82-
expr_visitor_no_bodies(|expr| {
83-
if let ExprKind::Let(_) = expr.kind {
84-
seen = true;
78+
for_each_expr(cond, |e| {
79+
if matches!(e.kind, ExprKind::Let(_)) {
80+
ControlFlow::Break(())
81+
} else {
82+
ControlFlow::Continue(())
8583
}
86-
87-
!seen
8884
})
89-
.visit_expr(cond);
90-
91-
seen
85+
.is_some()
9286
}
9387

9488
fn stmt_needs_ordered_drop(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {

clippy_lints/src/panic_in_result_fn.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::macros::root_macro_call_first_node;
33
use clippy_utils::return_ty;
44
use clippy_utils::ty::is_type_diagnostic_item;
5-
use clippy_utils::visitors::expr_visitor_no_bodies;
5+
use clippy_utils::visitors::{for_each_expr, Descend};
6+
use core::ops::ControlFlow;
67
use rustc_hir as hir;
7-
use rustc_hir::intravisit::{FnKind, Visitor};
8+
use rustc_hir::intravisit::FnKind;
89
use rustc_lint::{LateContext, LateLintPass};
910
use rustc_session::{declare_lint_pass, declare_tool_lint};
1011
use rustc_span::{sym, Span};
@@ -58,18 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
5859

5960
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
6061
let mut panics = Vec::new();
61-
expr_visitor_no_bodies(|expr| {
62-
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true };
62+
let _: Option<!> = for_each_expr(body.value, |e| {
63+
let Some(macro_call) = root_macro_call_first_node(cx, e) else {
64+
return ControlFlow::Continue(Descend::Yes);
65+
};
6366
if matches!(
6467
cx.tcx.item_name(macro_call.def_id).as_str(),
6568
"unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne"
6669
) {
6770
panics.push(macro_call.span);
68-
return false;
71+
ControlFlow::Continue(Descend::No)
72+
} else {
73+
ControlFlow::Continue(Descend::Yes)
6974
}
70-
true
71-
})
72-
.visit_expr(body.value);
75+
});
7376
if !panics.is_empty() {
7477
span_lint_and_then(
7578
cx,

clippy_lints/src/read_zero_byte_vec.rs

+17-23
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ use clippy_utils::{
22
diagnostics::{span_lint, span_lint_and_sugg},
33
higher::{get_vec_init_kind, VecInitKind},
44
source::snippet,
5-
visitors::expr_visitor_no_bodies,
5+
visitors::for_each_expr,
66
};
7-
use hir::{intravisit::Visitor, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind};
7+
use core::ops::ControlFlow;
8+
use hir::{Expr, ExprKind, Local, PatKind, PathSegment, QPath, StmtKind};
89
use rustc_errors::Applicability;
910
use rustc_hir as hir;
1011
use rustc_lint::{LateContext, LateLintPass};
@@ -58,38 +59,31 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
5859
&& let PatKind::Binding(_, _, ident, _) = pat.kind
5960
&& let Some(vec_init_kind) = get_vec_init_kind(cx, init)
6061
{
61-
// finds use of `_.read(&mut v)`
62-
let mut read_found = false;
63-
let mut visitor = expr_visitor_no_bodies(|expr| {
64-
if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind
62+
let visitor = |expr: &Expr<'_>| {
63+
if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind
6564
&& let PathSegment { ident: read_or_read_exact, .. } = *path
6665
&& matches!(read_or_read_exact.as_str(), "read" | "read_exact")
6766
&& let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind
6867
&& let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind
6968
&& let [inner_seg] = inner_path.segments
7069
&& ident.name == inner_seg.ident.name
7170
{
72-
read_found = true;
71+
ControlFlow::Break(())
72+
} else {
73+
ControlFlow::Continue(())
7374
}
74-
!read_found
75-
});
75+
};
7676

77-
let next_stmt_span;
78-
if idx == block.stmts.len() - 1 {
77+
let (read_found, next_stmt_span) =
78+
if let Some(next_stmt) = block.stmts.get(idx + 1) {
79+
// case { .. stmt; stmt; .. }
80+
(for_each_expr(next_stmt, visitor).is_some(), next_stmt.span)
81+
} else if let Some(e) = block.expr {
7982
// case { .. stmt; expr }
80-
if let Some(e) = block.expr {
81-
visitor.visit_expr(e);
82-
next_stmt_span = e.span;
83-
} else {
84-
return;
85-
}
83+
(for_each_expr(e, visitor).is_some(), e.span)
8684
} else {
87-
// case { .. stmt; stmt; .. }
88-
let next_stmt = &block.stmts[idx + 1];
89-
visitor.visit_stmt(next_stmt);
90-
next_stmt_span = next_stmt.span;
91-
}
92-
drop(visitor);
85+
return
86+
};
9387

9488
if read_found && !next_stmt_span.from_expansion() {
9589
let applicability = Applicability::MaybeIncorrect;

clippy_utils/src/lib.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(control_flow_enum)]
44
#![feature(let_chains)]
55
#![feature(lint_reasons)]
6+
#![feature(never_type)]
67
#![feature(once_cell)]
78
#![feature(rustc_private)]
89
#![recursion_limit = "512"]
@@ -65,6 +66,7 @@ pub use self::hir_utils::{
6566
both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
6667
};
6768

69+
use core::ops::ControlFlow;
6870
use std::collections::hash_map::Entry;
6971
use std::hash::BuildHasherDefault;
7072
use std::sync::OnceLock;
@@ -113,7 +115,7 @@ use rustc_target::abi::Integer;
113115

114116
use crate::consts::{constant, Constant};
115117
use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
116-
use crate::visitors::expr_visitor_no_bodies;
118+
use crate::visitors::for_each_expr;
117119

118120
pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
119121
if let Ok(version) = RustcVersion::parse(msrv) {
@@ -1193,17 +1195,14 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
11931195

11941196
/// Returns `true` if `expr` contains a return expression
11951197
pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
1196-
let mut found = false;
1197-
expr_visitor_no_bodies(|expr| {
1198-
if !found {
1199-
if let hir::ExprKind::Ret(..) = &expr.kind {
1200-
found = true;
1201-
}
1198+
for_each_expr(expr, |e| {
1199+
if matches!(e.kind, hir::ExprKind::Ret(..)) {
1200+
ControlFlow::Break(())
1201+
} else {
1202+
ControlFlow::Continue(())
12021203
}
1203-
!found
12041204
})
1205-
.visit_expr(expr);
1206-
found
1205+
.is_some()
12071206
}
12081207

12091208
/// Extends the span to the beginning of the spans line, incl. whitespaces.

0 commit comments

Comments
 (0)