@@ -5,14 +5,82 @@ use rustc_hir as hir;
55use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
66use rustc_hir:: intravisit:: { self , walk_block, walk_expr, Visitor } ;
77use 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 ,
99 UnsafeSource , Unsafety ,
1010} ;
1111use rustc_lint:: LateContext ;
1212use rustc_middle:: hir:: map:: Map ;
1313use rustc_middle:: hir:: nested_filter;
1414use rustc_middle:: ty:: adjustment:: Adjust ;
1515use 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+ }
1684
1785/// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested
1886/// bodies (i.e. closures) are visited.
0 commit comments