|
1 | 1 | use crate as utils; |
| 2 | +use crate::visitors::{expr_visitor, expr_visitor_no_bodies}; |
2 | 3 | use rustc_hir as hir; |
3 | | -use rustc_hir::intravisit; |
4 | | -use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; |
| 4 | +use rustc_hir::intravisit::{self, Visitor}; |
5 | 5 | use rustc_hir::HirIdSet; |
6 | 6 | use rustc_hir::{Expr, ExprKind, HirId}; |
7 | 7 | use rustc_infer::infer::TyCtxtInferExt; |
@@ -148,96 +148,47 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { |
148 | 148 | } |
149 | 149 | } |
150 | 150 |
|
151 | | -struct ReturnBreakContinueMacroVisitor { |
152 | | - seen_return_break_continue: bool, |
153 | | -} |
154 | | - |
155 | | -impl ReturnBreakContinueMacroVisitor { |
156 | | - fn new() -> ReturnBreakContinueMacroVisitor { |
157 | | - ReturnBreakContinueMacroVisitor { |
158 | | - seen_return_break_continue: false, |
159 | | - } |
160 | | - } |
161 | | -} |
162 | | - |
163 | | -impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor { |
164 | | - type Map = Map<'tcx>; |
165 | | - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
166 | | - NestedVisitorMap::None |
167 | | - } |
168 | | - |
169 | | - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { |
170 | | - if self.seen_return_break_continue { |
171 | | - // No need to look farther if we've already seen one of them |
172 | | - return; |
| 151 | +pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { |
| 152 | + let mut seen_return_break_continue = false; |
| 153 | + expr_visitor_no_bodies(|ex| { |
| 154 | + if seen_return_break_continue { |
| 155 | + return false; |
173 | 156 | } |
174 | 157 | match &ex.kind { |
175 | 158 | ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => { |
176 | | - self.seen_return_break_continue = true; |
| 159 | + seen_return_break_continue = true; |
177 | 160 | }, |
178 | 161 | // Something special could be done here to handle while or for loop |
179 | 162 | // desugaring, as this will detect a break if there's a while loop |
180 | 163 | // or a for loop inside the expression. |
181 | 164 | _ => { |
182 | 165 | if ex.span.from_expansion() { |
183 | | - self.seen_return_break_continue = true; |
184 | | - } else { |
185 | | - rustc_hir::intravisit::walk_expr(self, ex); |
| 166 | + seen_return_break_continue = true; |
186 | 167 | } |
187 | 168 | }, |
188 | 169 | } |
189 | | - } |
190 | | -} |
191 | | - |
192 | | -pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool { |
193 | | - let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new(); |
194 | | - recursive_visitor.visit_expr(expression); |
195 | | - recursive_visitor.seen_return_break_continue |
196 | | -} |
197 | | - |
198 | | -pub struct UsedAfterExprVisitor<'a, 'tcx> { |
199 | | - cx: &'a LateContext<'tcx>, |
200 | | - expr: &'tcx Expr<'tcx>, |
201 | | - definition: HirId, |
202 | | - past_expr: bool, |
203 | | - used_after_expr: bool, |
204 | | -} |
205 | | -impl<'a, 'tcx> UsedAfterExprVisitor<'a, 'tcx> { |
206 | | - pub fn is_found(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { |
207 | | - utils::path_to_local(expr).map_or(false, |definition| { |
208 | | - let mut visitor = UsedAfterExprVisitor { |
209 | | - cx, |
210 | | - expr, |
211 | | - definition, |
212 | | - past_expr: false, |
213 | | - used_after_expr: false, |
214 | | - }; |
215 | | - utils::get_enclosing_block(cx, definition).map_or(false, |block| { |
216 | | - visitor.visit_block(block); |
217 | | - visitor.used_after_expr |
218 | | - }) |
219 | | - }) |
220 | | - } |
221 | | -} |
222 | | - |
223 | | -impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedAfterExprVisitor<'a, 'tcx> { |
224 | | - type Map = Map<'tcx>; |
225 | | - |
226 | | - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
227 | | - NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) |
228 | | - } |
229 | | - |
230 | | - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { |
231 | | - if self.used_after_expr { |
232 | | - return; |
| 170 | + !seen_return_break_continue |
| 171 | + }) |
| 172 | + .visit_expr(expression); |
| 173 | + seen_return_break_continue |
| 174 | +} |
| 175 | + |
| 176 | +pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool { |
| 177 | + let Some(block) = utils::get_enclosing_block(cx, local_id) else { return false }; |
| 178 | + let mut used_after_expr = false; |
| 179 | + let mut past_expr = false; |
| 180 | + expr_visitor(cx, |expr| { |
| 181 | + if used_after_expr { |
| 182 | + return false; |
233 | 183 | } |
234 | 184 |
|
235 | | - if expr.hir_id == self.expr.hir_id { |
236 | | - self.past_expr = true; |
237 | | - } else if self.past_expr && utils::path_to_local_id(expr, self.definition) { |
238 | | - self.used_after_expr = true; |
239 | | - } else { |
240 | | - intravisit::walk_expr(self, expr); |
| 185 | + if expr.hir_id == after.hir_id { |
| 186 | + past_expr = true; |
| 187 | + } else if past_expr && utils::path_to_local_id(expr, local_id) { |
| 188 | + used_after_expr = true; |
241 | 189 | } |
242 | | - } |
| 190 | + !used_after_expr |
| 191 | + }) |
| 192 | + .visit_block(block); |
| 193 | + used_after_expr |
243 | 194 | } |
0 commit comments