1 use crate::path_to_local_id
;
3 use rustc_hir
::intravisit
::{self, walk_expr, ErasedMap, NestedVisitorMap, Visitor}
;
4 use rustc_hir
::{def::Res, Arm, Block, Body, BodyId, Destination, Expr, ExprKind, HirId, Stmt}
;
5 use rustc_lint
::LateContext
;
6 use rustc_middle
::hir
::map
::Map
;
7 use std
::ops
::ControlFlow
;
9 /// returns `true` if expr contains match expr desugared from try
10 fn contains_try(expr
: &hir
::Expr
<'_
>) -> bool
{
15 impl<'hir
> intravisit
::Visitor
<'hir
> for TryFinder
{
18 fn nested_visit_map(&mut self) -> intravisit
::NestedVisitorMap
<Self::Map
> {
19 intravisit
::NestedVisitorMap
::None
22 fn visit_expr(&mut self, expr
: &'hir hir
::Expr
<'hir
>) {
27 hir
::ExprKind
::Match(_
, _
, hir
::MatchSource
::TryDesugar
) => self.found
= true,
28 _
=> intravisit
::walk_expr(self, expr
),
33 let mut visitor
= TryFinder { found: false }
;
34 visitor
.visit_expr(expr
);
38 pub fn find_all_ret_expressions
<'hir
, F
>(_cx
: &LateContext
<'_
>, expr
: &'hir hir
::Expr
<'hir
>, callback
: F
) -> bool
40 F
: FnMut(&'hir hir
::Expr
<'hir
>) -> bool
,
48 struct WithStmtGuarg
<'a
, F
> {
49 val
: &'a
mut RetFinder
<F
>,
53 impl<F
> RetFinder
<F
> {
54 fn inside_stmt(&mut self, in_stmt
: bool
) -> WithStmtGuarg
<'_
, F
> {
55 let prev_in_stmt
= std
::mem
::replace(&mut self.in_stmt
, in_stmt
);
63 impl<F
> std
::ops
::Deref
for WithStmtGuarg
<'_
, F
> {
64 type Target
= RetFinder
<F
>;
66 fn deref(&self) -> &Self::Target
{
71 impl<F
> std
::ops
::DerefMut
for WithStmtGuarg
<'_
, F
> {
72 fn deref_mut(&mut self) -> &mut Self::Target
{
77 impl<F
> Drop
for WithStmtGuarg
<'_
, F
> {
79 self.val
.in_stmt
= self.prev_in_stmt
;
83 impl<'hir
, F
: FnMut(&'hir hir
::Expr
<'hir
>) -> bool
> intravisit
::Visitor
<'hir
> for RetFinder
<F
> {
86 fn nested_visit_map(&mut self) -> intravisit
::NestedVisitorMap
<Self::Map
> {
87 intravisit
::NestedVisitorMap
::None
90 fn visit_stmt(&mut self, stmt
: &'hir hir
::Stmt
<'_
>) {
91 intravisit
::walk_stmt(&mut *self.inside_stmt(true), stmt
);
94 fn visit_expr(&mut self, expr
: &'hir hir
::Expr
<'_
>) {
100 hir
::ExprKind
::Ret(Some(expr
)) => self.inside_stmt(false).visit_expr(expr
),
101 _
=> intravisit
::walk_expr(self, expr
),
105 hir
::ExprKind
::If(cond
, then
, else_opt
) => {
106 self.inside_stmt(true).visit_expr(cond
);
107 self.visit_expr(then
);
108 if let Some(el
) = else_opt
{
112 hir
::ExprKind
::Match(cond
, arms
, _
) => {
113 self.inside_stmt(true).visit_expr(cond
);
115 self.visit_expr(arm
.body
);
118 hir
::ExprKind
::Block(..) => intravisit
::walk_expr(self, expr
),
119 hir
::ExprKind
::Ret(Some(expr
)) => self.visit_expr(expr
),
120 _
=> self.failed
|= !(self.cb
)(expr
),
126 !contains_try(expr
) && {
127 let mut ret_finder
= RetFinder
{
132 ret_finder
.visit_expr(expr
);
137 /// A type which can be visited.
138 pub trait Visitable
<'tcx
> {
139 /// Calls the corresponding `visit_*` function on the visitor.
140 fn visit
<V
: Visitor
<'tcx
>>(self, visitor
: &mut V
);
142 macro_rules
! visitable_ref
{
143 ($t
:ident
, $f
:ident
) => {
144 impl Visitable
<'tcx
> for &'tcx $t
<'tcx
> {
145 fn visit
<V
: Visitor
<'tcx
>>(self, visitor
: &mut V
) {
151 visitable_ref
!(Arm
, visit_arm
);
152 visitable_ref
!(Block
, visit_block
);
153 visitable_ref
!(Body
, visit_body
);
154 visitable_ref
!(Expr
, visit_expr
);
155 visitable_ref
!(Stmt
, visit_stmt
);
157 // impl<'tcx, I: IntoIterator> Visitable<'tcx> for I
159 // I::Item: Visitable<'tcx>,
161 // fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
168 /// Calls the given function for each break expression.
169 pub fn visit_break_exprs
<'tcx
>(
170 node
: impl Visitable
<'tcx
>,
171 f
: impl FnMut(&'tcx Expr
<'tcx
>, Destination
, Option
<&'tcx Expr
<'tcx
>>),
174 impl<'tcx
, F
: FnMut(&'tcx Expr
<'tcx
>, Destination
, Option
<&'tcx Expr
<'tcx
>>)> Visitor
<'tcx
> for V
<F
> {
175 type Map
= ErasedMap
<'tcx
>;
176 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
177 NestedVisitorMap
::None
180 fn visit_expr(&mut self, e
: &'tcx Expr
<'_
>) {
181 if let ExprKind
::Break(dest
, sub_expr
) = e
.kind
{
182 self.0(e
, dest
, sub_expr
);
188 node
.visit(&mut V(f
));
191 /// Checks if the given resolved path is used in the given body.
192 pub fn is_res_used(cx
: &LateContext
<'_
>, res
: Res
, body
: BodyId
) -> bool
{
194 cx
: &'a LateContext
<'tcx
>,
198 impl Visitor
<'tcx
> for V
<'_
, 'tcx
> {
199 type Map
= Map
<'tcx
>;
200 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
201 NestedVisitorMap
::OnlyBodies(self.cx
.tcx
.hir())
204 fn visit_expr(&mut self, e
: &'tcx Expr
<'_
>) {
209 if let ExprKind
::Path(p
) = &e
.kind
{
210 if self.cx
.qpath_res(p
, e
.hir_id
) == self.res
{
219 let mut v
= V { cx, res, found: false }
;
220 v
.visit_expr(&cx
.tcx
.hir().body(body
).value
);
224 /// Calls the given function for each usage of the given local.
225 pub fn for_each_local_usage
<'tcx
, B
>(
226 cx
: &LateContext
<'tcx
>,
227 visitable
: impl Visitable
<'tcx
>,
229 f
: impl FnMut(&'tcx Expr
<'tcx
>) -> ControlFlow
<B
>,
230 ) -> ControlFlow
<B
> {
231 struct V
<'tcx
, B
, F
> {
237 impl<'tcx
, B
, F
: FnMut(&'tcx Expr
<'tcx
>) -> ControlFlow
<B
>> Visitor
<'tcx
> for V
<'tcx
, B
, F
> {
238 type Map
= Map
<'tcx
>;
239 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
240 NestedVisitorMap
::OnlyBodies(self.map
)
243 fn visit_expr(&mut self, e
: &'tcx Expr
<'_
>) {
244 if self.res
.is_continue() {
245 if path_to_local_id(e
, self.id
) {
246 self.res
= (self.f
)(e
);
258 res
: ControlFlow
::CONTINUE
,
260 visitable
.visit(&mut v
);
264 /// Checks if the given local is used.
265 pub fn is_local_used(cx
: &LateContext
<'tcx
>, visitable
: impl Visitable
<'tcx
>, id
: HirId
) -> bool
{
266 for_each_local_usage(cx
, visitable
, id
, |_
| ControlFlow
::BREAK
).is_break()