rapx/check/opt/
loop_visitors.rs1use rustc_hir::{Expr, ExprKind, intravisit};
2use rustc_middle::ty::TypeckResults;
3use rustc_span::Span;
4
5pub struct LoopFinder<'tcx> {
6 pub typeck_results: &'tcx TypeckResults<'tcx>,
7 pub record: Vec<(Span, Vec<Span>)>,
8 pub target_def_id: rustc_span::def_id::DefId,
9}
10
11pub struct MethodCallFinder<'tcx> {
12 typeck_results: &'tcx TypeckResults<'tcx>,
13 record: Vec<Span>,
14 target_def_id: rustc_span::def_id::DefId,
15}
16
17impl<'tcx> MethodCallFinder<'tcx> {
18 pub fn new(
19 typeck_results: &'tcx TypeckResults<'tcx>,
20 target_def_id: rustc_span::def_id::DefId,
21 ) -> MethodCallFinder<'tcx> {
22 MethodCallFinder {
23 typeck_results,
24 record: Vec::new(),
25 target_def_id,
26 }
27 }
28
29 pub fn into_record(self) -> Vec<Span> {
30 self.record
31 }
32}
33
34impl<'tcx> LoopFinder<'tcx> {
35 pub fn new(
36 typeck_results: &'tcx TypeckResults<'tcx>,
37 target_def_id: rustc_span::def_id::DefId,
38 ) -> LoopFinder<'tcx> {
39 LoopFinder {
40 typeck_results,
41 record: Vec::new(),
42 target_def_id,
43 }
44 }
45
46 pub fn into_record(self) -> Vec<(Span, Vec<Span>)> {
47 self.record
48 }
49}
50
51impl<'tcx> intravisit::Visitor<'tcx> for MethodCallFinder<'tcx> {
52 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
53 if let ExprKind::MethodCall(.., span) = ex.kind {
54 let def_id = self
55 .typeck_results
56 .type_dependent_def_id(ex.hir_id)
57 .unwrap();
58 if def_id == self.target_def_id {
59 self.record.push(span);
60 }
61 }
62 intravisit::walk_expr(self, ex);
63 }
64}
65
66impl<'tcx> intravisit::Visitor<'tcx> for LoopFinder<'tcx> {
67 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
68 if let ExprKind::Loop(block, ..) = ex.kind {
69 let mut push_finder = MethodCallFinder::new(self.typeck_results, self.target_def_id);
70 intravisit::walk_block(&mut push_finder, block);
71 if push_finder.record.len() == 1 {
72 self.record.push((ex.span, push_finder.into_record()));
73 }
74 }
75 intravisit::walk_expr(self, ex);
76 }
77}