Skip to content

Commit 1d30422

Browse files
committed
Enhance LocalUsedVisitor to check closure bodies
1 parent 4bbd7e4 commit 1d30422

File tree

6 files changed

+45
-26
lines changed

6 files changed

+45
-26
lines changed

clippy_lints/src/collapsible_match.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch {
6060
}
6161
}
6262

63-
fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
63+
fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext<'tcx>) {
6464
if_chain! {
6565
let expr = strip_singleton_blocks(arm.body);
6666
if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind;
@@ -84,14 +84,13 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
8484
// the "wild-like" branches must be equal
8585
if SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, wild_outer_arm.body);
8686
// the binding must not be used in the if guard
87+
let mut used_visitor = LocalUsedVisitor::new(cx, binding_id);
8788
if match arm.guard {
8889
None => true,
89-
Some(Guard::If(expr) | Guard::IfLet(_, expr)) => {
90-
!LocalUsedVisitor::new(binding_id).check_expr(expr)
91-
}
90+
Some(Guard::If(expr) | Guard::IfLet(_, expr)) => !used_visitor.check_expr(expr),
9291
};
9392
// ...or anywhere in the inner match
94-
if !arms_inner.iter().any(|arm| LocalUsedVisitor::new(binding_id).check_arm(arm));
93+
if !arms_inner.iter().any(|arm| used_visitor.check_arm(arm));
9594
then {
9695
span_lint_and_then(
9796
cx,

clippy_lints/src/let_if_seq.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
6363
if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind;
6464
if let hir::StmtKind::Expr(ref if_) = expr.kind;
6565
if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind;
66-
if !LocalUsedVisitor::new(canonical_id).check_expr(cond);
66+
let mut used_visitor = LocalUsedVisitor::new(cx, canonical_id);
67+
if !used_visitor.check_expr(cond);
6768
if let hir::ExprKind::Block(ref then, _) = then.kind;
68-
if let Some(value) = check_assign(canonical_id, &*then);
69-
if !LocalUsedVisitor::new(canonical_id).check_expr(value);
69+
if let Some(value) = check_assign(cx, canonical_id, &*then);
70+
if !used_visitor.check_expr(value);
7071
then {
7172
let span = stmt.span.to(if_.span);
7273

@@ -78,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
7879

7980
let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
8081
if let hir::ExprKind::Block(ref else_, _) = else_.kind {
81-
if let Some(default) = check_assign(canonical_id, else_) {
82+
if let Some(default) = check_assign(cx, canonical_id, else_) {
8283
(else_.stmts.len() > 1, default)
8384
} else if let Some(ref default) = local.init {
8485
(true, &**default)
@@ -133,15 +134,19 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
133134
}
134135
}
135136

136-
fn check_assign<'tcx>(decl: hir::HirId, block: &'tcx hir::Block<'_>) -> Option<&'tcx hir::Expr<'tcx>> {
137+
fn check_assign<'tcx>(
138+
cx: &LateContext<'tcx>,
139+
decl: hir::HirId,
140+
block: &'tcx hir::Block<'_>,
141+
) -> Option<&'tcx hir::Expr<'tcx>> {
137142
if_chain! {
138143
if block.expr.is_none();
139144
if let Some(expr) = block.stmts.iter().last();
140145
if let hir::StmtKind::Semi(ref expr) = expr.kind;
141146
if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind;
142147
if path_to_local_id(var, decl);
143148
then {
144-
let mut v = LocalUsedVisitor::new(decl);
149+
let mut v = LocalUsedVisitor::new(cx, decl);
145150

146151
if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| v.check_stmt(stmt)) {
147152
return None;

clippy_lints/src/loops.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,8 +1893,8 @@ fn check_for_loop_over_map_kv<'tcx>(
18931893
let arg_span = arg.span;
18941894
let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() {
18951895
ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
1896-
(key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl),
1897-
(_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not),
1896+
(key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl),
1897+
(_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not),
18981898
_ => return,
18991899
},
19001900
_ => return,
@@ -2145,11 +2145,11 @@ fn check_for_mutation<'tcx>(
21452145
}
21462146

21472147
/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`.
2148-
fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
2148+
fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
21492149
match *pat {
21502150
PatKind::Wild => true,
21512151
PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => {
2152-
!LocalUsedVisitor::new(id).check_expr(body)
2152+
!LocalUsedVisitor::new(cx, id).check_expr(body)
21532153
},
21542154
_ => false,
21552155
}
@@ -2188,7 +2188,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
21882188
then {
21892189
let index_used_directly = path_to_local_id(idx, self.var);
21902190
let indexed_indirectly = {
2191-
let mut used_visitor = LocalUsedVisitor::new(self.var);
2191+
let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var);
21922192
walk_expr(&mut used_visitor, idx);
21932193
used_visitor.used
21942194
};

clippy_lints/src/matches.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms
911911
}
912912
}
913913

914-
fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
914+
fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
915915
let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
916916
if is_type_diagnostic_item(cx, ex_ty, sym::result_type) {
917917
for arm in arms {
@@ -924,7 +924,9 @@ fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
924924
// Looking for unused bindings (i.e.: `_e`)
925925
inner.iter().for_each(|pat| {
926926
if let PatKind::Binding(_, id, ident, None) = pat.kind {
927-
if ident.as_str().starts_with('_') && !LocalUsedVisitor::new(id).check_expr(arm.body) {
927+
if ident.as_str().starts_with('_')
928+
&& !LocalUsedVisitor::new(cx, id).check_expr(arm.body)
929+
{
928930
ident_bind_name = (&ident.name.as_str()).to_string();
929931
matching_wild = true;
930932
}

clippy_lints/src/utils/visitors.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,16 @@ where
133133
}
134134
}
135135

136-
pub struct LocalUsedVisitor {
136+
pub struct LocalUsedVisitor<'hir> {
137+
hir: Map<'hir>,
137138
pub local_hir_id: HirId,
138139
pub used: bool,
139140
}
140141

141-
impl LocalUsedVisitor {
142-
pub fn new(local_hir_id: HirId) -> Self {
142+
impl<'hir> LocalUsedVisitor<'hir> {
143+
pub fn new(cx: &LateContext<'hir>, local_hir_id: HirId) -> Self {
143144
Self {
145+
hir: cx.tcx.hir(),
144146
local_hir_id,
145147
used: false,
146148
}
@@ -151,23 +153,26 @@ impl LocalUsedVisitor {
151153
std::mem::replace(&mut self.used, false)
152154
}
153155

154-
pub fn check_arm(&mut self, arm: &Arm<'_>) -> bool {
156+
pub fn check_arm(&mut self, arm: &'hir Arm<'_>) -> bool {
155157
self.check(arm, Self::visit_arm)
156158
}
157159

158-
pub fn check_expr(&mut self, expr: &Expr<'_>) -> bool {
160+
pub fn check_expr(&mut self, expr: &'hir Expr<'_>) -> bool {
159161
self.check(expr, Self::visit_expr)
160162
}
161163

162-
pub fn check_stmt(&mut self, stmt: &Stmt<'_>) -> bool {
164+
pub fn check_stmt(&mut self, stmt: &'hir Stmt<'_>) -> bool {
163165
self.check(stmt, Self::visit_stmt)
164166
}
165167
}
166168

167-
impl<'v> Visitor<'v> for LocalUsedVisitor {
169+
impl<'v> Visitor<'v> for LocalUsedVisitor<'v> {
168170
type Map = Map<'v>;
169171

170172
fn visit_expr(&mut self, expr: &'v Expr<'v>) {
173+
if self.used {
174+
return;
175+
}
171176
if path_to_local_id(expr, self.local_hir_id) {
172177
self.used = true;
173178
} else {
@@ -176,6 +181,6 @@ impl<'v> Visitor<'v> for LocalUsedVisitor {
176181
}
177182

178183
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
179-
NestedVisitorMap::None
184+
NestedVisitorMap::OnlyBodies(self.hir)
180185
}
181186
}

tests/ui/collapsible_match.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,14 @@ fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u
224224
},
225225
_ => return,
226226
}
227+
if let Ok(val) = res_opt {
228+
if let Some(n) = val {
229+
let _ = || {
230+
// usage in closure
231+
println!("{:?}", val);
232+
};
233+
}
234+
}
227235
}
228236

229237
fn make<T>() -> T {

0 commit comments

Comments
 (0)