Skip to content

Commit 94517d3

Browse files
committed
Auto merge of rust-lang#7938 - camsteffen:visitors, r=xFrednet
Introduce `expr_visitor` and `expr_visitor_no_bodies` changelog: none A couple utils that satisfy a *lot* of visitor use cases. Factoring in every possible usage would be really big so I just focused on cleaning clippy_utils.
2 parents 6fcdf81 + 2c7b7e8 commit 94517d3

File tree

8 files changed

+160
-308
lines changed

8 files changed

+160
-308
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/format_args.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
1111
use rustc_middle::ty::Ty;
1212
use rustc_session::{declare_lint_pass, declare_tool_lint};
13-
use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol};
13+
use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol};
1414

1515
declare_clippy_lint! {
1616
/// ### What it does
@@ -128,7 +128,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
128128
span_lint_and_then(
129129
cx,
130130
FORMAT_IN_FORMAT_ARGS,
131-
trim_semicolon(cx, call_site),
131+
call_site,
132132
&format!("`format!` in `{}!` args", name),
133133
|diag| {
134134
diag.help(&format!(
@@ -192,13 +192,6 @@ fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
192192
.any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
193193
}
194194

195-
fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
196-
snippet_opt(cx, span).map_or(span, |snippet| {
197-
let snippet = snippet.trim_end_matches(';');
198-
span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap()))
199-
})
200-
}
201-
202195
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
203196
where
204197
I: Iterator<Item = &'tcx Adjustment<'tcx>>,

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_lints/src/matches.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,6 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
632632
if let ExprKind::Match(ex, arms, _) = expr.kind {
633633
check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
634634
}
635-
if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
636-
check_match_ref_pats(cx, let_expr, once(let_pat), expr);
637-
}
638635
}
639636

640637
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {

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
}

0 commit comments

Comments
 (0)