@@ -5,14 +5,82 @@ use rustc_hir as hir;
5
5
use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
6
6
use rustc_hir:: intravisit:: { self , walk_block, walk_expr, Visitor } ;
7
7
use rustc_hir:: {
8
- Arm , Block , BlockCheckMode , Body , BodyId , Expr , ExprKind , HirId , ItemId , ItemKind , Let , QPath , Stmt , UnOp ,
8
+ Arm , Block , BlockCheckMode , Body , BodyId , Expr , ExprKind , HirId , ItemId , ItemKind , Let , Pat , QPath , Stmt , UnOp ,
9
9
UnsafeSource , Unsafety ,
10
10
} ;
11
11
use rustc_lint:: LateContext ;
12
12
use rustc_middle:: hir:: map:: Map ;
13
13
use rustc_middle:: hir:: nested_filter;
14
14
use rustc_middle:: ty:: adjustment:: Adjust ;
15
15
use rustc_middle:: ty:: { self , Ty , TypeckResults } ;
16
+ use rustc_span:: Span ;
17
+
18
+ mod internal {
19
+ /// Trait for visitor functions to control whether or not to descend to child nodes. Implemented
20
+ /// for only two types. `()` always descends. `Descend` allows controlled descent.
21
+ pub trait Continue {
22
+ fn descend ( & self ) -> bool ;
23
+ }
24
+ }
25
+ use internal:: Continue ;
26
+
27
+ impl Continue for ( ) {
28
+ fn descend ( & self ) -> bool {
29
+ true
30
+ }
31
+ }
32
+
33
+ /// Allows for controlled descent whe using visitor functions. Use `()` instead when always
34
+ /// descending into child nodes.
35
+ #[ derive( Clone , Copy ) ]
36
+ pub enum Descend {
37
+ Yes ,
38
+ No ,
39
+ }
40
+ impl From < bool > for Descend {
41
+ fn from ( from : bool ) -> Self {
42
+ if from { Self :: Yes } else { Self :: No }
43
+ }
44
+ }
45
+ impl Continue for Descend {
46
+ fn descend ( & self ) -> bool {
47
+ matches ! ( self , Self :: Yes )
48
+ }
49
+ }
50
+
51
+ /// Calls the given function once for each expression contained. This does not enter any bodies or
52
+ /// nested items.
53
+ pub fn for_each_expr < ' tcx , B , C : Continue > (
54
+ node : impl Visitable < ' tcx > ,
55
+ f : impl FnMut ( & ' tcx Expr < ' tcx > ) -> ControlFlow < B , C > ,
56
+ ) -> Option < B > {
57
+ struct V < B , F > {
58
+ f : F ,
59
+ res : Option < B > ,
60
+ }
61
+ impl < ' tcx , B , C : Continue , F : FnMut ( & ' tcx Expr < ' tcx > ) -> ControlFlow < B , C > > Visitor < ' tcx > for V < B , F > {
62
+ fn visit_expr ( & mut self , e : & ' tcx Expr < ' tcx > ) {
63
+ if self . res . is_some ( ) {
64
+ return ;
65
+ }
66
+ match ( self . f ) ( e) {
67
+ ControlFlow :: Continue ( c) if c. descend ( ) => walk_expr ( self , e) ,
68
+ ControlFlow :: Break ( b) => self . res = Some ( b) ,
69
+ ControlFlow :: Continue ( _) => ( ) ,
70
+ }
71
+ }
72
+
73
+ // Avoid unnecessary `walk_*` calls.
74
+ fn visit_ty ( & mut self , _: & ' tcx hir:: Ty < ' tcx > ) { }
75
+ fn visit_pat ( & mut self , _: & ' tcx Pat < ' tcx > ) { }
76
+ fn visit_qpath ( & mut self , _: & ' tcx QPath < ' tcx > , _: HirId , _: Span ) { }
77
+ // Avoid monomorphising all `visit_*` functions.
78
+ fn visit_nested_item ( & mut self , _: ItemId ) { }
79
+ }
80
+ let mut v = V { f, res : None } ;
81
+ node. visit ( & mut v) ;
82
+ v. res
83
+ }
16
84
17
85
/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested
18
86
/// bodies (i.e. closures) are visited.
0 commit comments