]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/utils/visitors.rs
Use `summary_opts()` in another spot
[rust.git] / src / tools / clippy / clippy_lints / src / utils / visitors.rs
1 use rustc_hir as hir;
2 use rustc_hir::intravisit::{self, Visitor};
3 use rustc_lint::LateContext;
4 use rustc_middle::hir::map::Map;
5
6 /// returns `true` if expr contains match expr desugared from try
7 fn contains_try(expr: &hir::Expr<'_>) -> bool {
8     struct TryFinder {
9         found: bool,
10     }
11
12     impl<'hir> intravisit::Visitor<'hir> for TryFinder {
13         type Map = Map<'hir>;
14
15         fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
16             intravisit::NestedVisitorMap::None
17         }
18
19         fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
20             if self.found {
21                 return;
22             }
23             match expr.kind {
24                 hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true,
25                 _ => intravisit::walk_expr(self, expr),
26             }
27         }
28     }
29
30     let mut visitor = TryFinder { found: false };
31     visitor.visit_expr(expr);
32     visitor.found
33 }
34
35 pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
36 where
37     F: FnMut(&'hir hir::Expr<'hir>) -> bool,
38 {
39     struct RetFinder<F> {
40         in_stmt: bool,
41         failed: bool,
42         cb: F,
43     }
44
45     struct WithStmtGuarg<'a, F> {
46         val: &'a mut RetFinder<F>,
47         prev_in_stmt: bool,
48     }
49
50     impl<F> RetFinder<F> {
51         fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
52             let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
53             WithStmtGuarg {
54                 val: self,
55                 prev_in_stmt,
56             }
57         }
58     }
59
60     impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
61         type Target = RetFinder<F>;
62
63         fn deref(&self) -> &Self::Target {
64             self.val
65         }
66     }
67
68     impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
69         fn deref_mut(&mut self) -> &mut Self::Target {
70             self.val
71         }
72     }
73
74     impl<F> Drop for WithStmtGuarg<'_, F> {
75         fn drop(&mut self) {
76             self.val.in_stmt = self.prev_in_stmt;
77         }
78     }
79
80     impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
81         type Map = Map<'hir>;
82
83         fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
84             intravisit::NestedVisitorMap::None
85         }
86
87         fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
88             intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
89         }
90
91         fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
92             if self.failed {
93                 return;
94             }
95             if self.in_stmt {
96                 match expr.kind {
97                     hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
98                     _ => intravisit::walk_expr(self, expr),
99                 }
100             } else {
101                 match expr.kind {
102                     hir::ExprKind::Match(cond, arms, _) => {
103                         self.inside_stmt(true).visit_expr(cond);
104                         for arm in arms {
105                             self.visit_expr(arm.body);
106                         }
107                     },
108                     hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr),
109                     hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
110                     _ => self.failed |= !(self.cb)(expr),
111                 }
112             }
113         }
114     }
115
116     !contains_try(expr) && {
117         let mut ret_finder = RetFinder {
118             in_stmt: false,
119             failed: false,
120             cb: callback,
121         };
122         ret_finder.visit_expr(expr);
123         !ret_finder.failed
124     }
125 }