@@ -4,6 +4,7 @@ use rustc_hir::intravisit::{self, walk_expr, ErasedMap, NestedVisitorMap, Visito
44use rustc_hir:: { def:: Res , Arm , Block , Body , BodyId , Destination , Expr , ExprKind , HirId , Stmt } ;
55use rustc_lint:: LateContext ;
66use rustc_middle:: hir:: map:: Map ;
7+ use std:: ops:: ControlFlow ;
78
89/// returns `true` if expr contains match expr desugared from try
910fn contains_try ( expr : & hir:: Expr < ' _ > ) -> bool {
@@ -133,62 +134,6 @@ where
133134 }
134135}
135136
136- pub struct LocalUsedVisitor < ' hir > {
137- hir : Map < ' hir > ,
138- pub local_hir_id : HirId ,
139- pub used : bool ,
140- }
141-
142- impl < ' hir > LocalUsedVisitor < ' hir > {
143- pub fn new ( cx : & LateContext < ' hir > , local_hir_id : HirId ) -> Self {
144- Self {
145- hir : cx. tcx . hir ( ) ,
146- local_hir_id,
147- used : false ,
148- }
149- }
150-
151- fn check < T > ( & mut self , t : T , visit : fn ( & mut Self , T ) ) -> bool {
152- visit ( self , t) ;
153- std:: mem:: replace ( & mut self . used , false )
154- }
155-
156- pub fn check_arm ( & mut self , arm : & ' hir Arm < ' _ > ) -> bool {
157- self . check ( arm, Self :: visit_arm)
158- }
159-
160- pub fn check_body ( & mut self , body : & ' hir Body < ' _ > ) -> bool {
161- self . check ( body, Self :: visit_body)
162- }
163-
164- pub fn check_expr ( & mut self , expr : & ' hir Expr < ' _ > ) -> bool {
165- self . check ( expr, Self :: visit_expr)
166- }
167-
168- pub fn check_stmt ( & mut self , stmt : & ' hir Stmt < ' _ > ) -> bool {
169- self . check ( stmt, Self :: visit_stmt)
170- }
171- }
172-
173- impl < ' v > Visitor < ' v > for LocalUsedVisitor < ' v > {
174- type Map = Map < ' v > ;
175-
176- fn visit_expr ( & mut self , expr : & ' v Expr < ' v > ) {
177- if self . used {
178- return ;
179- }
180- if path_to_local_id ( expr, self . local_hir_id ) {
181- self . used = true ;
182- } else {
183- walk_expr ( self , expr) ;
184- }
185- }
186-
187- fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
188- NestedVisitorMap :: OnlyBodies ( self . hir )
189- }
190- }
191-
192137/// A type which can be visited.
193138pub trait Visitable < ' tcx > {
194139 /// Calls the corresponding `visit_*` function on the visitor.
@@ -202,8 +147,22 @@ macro_rules! visitable_ref {
202147 }
203148 }
204149 } ;
150+ ( [ $t: ident] , $f: ident) => {
151+ impl Visitable <' tcx> for & ' tcx [ $t<' tcx>] {
152+ fn visit<V : Visitor <' tcx>>( self , visitor: & mut V ) {
153+ for x in self {
154+ visitor. $f( x) ;
155+ }
156+ }
157+ }
158+ } ;
205159}
160+ visitable_ref ! ( Arm , visit_arm) ;
206161visitable_ref ! ( Block , visit_block) ;
162+ visitable_ref ! ( Body , visit_body) ;
163+ visitable_ref ! ( Expr , visit_expr) ;
164+ visitable_ref ! ( Stmt , visit_stmt) ;
165+ visitable_ref ! ( [ Stmt ] , visit_stmt) ;
207166
208167/// Calls the given function for each break expression.
209168pub fn visit_break_exprs < ' tcx > (
@@ -260,3 +219,48 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
260219 v. visit_expr ( & cx. tcx . hir ( ) . body ( body) . value ) ;
261220 v. found
262221}
222+
223+ /// Calls the given function for each usage of the given local.
224+ pub fn for_each_local_usage < ' tcx , B > (
225+ cx : & LateContext < ' tcx > ,
226+ visitable : impl Visitable < ' tcx > ,
227+ id : HirId ,
228+ f : impl FnMut ( & ' tcx Expr < ' tcx > ) -> ControlFlow < B > ,
229+ ) -> ControlFlow < B > {
230+ struct V < ' tcx , B , F > {
231+ map : Map < ' tcx > ,
232+ id : HirId ,
233+ f : F ,
234+ res : ControlFlow < B > ,
235+ }
236+ impl < ' tcx , B , F : FnMut ( & ' tcx Expr < ' tcx > ) -> ControlFlow < B > > Visitor < ' tcx > for V < ' tcx , B , F > {
237+ type Map = Map < ' tcx > ;
238+ fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
239+ NestedVisitorMap :: OnlyBodies ( self . map )
240+ }
241+
242+ fn visit_expr ( & mut self , e : & ' tcx Expr < ' _ > ) {
243+ if self . res . is_continue ( ) {
244+ if path_to_local_id ( e, self . id ) {
245+ self . res = ( self . f ) ( e) ;
246+ } else {
247+ walk_expr ( self , e) ;
248+ }
249+ }
250+ }
251+ }
252+
253+ let mut v = V {
254+ map : cx. tcx . hir ( ) ,
255+ id,
256+ f,
257+ res : ControlFlow :: CONTINUE ,
258+ } ;
259+ visitable. visit ( & mut v) ;
260+ v. res
261+ }
262+
263+ /// Checks if the given local is used.
264+ pub fn is_local_used ( cx : & LateContext < ' tcx > , visitable : impl Visitable < ' tcx > , id : HirId ) -> bool {
265+ for_each_local_usage ( cx, visitable, id, |_| ControlFlow :: BREAK ) . is_break ( )
266+ }
0 commit comments