Skip to content

Commit 096a7ca

Browse files
flip1995Mark-Simulacrum
authored andcommitted
Prevent infinite (exponential) recursion in only_used_in_recursion
This simplifies the visitor code a bit and prevents checking expressions multiple times. I still think this lint should be removed for now, because its code isn't really tested.
1 parent 6db7d1b commit 096a7ca

File tree

1 file changed

+16
-31
lines changed

1 file changed

+16
-31
lines changed

src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs

+16-31
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
88
use rustc_hir::def::{DefKind, Res};
99
use rustc_hir::def_id::DefId;
1010
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};
1212
use rustc_hir::{
1313
Arm, Block, Body, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, PathSegment,
1414
QPath, Stmt, StmtKind, TyKind, UnOp,
@@ -145,7 +145,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
145145
is_method: matches!(kind, FnKind::Method(..)),
146146
has_self,
147147
ty_res,
148-
ty_ctx: cx.tcx,
148+
tcx: cx.tcx,
149+
visited_exprs: FxHashSet::default(),
149150
};
150151

151152
visitor.visit_expr(&body.value);
@@ -206,19 +207,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
206207
}
207208

208209
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()
214212
}
215213

216214
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()
222217
}
223218

224219
/// This builds the graph of side effect.
@@ -250,40 +245,30 @@ pub struct SideEffectVisit<'tcx> {
250245
is_method: bool,
251246
has_self: bool,
252247
ty_res: &'tcx TypeckResults<'tcx>,
253-
ty_ctx: TyCtxt<'tcx>,
248+
tcx: TyCtxt<'tcx>,
249+
visited_exprs: FxHashSet<HirId>,
254250
}
255251

256252
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-
265253
fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
266254
match s.kind {
267255
StmtKind::Local(Local {
268256
pat, init: Some(init), ..
269257
}) => {
270258
self.visit_pat_expr(pat, init, false);
271-
self.ret_vars.clear();
272259
},
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);
281262
},
282263
StmtKind::Local(_) => {},
283264
}
265+
self.ret_vars.clear();
284266
}
285267

286268
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
269+
if !self.visited_exprs.insert(ex.hir_id) {
270+
return;
271+
}
287272
match ex.kind {
288273
ExprKind::Array(exprs) | ExprKind::Tup(exprs) => {
289274
self.ret_vars = exprs
@@ -307,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
307292
ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
308293
// since analysing the closure is not easy, just set all variables in it to side-effect
309294
ExprKind::Closure(_, _, body_id, _, _) => {
310-
let body = self.ty_ctx.hir().body(body_id);
295+
let body = self.tcx.hir().body(body_id);
311296
self.visit_body(body);
312297
let vars = std::mem::take(&mut self.ret_vars);
313298
self.add_side_effect(vars);

0 commit comments

Comments
 (0)