Skip to content

Commit 5239a90

Browse files
committed
Factor in some expr_visitor usages
1 parent 73501da commit 5239a90

File tree

6 files changed

+120
-303
lines changed

6 files changed

+120
-303
lines changed

clippy_lints/src/eta_reduction.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
22
use clippy_utils::higher::VecArgs;
33
use clippy_utils::source::snippet_opt;
4-
use clippy_utils::usage::UsedAfterExprVisitor;
5-
use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id};
4+
use clippy_utils::usage::local_used_after_expr;
5+
use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local, path_to_local_id};
66
use if_chain::if_chain;
77
use rustc_errors::Applicability;
88
use rustc_hir::def_id::DefId;
@@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
118118
if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
119119
if substs.as_closure().kind() == ClosureKind::FnMut;
120120
if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
121-
|| UsedAfterExprVisitor::is_found(cx, callee);
121+
|| path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, callee));
122122

123123
then {
124124
// Mutable closure is used after current expr; we cannot consume it.

clippy_lints/src/implicit_return.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use clippy_utils::{
22
diagnostics::span_lint_and_sugg,
33
get_async_fn_body, is_async_fn,
44
source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
5-
visitors::visit_break_exprs,
5+
visitors::expr_visitor_no_bodies,
66
};
77
use rustc_errors::Applicability;
8-
use rustc_hir::intravisit::FnKind;
8+
use rustc_hir::intravisit::{FnKind, Visitor};
99
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
1010
use rustc_lint::{LateContext, LateLintPass, LintContext};
1111
use rustc_middle::lint::in_external_macro;
@@ -144,20 +144,24 @@ fn lint_implicit_returns(
144144

145145
ExprKind::Loop(block, ..) => {
146146
let mut add_return = false;
147-
visit_break_exprs(block, |break_expr, dest, sub_expr| {
148-
if dest.target_id.ok() == Some(expr.hir_id) {
149-
if call_site_span.is_none() && break_expr.span.ctxt() == ctxt {
150-
// At this point sub_expr can be `None` in async functions which either diverge, or return the
151-
// unit type.
152-
if let Some(sub_expr) = sub_expr {
153-
lint_break(cx, break_expr.span, sub_expr.span);
147+
expr_visitor_no_bodies(|e| {
148+
if let ExprKind::Break(dest, sub_expr) = e.kind {
149+
if dest.target_id.ok() == Some(expr.hir_id) {
150+
if call_site_span.is_none() && e.span.ctxt() == ctxt {
151+
// At this point sub_expr can be `None` in async functions which either diverge, or return
152+
// the unit type.
153+
if let Some(sub_expr) = sub_expr {
154+
lint_break(cx, e.span, sub_expr.span);
155+
}
156+
} else {
157+
// the break expression is from a macro call, add a return to the loop
158+
add_return = true;
154159
}
155-
} else {
156-
// the break expression is from a macro call, add a return to the loop
157-
add_return = true;
158160
}
159161
}
160-
});
162+
true
163+
})
164+
.visit_block(block);
161165
if add_return {
162166
#[allow(clippy::option_if_let_else)]
163167
if let Some(span) = call_site_span {

clippy_utils/src/lib.rs

Lines changed: 20 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![feature(box_patterns)]
22
#![feature(in_band_lifetimes)]
33
#![feature(iter_zip)]
4+
#![feature(let_else)]
45
#![feature(rustc_private)]
56
#![feature(control_flow_enum)]
67
#![recursion_limit = "512"]
@@ -68,7 +69,7 @@ use rustc_hir as hir;
6869
use rustc_hir::def::{DefKind, Res};
6970
use rustc_hir::def_id::DefId;
7071
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
71-
use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
72+
use rustc_hir::intravisit::{walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
7273
use rustc_hir::itemlikevisit::ItemLikeVisitor;
7374
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
7475
use rustc_hir::{
@@ -96,6 +97,7 @@ use rustc_target::abi::Integer;
9697

9798
use crate::consts::{constant, Constant};
9899
use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type};
100+
use crate::visitors::expr_visitor_no_bodies;
99101

100102
pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
101103
if let Ok(version) = RustcVersion::parse(msrv) {
@@ -1107,63 +1109,30 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {
11071109

11081110
/// Returns `true` if `expr` contains a return expression
11091111
pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
1110-
struct RetCallFinder {
1111-
found: bool,
1112-
}
1113-
1114-
impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder {
1115-
type Map = Map<'tcx>;
1116-
1117-
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
1118-
if self.found {
1119-
return;
1120-
}
1112+
let mut found = false;
1113+
expr_visitor_no_bodies(|expr| {
1114+
if !found {
11211115
if let hir::ExprKind::Ret(..) = &expr.kind {
1122-
self.found = true;
1123-
} else {
1124-
hir::intravisit::walk_expr(self, expr);
1116+
found = true;
11251117
}
11261118
}
1127-
1128-
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
1129-
hir::intravisit::NestedVisitorMap::None
1130-
}
1131-
}
1132-
1133-
let mut visitor = RetCallFinder { found: false };
1134-
visitor.visit_expr(expr);
1135-
visitor.found
1136-
}
1137-
1138-
struct FindMacroCalls<'a, 'b> {
1139-
names: &'a [&'b str],
1140-
result: Vec<Span>,
1141-
}
1142-
1143-
impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> {
1144-
type Map = Map<'tcx>;
1145-
1146-
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
1147-
if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
1148-
self.result.push(expr.span);
1149-
}
1150-
// and check sub-expressions
1151-
intravisit::walk_expr(self, expr);
1152-
}
1153-
1154-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
1155-
NestedVisitorMap::None
1156-
}
1119+
!found
1120+
})
1121+
.visit_expr(expr);
1122+
found
11571123
}
11581124

11591125
/// Finds calls of the specified macros in a function body.
11601126
pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
1161-
let mut fmc = FindMacroCalls {
1162-
names,
1163-
result: Vec::new(),
1164-
};
1165-
fmc.visit_expr(&body.value);
1166-
fmc.result
1127+
let mut result = Vec::new();
1128+
expr_visitor_no_bodies(|expr| {
1129+
if names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
1130+
result.push(expr.span);
1131+
}
1132+
true
1133+
})
1134+
.visit_expr(&body.value);
1135+
result
11671136
}
11681137

11691138
/// Extends the span to the beginning of the spans line, incl. whitespaces.

clippy_utils/src/ptr.rs

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::source::snippet;
2+
use crate::visitors::expr_visitor_no_bodies;
23
use crate::{path_to_local_id, strip_pat_refs};
3-
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
4-
use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
4+
use rustc_hir::intravisit::Visitor;
5+
use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
56
use rustc_lint::LateContext;
6-
use rustc_middle::hir::map::Map;
77
use rustc_span::Span;
88
use std::borrow::Cow;
99

@@ -30,50 +30,28 @@ fn extract_clone_suggestions<'tcx>(
3030
replace: &[(&'static str, &'static str)],
3131
body: &'tcx Body<'_>,
3232
) -> Option<Vec<(Span, Cow<'static, str>)>> {
33-
let mut visitor = PtrCloneVisitor {
34-
cx,
35-
id,
36-
replace,
37-
spans: vec![],
38-
abort: false,
39-
};
40-
visitor.visit_body(body);
41-
if visitor.abort { None } else { Some(visitor.spans) }
42-
}
43-
44-
struct PtrCloneVisitor<'a, 'tcx> {
45-
cx: &'a LateContext<'tcx>,
46-
id: HirId,
47-
replace: &'a [(&'static str, &'static str)],
48-
spans: Vec<(Span, Cow<'static, str>)>,
49-
abort: bool,
50-
}
51-
52-
impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
53-
type Map = Map<'tcx>;
54-
55-
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
56-
if self.abort {
57-
return;
33+
let mut abort = false;
34+
let mut spans = Vec::new();
35+
expr_visitor_no_bodies(|expr| {
36+
if abort {
37+
return false;
5838
}
5939
if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind {
60-
if path_to_local_id(recv, self.id) {
40+
if path_to_local_id(recv, id) {
6141
if seg.ident.name.as_str() == "capacity" {
62-
self.abort = true;
63-
return;
42+
abort = true;
43+
return false;
6444
}
65-
for &(fn_name, suffix) in self.replace {
45+
for &(fn_name, suffix) in replace {
6646
if seg.ident.name.as_str() == fn_name {
67-
self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
68-
return;
47+
spans.push((expr.span, snippet(cx, recv.span, "_") + suffix));
48+
return false;
6949
}
7050
}
7151
}
7252
}
73-
walk_expr(self, expr);
74-
}
75-
76-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
77-
NestedVisitorMap::None
78-
}
53+
!abort
54+
})
55+
.visit_body(body);
56+
if abort { None } else { Some(spans) }
7957
}

clippy_utils/src/usage.rs

Lines changed: 30 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate as utils;
2+
use crate::visitors::{expr_visitor, expr_visitor_no_bodies};
23
use rustc_hir as hir;
3-
use rustc_hir::intravisit;
4-
use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
4+
use rustc_hir::intravisit::{self, Visitor};
55
use rustc_hir::HirIdSet;
66
use rustc_hir::{Expr, ExprKind, HirId};
77
use rustc_infer::infer::TyCtxtInferExt;
@@ -148,96 +148,47 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
148148
}
149149
}
150150

151-
struct ReturnBreakContinueMacroVisitor {
152-
seen_return_break_continue: bool,
153-
}
154-
155-
impl ReturnBreakContinueMacroVisitor {
156-
fn new() -> ReturnBreakContinueMacroVisitor {
157-
ReturnBreakContinueMacroVisitor {
158-
seen_return_break_continue: false,
159-
}
160-
}
161-
}
162-
163-
impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
164-
type Map = Map<'tcx>;
165-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
166-
NestedVisitorMap::None
167-
}
168-
169-
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
170-
if self.seen_return_break_continue {
171-
// No need to look farther if we've already seen one of them
172-
return;
151+
pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
152+
let mut seen_return_break_continue = false;
153+
expr_visitor_no_bodies(|ex| {
154+
if seen_return_break_continue {
155+
return false;
173156
}
174157
match &ex.kind {
175158
ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => {
176-
self.seen_return_break_continue = true;
159+
seen_return_break_continue = true;
177160
},
178161
// Something special could be done here to handle while or for loop
179162
// desugaring, as this will detect a break if there's a while loop
180163
// or a for loop inside the expression.
181164
_ => {
182165
if ex.span.from_expansion() {
183-
self.seen_return_break_continue = true;
184-
} else {
185-
rustc_hir::intravisit::walk_expr(self, ex);
166+
seen_return_break_continue = true;
186167
}
187168
},
188169
}
189-
}
190-
}
191-
192-
pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
193-
let mut recursive_visitor = ReturnBreakContinueMacroVisitor::new();
194-
recursive_visitor.visit_expr(expression);
195-
recursive_visitor.seen_return_break_continue
196-
}
197-
198-
pub struct UsedAfterExprVisitor<'a, 'tcx> {
199-
cx: &'a LateContext<'tcx>,
200-
expr: &'tcx Expr<'tcx>,
201-
definition: HirId,
202-
past_expr: bool,
203-
used_after_expr: bool,
204-
}
205-
impl<'a, 'tcx> UsedAfterExprVisitor<'a, 'tcx> {
206-
pub fn is_found(cx: &'a LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
207-
utils::path_to_local(expr).map_or(false, |definition| {
208-
let mut visitor = UsedAfterExprVisitor {
209-
cx,
210-
expr,
211-
definition,
212-
past_expr: false,
213-
used_after_expr: false,
214-
};
215-
utils::get_enclosing_block(cx, definition).map_or(false, |block| {
216-
visitor.visit_block(block);
217-
visitor.used_after_expr
218-
})
219-
})
220-
}
221-
}
222-
223-
impl<'a, 'tcx> intravisit::Visitor<'tcx> for UsedAfterExprVisitor<'a, 'tcx> {
224-
type Map = Map<'tcx>;
225-
226-
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
227-
NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
228-
}
229-
230-
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
231-
if self.used_after_expr {
232-
return;
170+
!seen_return_break_continue
171+
})
172+
.visit_expr(expression);
173+
seen_return_break_continue
174+
}
175+
176+
pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
177+
let Some(block) = utils::get_enclosing_block(cx, local_id) else { return false };
178+
let mut used_after_expr = false;
179+
let mut past_expr = false;
180+
expr_visitor(cx, |expr| {
181+
if used_after_expr {
182+
return false;
233183
}
234184

235-
if expr.hir_id == self.expr.hir_id {
236-
self.past_expr = true;
237-
} else if self.past_expr && utils::path_to_local_id(expr, self.definition) {
238-
self.used_after_expr = true;
239-
} else {
240-
intravisit::walk_expr(self, expr);
185+
if expr.hir_id == after.hir_id {
186+
past_expr = true;
187+
} else if past_expr && utils::path_to_local_id(expr, local_id) {
188+
used_after_expr = true;
241189
}
242-
}
190+
!used_after_expr
191+
})
192+
.visit_block(block);
193+
used_after_expr
243194
}

0 commit comments

Comments
 (0)