Skip to content

Commit 44c2a82

Browse files
committed
Swap Visitors to early exit, instead of storing poison flag
1 parent ccf7c88 commit 44c2a82

9 files changed

Lines changed: 148 additions & 158 deletions

File tree

‎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-
letmut walker = ContainsName{
544-
name,
545-
result:false,
546-
cx,
547-
};
543+
letmut walker = ContainsName{ name, cx };
548544

549545
// Scan block
550-
block
546+
letmut 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
ifletSome(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
fnhas_unsafe<'tcx>(cx:&LateContext<'tcx>,item:&'tcxItem<'_>) -> bool{
374-
letmut visitor = UnsafeVisitor{ cx,has_unsafe:false};
375-
walk_item(&mut visitor, item);
376-
visitor.has_unsafe
376+
letmut visitor = UnsafeVisitor{ cx };
377+
walk_item(&mut visitor, item).is_break()
377378
}
378379

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

407408
structUnsafeVisitor<'a,'tcx>{
408409
cx:&'aLateContext<'tcx>,
409-
has_unsafe:bool,
410410
}
411411

412412
impl<'tcx>Visitor<'tcx>forUnsafeVisitor<'_,'tcx>{
413+
typeResult = ControlFlow<()>;
413414
typeNestedFilter = nested_filter::All;
414415

415-
fnvisit_fn(&mutself,kind:FnKind<'tcx>,decl:&'tcxFnDecl<'_>,body_id:BodyId, _:Span,id:LocalDefId){
416-
ifself.has_unsafe{
417-
return;
418-
}
419-
416+
fnvisit_fn(
417+
&mutself,
418+
kind:FnKind<'tcx>,
419+
decl:&'tcxFnDecl<'_>,
420+
body_id:BodyId,
421+
_:Span,
422+
id:LocalDefId,
423+
) -> Self::Result{
420424
ifletSome(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-
fnvisit_expr(&mutself,expr:&'tcxExpr<'_>){
430-
ifself.has_unsafe{
431-
return;
432-
}
433-
433+
fnvisit_expr(&mutself,expr:&'tcxExpr<'_>) -> Self::Result{
434434
ifletExprKind::Block(block, _) = expr.kind{
435435
if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided){
436-
self.has_unsafe = true;
436+
returnControlFlow::Break(());
437437
}
438438
}
439439

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

443443
fnnested_visit_map(&mutself) -> 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
structSelfFinder<'a,'tcx>{
119124
cx:&'aLateContext<'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>forSelfFinder<'_,'tcx>{
132+
typeResult = ControlFlow<()>;
130133
typeNestedFilter = OnlyBodies;
131134

132135
fnnested_visit_map(&mutself) -> Self::Map{
133136
self.cx.tcx.hir()
134137
}
135138

136-
fnvisit_path(&mutself,path:&Path<'tcx>,_id:HirId){
139+
fnvisit_path(&mutself,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+
returnControlFlow::Break(());
149+
}
145150
}
146151

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

152-
fnvisit_name(&mutself,name:Symbol){
155+
fnvisit_name(&mutself,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
returnNone;
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:&'aLateContext<'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>forVarCollectorVisitor<'_,'tcx>{
107-
fnvisit_expr(&mutself,ex:&'tcxExpr<'_>){
104+
typeResult = ControlFlow<()>;
105+
fnvisit_expr(&mutself,ex:&'tcxExpr<'_>) -> 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
usesuper::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
structV<'a,'b,'tcx>{
205207
cx:&'aLateContext<'tcx>,
206208
iter_expr:&'bIterExpr,
207-
uses_iter:bool,
208209
}
209210
impl<'tcx>Visitor<'tcx>forV<'_,'_,'tcx>{
210-
fnvisit_expr(&mutself,e:&'tcxExpr<'_>){
211-
ifself.uses_iter{
212-
// return
213-
}elseifis_expr_same_child_or_parent_field(self.cx, e,&self.iter_expr.fields,self.iter_expr.path){
214-
self.uses_iter = true;
211+
typeResult = ControlFlow<()>;
212+
fnvisit_expr(&mutself,e:&'tcxExpr<'_>) -> Self::Result{
213+
ifis_expr_same_child_or_parent_field(self.cx, e,&self.iter_expr.fields,self.iter_expr.path){
214+
ControlFlow::Break(())
215215
}elseiflet(e,true) = skip_fields_and_path(e){
216216
ifletSome(e) = e {
217-
self.visit_expr(e);
217+
self.visit_expr(e)
218+
}else{
219+
ControlFlow::Continue(())
218220
}
219221
}elseifletExprKind::Closure(&Closure{body: id, .. }) = e.kind{
220222
ifis_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-
letmut v = V{
230-
cx,
231-
iter_expr,
232-
uses_iter:false,
233-
};
234-
v.visit_expr(container);
235-
v.uses_iter
233+
letmut 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:&'bIterExpr,
243242
loop_id:HirId,
244243
after_loop:bool,
245-
used_iter:bool,
246244
}
247245
impl<'tcx>Visitor<'tcx>forAfterLoopVisitor<'_,'_,'tcx>{
248246
typeNestedFilter = OnlyBodies;
247+
typeResult = ControlFlow<()>;
249248
fnnested_visit_map(&mutself) -> Self::Map{
250249
self.cx.tcx.hir()
251250
}
252251

253-
fnvisit_expr(&mutself,e:&'tcxExpr<'_>){
254-
ifself.used_iter{
255-
return;
256-
}
252+
fnvisit_expr(&mutself,e:&'tcxExpr<'_>) -> Self::Result{
257253
ifself.after_loop{
258254
ifis_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
}elseiflet(e,true) = skip_fields_and_path(e){
261257
ifletSome(e) = e {
262-
self.visit_expr(e);
258+
self.visit_expr(e)
259+
}else{
260+
ControlFlow::Continue(())
263261
}
264262
}elseifletExprKind::Closure(&Closure{body: id, .. }) = e.kind{
265-
self.used_iter = is_res_used(self.cx,self.iter_expr.path, id);
263+
ifis_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
}elseifself.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
iflet ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind()
2426
&& let ty::Str = ty.kind()
2527
{
26-
letmut visitor = MatchExprVisitor{ cx,case_method:None};
27-
28-
visitor.visit_expr(scrutinee);
29-
30-
ifletSome(case_method) = visitor.case_method{
28+
letmut visitor = MatchExprVisitor{ cx };
29+
ifletControlFlow::Break(case_method) = visitor.visit_expr(scrutinee){
3130
ifletSome((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
structMatchExprVisitor<'a,'tcx>{
3938
cx:&'aLateContext<'tcx>,
40-
case_method:Option<CaseMethod>,
4139
}
4240

4341
impl<'tcx>Visitor<'tcx>forMatchExprVisitor<'_,'tcx>{
44-
fnvisit_expr(&mutself,ex:&'tcxExpr<'_>){
45-
match ex.kind{
46-
ExprKind::MethodCall(segment, receiver,[], _)ifself.case_altered(segment.ident.as_str(), receiver) => {},
47-
_ => walk_expr(self, ex),
42+
typeResult = ControlFlow<CaseMethod>;
43+
fnvisit_expr(&mutself,ex:&'tcxExpr<'_>) -> Self::Result{
44+
ifletExprKind::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
implMatchExprVisitor<'_,'_>{
53-
fncase_altered(&mutself,segment_ident:&str,receiver:&Expr<'_>) -> bool{
56+
fncase_altered(&mutself,segment_ident:&str,receiver:&Expr<'_>) -> ControlFlow<CaseMethod>{
5457
ifletSome(case_method) = get_case_method(segment_ident){
5558
let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
5659

5760
ifis_type_lang_item(self.cx, ty,LangItem::String) || ty.kind() == &ty::Str{
58-
self.case_method = Some(case_method);
59-
returntrue;
61+
returnControlFlow::Break(case_method);
6062
}
6163
}
6264

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

0 commit comments

Comments
 (0)