]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/utils/visitors.rs
Rollup merge of #81588 - xfix:delete-doc-alias, r=Mark-Simulacrum
[rust.git] / src / tools / clippy / clippy_lints / src / utils / visitors.rs
1 use rustc_hir as hir;
2 use rustc_hir::def::Res;
3 use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor};
4 use rustc_hir::{Arm, Expr, ExprKind, HirId, QPath, Stmt};
5 use rustc_lint::LateContext;
6 use rustc_middle::hir::map::Map;
7
8 /// returns `true` if expr contains match expr desugared from try
9 fn contains_try(expr: &hir::Expr<'_>) -> bool {
10     struct TryFinder {
11         found: bool,
12     }
13
14     impl<'hir> intravisit::Visitor<'hir> for TryFinder {
15         type Map = Map<'hir>;
16
17         fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
18             intravisit::NestedVisitorMap::None
19         }
20
21         fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
22             if self.found {
23                 return;
24             }
25             match expr.kind {
26                 hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true,
27                 _ => intravisit::walk_expr(self, expr),
28             }
29         }
30     }
31
32     let mut visitor = TryFinder { found: false };
33     visitor.visit_expr(expr);
34     visitor.found
35 }
36
37 pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool
38 where
39     F: FnMut(&'hir hir::Expr<'hir>) -> bool,
40 {
41     struct RetFinder<F> {
42         in_stmt: bool,
43         failed: bool,
44         cb: F,
45     }
46
47     struct WithStmtGuarg<'a, F> {
48         val: &'a mut RetFinder<F>,
49         prev_in_stmt: bool,
50     }
51
52     impl<F> RetFinder<F> {
53         fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> {
54             let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt);
55             WithStmtGuarg {
56                 val: self,
57                 prev_in_stmt,
58             }
59         }
60     }
61
62     impl<F> std::ops::Deref for WithStmtGuarg<'_, F> {
63         type Target = RetFinder<F>;
64
65         fn deref(&self) -> &Self::Target {
66             self.val
67         }
68     }
69
70     impl<F> std::ops::DerefMut for WithStmtGuarg<'_, F> {
71         fn deref_mut(&mut self) -> &mut Self::Target {
72             self.val
73         }
74     }
75
76     impl<F> Drop for WithStmtGuarg<'_, F> {
77         fn drop(&mut self) {
78             self.val.in_stmt = self.prev_in_stmt;
79         }
80     }
81
82     impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
83         type Map = Map<'hir>;
84
85         fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
86             intravisit::NestedVisitorMap::None
87         }
88
89         fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
90             intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
91         }
92
93         fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
94             if self.failed {
95                 return;
96             }
97             if self.in_stmt {
98                 match expr.kind {
99                     hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr),
100                     _ => intravisit::walk_expr(self, expr),
101                 }
102             } else {
103                 match expr.kind {
104                     hir::ExprKind::If(cond, then, else_opt) => {
105                         self.inside_stmt(true).visit_expr(cond);
106                         self.visit_expr(then);
107                         if let Some(el) = else_opt {
108                             self.visit_expr(el);
109                         }
110                     },
111                     hir::ExprKind::Match(cond, arms, _) => {
112                         self.inside_stmt(true).visit_expr(cond);
113                         for arm in arms {
114                             self.visit_expr(arm.body);
115                         }
116                     },
117                     hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr),
118                     hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr),
119                     _ => self.failed |= !(self.cb)(expr),
120                 }
121             }
122         }
123     }
124
125     !contains_try(expr) && {
126         let mut ret_finder = RetFinder {
127             in_stmt: false,
128             failed: false,
129             cb: callback,
130         };
131         ret_finder.visit_expr(expr);
132         !ret_finder.failed
133     }
134 }
135
136 pub struct LocalUsedVisitor {
137     pub local_hir_id: HirId,
138     pub used: bool,
139 }
140
141 impl LocalUsedVisitor {
142     pub fn new(local_hir_id: HirId) -> Self {
143         Self {
144             local_hir_id,
145             used: false,
146         }
147     }
148
149     fn check<T>(&mut self, t: T, visit: fn(&mut Self, T)) -> bool {
150         visit(self, t);
151         std::mem::replace(&mut self.used, false)
152     }
153
154     pub fn check_arm(&mut self, arm: &Arm<'_>) -> bool {
155         self.check(arm, Self::visit_arm)
156     }
157
158     pub fn check_expr(&mut self, expr: &Expr<'_>) -> bool {
159         self.check(expr, Self::visit_expr)
160     }
161
162     pub fn check_stmt(&mut self, stmt: &Stmt<'_>) -> bool {
163         self.check(stmt, Self::visit_stmt)
164     }
165 }
166
167 impl<'v> Visitor<'v> for LocalUsedVisitor {
168     type Map = Map<'v>;
169
170     fn visit_expr(&mut self, expr: &'v Expr<'v>) {
171         if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
172             if let Res::Local(id) = path.res {
173                 if id == self.local_hir_id {
174                     self.used = true;
175                     return;
176                 }
177             }
178         }
179         walk_expr(self, expr);
180     }
181
182     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
183         NestedVisitorMap::None
184     }
185 }