@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
8
8
use rustc_hir::def::{DefKind, Res};
9
9
use rustc_hir::def_id::DefId;
10
10
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
11
- use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
11
+ use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor};
12
12
use rustc_hir::{
13
13
Arm, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment,
14
14
QPath, Stmt, StmtKind, TyKind, UnOp,
@@ -145,7 +145,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
145
145
is_method: matches!(kind, FnKind::Method(..)),
146
146
has_self,
147
147
ty_res,
148
- ty_ctx: cx.tcx,
148
+ tcx: cx.tcx,
149
+ visited_exprs: FxHashSet::default(),
149
150
};
150
151
151
152
visitor.visit_expr(&body.value);
@@ -206,19 +207,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
206
207
}
207
208
208
209
pub fn is_primitive(ty: Ty<'_>) -> bool {
209
- match ty.kind() {
210
- ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
211
- ty::Ref(_, t, _) => is_primitive(*t),
212
- _ => false,
213
- }
210
+ let ty = ty.peel_refs();
211
+ ty.is_primitive() || ty.is_str()
214
212
}
215
213
216
214
pub fn is_array(ty: Ty<'_>) -> bool {
217
- match ty.kind() {
218
- ty::Array(..) | ty::Slice(..) => true,
219
- ty::Ref(_, t, _) => is_array(*t),
220
- _ => false,
221
- }
215
+ let ty = ty.peel_refs();
216
+ ty.is_array() || ty.is_array_slice()
222
217
}
223
218
224
219
/// This builds the graph of side effect.
@@ -250,40 +245,30 @@ pub struct SideEffectVisit<'tcx> {
250
245
is_method: bool,
251
246
has_self: bool,
252
247
ty_res: &'tcx TypeckResults<'tcx>,
253
- ty_ctx: TyCtxt<'tcx>,
248
+ tcx: TyCtxt<'tcx>,
249
+ visited_exprs: FxHashSet<HirId>,
254
250
}
255
251
256
252
impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
257
- fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
258
- b.stmts.iter().for_each(|stmt| {
259
- self.visit_stmt(stmt);
260
- self.ret_vars.clear();
261
- });
262
- walk_list!(self, visit_expr, b.expr);
263
- }
264
-
265
253
fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
266
254
match s.kind {
267
255
StmtKind::Local(Local {
268
256
pat, init: Some(init), ..
269
257
}) => {
270
258
self.visit_pat_expr(pat, init, false);
271
- self.ret_vars.clear();
272
259
},
273
- StmtKind::Item(i) => {
274
- let item = self.ty_ctx.hir().item(i);
275
- self.visit_item(item);
276
- self.ret_vars.clear();
277
- },
278
- StmtKind::Expr(e) | StmtKind::Semi(e) => {
279
- self.visit_expr(e);
280
- self.ret_vars.clear();
260
+ StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => {
261
+ walk_stmt(self, s);
281
262
},
282
263
StmtKind::Local(_) => {},
283
264
}
265
+ self.ret_vars.clear();
284
266
}
285
267
286
268
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
269
+ if !self.visited_exprs.insert(ex.hir_id) {
270
+ return;
271
+ }
287
272
match ex.kind {
288
273
ExprKind::Array(exprs) | ExprKind::Tup(exprs) => {
289
274
self.ret_vars = exprs
@@ -307,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
307
292
ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
308
293
// since analysing the closure is not easy, just set all variables in it to side-effect
309
294
ExprKind::Closure(_, _, body_id, _, _) => {
310
- let body = self.ty_ctx .hir().body(body_id);
295
+ let body = self.tcx .hir().body(body_id);
311
296
self.visit_body(body);
312
297
let vars = std::mem::take(&mut self.ret_vars);
313
298
self.add_side_effect(vars);
0 commit comments