Skip to content

Commit 6631a2c

Browse files
committed
Auto merge of #13654 - GnomedDev:early-exit-visitors, r=Alexendoo
Swap Visitors to early exit, instead of storing poison flag I noticed that a bunch of visitors had a `poison` or `success` field, when they could just be returning `ControlFlow`. changelog: none
2 parents ccf7c88 + 44c2a82 commit 6631a2c

File tree

9 files changed

+148
-158
lines changed

9 files changed

+148
-158
lines changed

clippy_lints/src/copies.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -540,24 +540,22 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
540540
.iter()
541541
.filter(|&&(_, name)| !name.as_str().starts_with('_'))
542542
.any(|&(_, name)| {
543-
let mut walker = ContainsName {
544-
name,
545-
result: false,
546-
cx,
547-
};
543+
let mut walker = ContainsName { name, cx };
548544

549545
// Scan block
550-
block
546+
let mut res = block
551547
.stmts
552548
.iter()
553549
.filter(|stmt| !ignore_span.overlaps(stmt.span))
554-
.for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt));
550+
.try_for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt));
555551

556552
if let Some(expr) = block.expr {
557-
intravisit::walk_expr(&mut walker, expr);
553+
if res.is_continue() {
554+
res = intravisit::walk_expr(&mut walker, expr);
555+
}
558556
}
559557

560-
walker.result
558+
res.is_break()
561559
})
562560
})
563561
}

clippy_lints/src/derive.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::ControlFlow;
2+
13
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then, span_lint_hir_and_then};
24
use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
35
use clippy_utils::{has_non_exhaustive_attr, is_lint_allowed, match_def_path, paths};
@@ -371,9 +373,8 @@ fn check_unsafe_derive_deserialize<'tcx>(
371373
ty: Ty<'tcx>,
372374
) {
373375
fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
374-
let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
375-
walk_item(&mut visitor, item);
376-
visitor.has_unsafe
376+
let mut visitor = UnsafeVisitor { cx };
377+
walk_item(&mut visitor, item).is_break()
377378
}
378379

379380
if let Some(trait_def_id) = trait_ref.trait_def_id()
@@ -406,38 +407,37 @@ fn check_unsafe_derive_deserialize<'tcx>(
406407

407408
struct UnsafeVisitor<'a, 'tcx> {
408409
cx: &'a LateContext<'tcx>,
409-
has_unsafe: bool,
410410
}
411411

412412
impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
413+
type Result = ControlFlow<()>;
413414
type NestedFilter = nested_filter::All;
414415

415-
fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
416-
if self.has_unsafe {
417-
return;
418-
}
419-
416+
fn visit_fn(
417+
&mut self,
418+
kind: FnKind<'tcx>,
419+
decl: &'tcx FnDecl<'_>,
420+
body_id: BodyId,
421+
_: Span,
422+
id: LocalDefId,
423+
) -> Self::Result {
420424
if let Some(header) = kind.header()
421425
&& header.safety == Safety::Unsafe
422426
{
423-
self.has_unsafe = true;
427+
ControlFlow::Break(())
428+
} else {
429+
walk_fn(self, kind, decl, body_id, id)
424430
}
425-
426-
walk_fn(self, kind, decl, body_id, id);
427431
}
428432

429-
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
430-
if self.has_unsafe {
431-
return;
432-
}
433-
433+
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
434434
if let ExprKind::Block(block, _) = expr.kind {
435435
if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) {
436-
self.has_unsafe = true;
436+
return ControlFlow::Break(());
437437
}
438438
}
439439

440-
walk_expr(self, expr);
440+
walk_expr(self, expr)
441441
}
442442

443443
fn nested_visit_map(&mut self) -> Self::Map {

clippy_lints/src/from_over_into.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::ControlFlow;
2+
13
use clippy_config::Conf;
24
use clippy_config::msrvs::{self, Msrv};
35
use clippy_utils::diagnostics::span_lint_and_then;
@@ -115,43 +117,46 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
115117
}
116118

117119
/// Finds the occurrences of `Self` and `self`
120+
///
121+
/// Returns `ControlFlow::break` if any of the `self`/`Self` usages were from an expansion, or the
122+
/// body contained a binding already named `val`.
118123
struct SelfFinder<'a, 'tcx> {
119124
cx: &'a LateContext<'tcx>,
120125
/// Occurrences of `Self`
121126
upper: Vec<Span>,
122127
/// Occurrences of `self`
123128
lower: Vec<Span>,
124-
/// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding
125-
/// already named `val`
126-
invalid: bool,
127129
}
128130

129131
impl<'tcx> Visitor<'tcx> for SelfFinder<'_, 'tcx> {
132+
type Result = ControlFlow<()>;
130133
type NestedFilter = OnlyBodies;
131134

132135
fn nested_visit_map(&mut self) -> Self::Map {
133136
self.cx.tcx.hir()
134137
}
135138

136-
fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
139+
fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> Self::Result {
137140
for segment in path.segments {
138141
match segment.ident.name {
139142
kw::SelfLower => self.lower.push(segment.ident.span),
140143
kw::SelfUpper => self.upper.push(segment.ident.span),
141144
_ => continue,
142145
}
143146

144-
self.invalid |= segment.ident.span.from_expansion();
147+
if segment.ident.span.from_expansion() {
148+
return ControlFlow::Break(());
149+
}
145150
}
146151

147-
if !self.invalid {
148-
walk_path(self, path);
149-
}
152+
walk_path(self, path)
150153
}
151154

152-
fn visit_name(&mut self, name: Symbol) {
155+
fn visit_name(&mut self, name: Symbol) -> Self::Result {
153156
if name == sym::val {
154-
self.invalid = true;
157+
ControlFlow::Break(())
158+
} else {
159+
ControlFlow::Continue(())
155160
}
156161
}
157162
}
@@ -209,11 +214,9 @@ fn convert_to_from(
209214
cx,
210215
upper: Vec::new(),
211216
lower: Vec::new(),
212-
invalid: false,
213217
};
214-
finder.visit_expr(body.value);
215218

216-
if finder.invalid {
219+
if finder.visit_expr(body.value).is_break() {
217220
return None;
218221
}
219222

clippy_lints/src/loops/while_immutable_condition.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
1919
cx,
2020
ids: HirIdSet::default(),
2121
def_ids: DefIdMap::default(),
22-
skip: false,
2322
};
24-
var_visitor.visit_expr(cond);
25-
if var_visitor.skip {
23+
if var_visitor.visit_expr(cond).is_break() {
2624
return;
2725
}
2826
let used_in_condition = &var_visitor.ids;
@@ -81,7 +79,6 @@ struct VarCollectorVisitor<'a, 'tcx> {
8179
cx: &'a LateContext<'tcx>,
8280
ids: HirIdSet,
8381
def_ids: DefIdMap<bool>,
84-
skip: bool,
8582
}
8683

8784
impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
@@ -104,11 +101,15 @@ impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
104101
}
105102

106103
impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> {
107-
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
104+
type Result = ControlFlow<()>;
105+
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result {
108106
match ex.kind {
109-
ExprKind::Path(_) => self.insert_def_id(ex),
107+
ExprKind::Path(_) => {
108+
self.insert_def_id(ex);
109+
ControlFlow::Continue(())
110+
},
110111
// If there is any function/method call… we just stop analysis
111-
ExprKind::Call(..) | ExprKind::MethodCall(..) => self.skip = true,
112+
ExprKind::Call(..) | ExprKind::MethodCall(..) => ControlFlow::Break(()),
112113

113114
_ => walk_expr(self, ex),
114115
}

clippy_lints/src/loops/while_let_on_iterator.rs

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::ControlFlow;
2+
13
use super::WHILE_LET_ON_ITERATOR;
24
use clippy_utils::diagnostics::span_lint_and_sugg;
35
use clippy_utils::source::snippet_with_applicability;
@@ -204,35 +206,32 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc
204206
struct V<'a, 'b, 'tcx> {
205207
cx: &'a LateContext<'tcx>,
206208
iter_expr: &'b IterExpr,
207-
uses_iter: bool,
208209
}
209210
impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> {
210-
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
211-
if self.uses_iter {
212-
// return
213-
} else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
214-
self.uses_iter = true;
211+
type Result = ControlFlow<()>;
212+
fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
213+
if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
214+
ControlFlow::Break(())
215215
} else if let (e, true) = skip_fields_and_path(e) {
216216
if let Some(e) = e {
217-
self.visit_expr(e);
217+
self.visit_expr(e)
218+
} else {
219+
ControlFlow::Continue(())
218220
}
219221
} else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
220222
if is_res_used(self.cx, self.iter_expr.path, id) {
221-
self.uses_iter = true;
223+
ControlFlow::Break(())
224+
} else {
225+
ControlFlow::Continue(())
222226
}
223227
} else {
224-
walk_expr(self, e);
228+
walk_expr(self, e)
225229
}
226230
}
227231
}
228232

229-
let mut v = V {
230-
cx,
231-
iter_expr,
232-
uses_iter: false,
233-
};
234-
v.visit_expr(container);
235-
v.uses_iter
233+
let mut v = V { cx, iter_expr };
234+
v.visit_expr(container).is_break()
236235
}
237236

238237
#[expect(clippy::too_many_lines)]
@@ -242,34 +241,38 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
242241
iter_expr: &'b IterExpr,
243242
loop_id: HirId,
244243
after_loop: bool,
245-
used_iter: bool,
246244
}
247245
impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
248246
type NestedFilter = OnlyBodies;
247+
type Result = ControlFlow<()>;
249248
fn nested_visit_map(&mut self) -> Self::Map {
250249
self.cx.tcx.hir()
251250
}
252251

253-
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
254-
if self.used_iter {
255-
return;
256-
}
252+
fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
257253
if self.after_loop {
258254
if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
259-
self.used_iter = true;
255+
ControlFlow::Break(())
260256
} else if let (e, true) = skip_fields_and_path(e) {
261257
if let Some(e) = e {
262-
self.visit_expr(e);
258+
self.visit_expr(e)
259+
} else {
260+
ControlFlow::Continue(())
263261
}
264262
} else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
265-
self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
263+
if is_res_used(self.cx, self.iter_expr.path, id) {
264+
ControlFlow::Break(())
265+
} else {
266+
ControlFlow::Continue(())
267+
}
266268
} else {
267-
walk_expr(self, e);
269+
walk_expr(self, e)
268270
}
269271
} else if self.loop_id == e.hir_id {
270272
self.after_loop = true;
273+
ControlFlow::Continue(())
271274
} else {
272-
walk_expr(self, e);
275+
walk_expr(self, e)
273276
}
274277
}
275278
}
@@ -347,9 +350,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
347350
iter_expr,
348351
loop_id: loop_expr.hir_id,
349352
after_loop: false,
350-
used_iter: false,
351353
};
352-
v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
353-
v.used_iter
354+
v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value)
355+
.is_break()
354356
}
355357
}

clippy_lints/src/matches/match_str_case_mismatch.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::ControlFlow;
2+
13
use clippy_utils::diagnostics::span_lint_and_sugg;
24
use clippy_utils::ty::is_type_lang_item;
35
use rustc_ast::ast::LitKind;
@@ -23,11 +25,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm
2325
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind()
2426
&& let ty::Str = ty.kind()
2527
{
26-
let mut visitor = MatchExprVisitor { cx, case_method: None };
27-
28-
visitor.visit_expr(scrutinee);
29-
30-
if let Some(case_method) = visitor.case_method {
28+
let mut visitor = MatchExprVisitor { cx };
29+
if let ControlFlow::Break(case_method) = visitor.visit_expr(scrutinee) {
3130
if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
3231
lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
3332
}
@@ -37,30 +36,33 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm
3736

3837
struct MatchExprVisitor<'a, 'tcx> {
3938
cx: &'a LateContext<'tcx>,
40-
case_method: Option<CaseMethod>,
4139
}
4240

4341
impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
44-
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
45-
match ex.kind {
46-
ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
47-
_ => walk_expr(self, ex),
42+
type Result = ControlFlow<CaseMethod>;
43+
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result {
44+
if let ExprKind::MethodCall(segment, receiver, [], _) = ex.kind {
45+
let result = self.case_altered(segment.ident.as_str(), receiver);
46+
if result.is_break() {
47+
return result;
48+
}
4849
}
50+
51+
walk_expr(self, ex)
4952
}
5053
}
5154

5255
impl MatchExprVisitor<'_, '_> {
53-
fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
56+
fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> {
5457
if let Some(case_method) = get_case_method(segment_ident) {
5558
let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
5659

5760
if is_type_lang_item(self.cx, ty, LangItem::String) || ty.kind() == &ty::Str {
58-
self.case_method = Some(case_method);
59-
return true;
61+
return ControlFlow::Break(case_method);
6062
}
6163
}
6264

63-
false
65+
ControlFlow::Continue(())
6466
}
6567
}
6668

0 commit comments

Comments
 (0)