Skip to content

Commit c29de92

Browse files
committed
Return a value from find_format_args instead of using a callback
1 parent b788add commit c29de92

File tree

9 files changed

+126
-129
lines changed

9 files changed

+126
-129
lines changed

clippy_lints/src/explicit_write.rs

+44-46
Original file line numberDiff line numberDiff line change
@@ -57,54 +57,52 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
5757
} else {
5858
None
5959
}
60+
&& let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root())
6061
{
61-
find_format_args(cx, write_arg, ExpnId::root(), |format_args| {
62-
let calling_macro =
63-
// ordering is important here, since `writeln!` uses `write!` internally
64-
if is_expn_of(write_call.span, "writeln").is_some() {
65-
Some("writeln")
66-
} else if is_expn_of(write_call.span, "write").is_some() {
67-
Some("write")
68-
} else {
69-
None
70-
};
71-
let prefix = if dest_name == "stderr" {
72-
"e"
73-
} else {
74-
""
75-
};
62+
// ordering is important here, since `writeln!` uses `write!` internally
63+
let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() {
64+
Some("writeln")
65+
} else if is_expn_of(write_call.span, "write").is_some() {
66+
Some("write")
67+
} else {
68+
None
69+
};
70+
let prefix = if dest_name == "stderr" {
71+
"e"
72+
} else {
73+
""
74+
};
7675

77-
// We need to remove the last trailing newline from the string because the
78-
// underlying `fmt::write` function doesn't know whether `println!` or `print!` was
79-
// used.
80-
let (used, sugg_mac) = if let Some(macro_name) = calling_macro {
81-
(
82-
format!("{macro_name}!({dest_name}(), ...)"),
83-
macro_name.replace("write", "print"),
84-
)
85-
} else {
86-
(
87-
format!("{dest_name}().write_fmt(...)"),
88-
"print".into(),
89-
)
90-
};
91-
let mut applicability = Applicability::MachineApplicable;
92-
let inputs_snippet = snippet_with_applicability(
93-
cx,
94-
format_args_inputs_span(format_args),
95-
"..",
96-
&mut applicability,
97-
);
98-
span_lint_and_sugg(
99-
cx,
100-
EXPLICIT_WRITE,
101-
expr.span,
102-
&format!("use of `{used}.unwrap()`"),
103-
"try",
104-
format!("{prefix}{sugg_mac}!({inputs_snippet})"),
105-
applicability,
106-
);
107-
});
76+
// We need to remove the last trailing newline from the string because the
77+
// underlying `fmt::write` function doesn't know whether `println!` or `print!` was
78+
// used.
79+
let (used, sugg_mac) = if let Some(macro_name) = calling_macro {
80+
(
81+
format!("{macro_name}!({dest_name}(), ...)"),
82+
macro_name.replace("write", "print"),
83+
)
84+
} else {
85+
(
86+
format!("{dest_name}().write_fmt(...)"),
87+
"print".into(),
88+
)
89+
};
90+
let mut applicability = Applicability::MachineApplicable;
91+
let inputs_snippet = snippet_with_applicability(
92+
cx,
93+
format_args_inputs_span(&format_args),
94+
"..",
95+
&mut applicability,
96+
);
97+
span_lint_and_sugg(
98+
cx,
99+
EXPLICIT_WRITE,
100+
expr.span,
101+
&format!("use of `{used}.unwrap()`"),
102+
"try",
103+
format!("{prefix}{sugg_mac}!({inputs_snippet})"),
104+
applicability,
105+
);
108106
}
109107
}
110108
}

clippy_lints/src/format.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,10 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
4343

4444
impl<'tcx> LateLintPass<'tcx> for UselessFormat {
4545
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
46-
let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
47-
return;
48-
};
49-
if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
50-
return;
51-
}
52-
53-
find_format_args(cx, expr, macro_call.expn, |format_args| {
46+
if let Some(macro_call) = root_macro_call_first_node(cx, expr)
47+
&& cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
48+
&& let Some(format_args) = find_format_args(cx, expr, macro_call.expn)
49+
{
5450
let mut applicability = Applicability::MachineApplicable;
5551
let call_site = macro_call.span;
5652

@@ -91,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
9187
},
9288
_ => {},
9389
}
94-
});
90+
}
9591
}
9692
}
9793

clippy_lints/src/format_args.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,10 @@ impl FormatArgs {
186186

187187
impl<'tcx> LateLintPass<'tcx> for FormatArgs {
188188
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
189-
let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
190-
return;
191-
};
192-
if !is_format_macro(cx, macro_call.def_id) {
193-
return;
194-
}
195-
let name = cx.tcx.item_name(macro_call.def_id);
196-
197-
find_format_args(cx, expr, macro_call.expn, |format_args| {
189+
if let Some(macro_call) = root_macro_call_first_node(cx, expr)
190+
&& is_format_macro(cx, macro_call.def_id)
191+
&& let Some(format_args) = find_format_args(cx, expr, macro_call.expn)
192+
{
198193
for piece in &format_args.template {
199194
if let FormatArgsPiece::Placeholder(placeholder) = piece
200195
&& let Ok(index) = placeholder.argument.index
@@ -206,22 +201,23 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
206201

207202
if placeholder.format_trait != FormatTrait::Display
208203
|| placeholder.format_options != FormatOptions::default()
209-
|| is_aliased(format_args, index)
204+
|| is_aliased(&format_args, index)
210205
{
211206
continue;
212207
}
213208

214209
if let Ok(arg_hir_expr) = arg_expr {
210+
let name = cx.tcx.item_name(macro_call.def_id);
215211
check_format_in_format_args(cx, macro_call.span, name, arg_hir_expr);
216212
check_to_string_in_format_args(cx, name, arg_hir_expr);
217213
}
218214
}
219215
}
220216

221217
if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) {
222-
check_uninlined_args(cx, format_args, macro_call.span, macro_call.def_id, self.ignore_mixed);
218+
check_uninlined_args(cx, &format_args, macro_call.span, macro_call.def_id, self.ignore_mixed);
223219
}
224-
});
220+
}
225221
}
226222

227223
extract_msrv_attr!(LateContext);

clippy_lints/src/format_impl.rs

+20-21
Original file line numberDiff line numberDiff line change
@@ -170,30 +170,29 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>,
170170
if let Some(outer_macro) = root_macro_call_first_node(cx, expr)
171171
&& let macro_def_id = outer_macro.def_id
172172
&& is_format_macro(cx, macro_def_id)
173+
&& let Some(format_args) = find_format_args(cx, expr, outer_macro.expn)
173174
{
174-
find_format_args(cx, expr, outer_macro.expn, |format_args| {
175-
for piece in &format_args.template {
176-
if let FormatArgsPiece::Placeholder(placeholder) = piece
177-
&& let trait_name = match placeholder.format_trait {
178-
FormatTrait::Display => sym::Display,
179-
FormatTrait::Debug => sym::Debug,
180-
FormatTrait::LowerExp => sym!(LowerExp),
181-
FormatTrait::UpperExp => sym!(UpperExp),
182-
FormatTrait::Octal => sym!(Octal),
183-
FormatTrait::Pointer => sym::Pointer,
184-
FormatTrait::Binary => sym!(Binary),
185-
FormatTrait::LowerHex => sym!(LowerHex),
186-
FormatTrait::UpperHex => sym!(UpperHex),
187-
}
188-
&& trait_name == impl_trait.name
189-
&& let Ok(index) = placeholder.argument.index
190-
&& let Some(arg) = format_args.arguments.all_args().get(index)
191-
&& let Ok(arg_expr) = find_format_arg_expr(expr, arg)
192-
{
193-
check_format_arg_self(cx, expr.span, arg_expr, impl_trait);
175+
for piece in &format_args.template {
176+
if let FormatArgsPiece::Placeholder(placeholder) = piece
177+
&& let trait_name = match placeholder.format_trait {
178+
FormatTrait::Display => sym::Display,
179+
FormatTrait::Debug => sym::Debug,
180+
FormatTrait::LowerExp => sym!(LowerExp),
181+
FormatTrait::UpperExp => sym!(UpperExp),
182+
FormatTrait::Octal => sym!(Octal),
183+
FormatTrait::Pointer => sym::Pointer,
184+
FormatTrait::Binary => sym!(Binary),
185+
FormatTrait::LowerHex => sym!(LowerHex),
186+
FormatTrait::UpperHex => sym!(UpperHex),
194187
}
188+
&& trait_name == impl_trait.name
189+
&& let Ok(index) = placeholder.argument.index
190+
&& let Some(arg) = format_args.arguments.all_args().get(index)
191+
&& let Ok(arg_expr) = find_format_arg_expr(expr, arg)
192+
{
193+
check_format_arg_self(cx, expr.span, arg_expr, impl_trait);
195194
}
196-
});
195+
}
197196
}
198197
}
199198

clippy_lints/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
609609
.collect(),
610610
))
611611
});
612-
store.register_early_pass(|| Box::new(utils::format_args_collector::FormatArgsCollector));
612+
store.register_early_pass(|| Box::<utils::format_args_collector::FormatArgsCollector>::default());
613613
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
614614
store.register_late_pass(|_| Box::new(utils::author::Author));
615615
let await_holding_invalid_types = conf.await_holding_invalid_types.clone();

clippy_lints/src/methods/expect_fun_call.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,12 @@ pub(super) fn check<'tcx>(
131131

132132
let mut applicability = Applicability::MachineApplicable;
133133

134-
//Special handling for `format!` as arg_root
134+
// Special handling for `format!` as arg_root
135135
if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) {
136-
if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
137-
return;
138-
}
139-
find_format_args(cx, arg_root, macro_call.expn, |format_args| {
140-
let span = format_args_inputs_span(format_args);
136+
if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
137+
&& let Some(format_args) = find_format_args(cx, arg_root, macro_call.expn)
138+
{
139+
let span = format_args_inputs_span(&format_args);
141140
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
142141
span_lint_and_sugg(
143142
cx,
@@ -148,7 +147,7 @@ pub(super) fn check<'tcx>(
148147
format!("unwrap_or_else({closure_args} panic!({sugg}))"),
149148
applicability,
150149
);
151-
});
150+
}
152151
return;
153152
}
154153

clippy_lints/src/utils/format_args_collector.rs

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
use clippy_utils::macros::collect_ast_format_args;
1+
use clippy_utils::macros::AST_FORMAT_ARGS;
22
use clippy_utils::source::snippet_opt;
33
use itertools::Itertools;
4-
use rustc_ast::{Expr, ExprKind, FormatArgs};
4+
use rustc_ast::{Crate, Expr, ExprKind, FormatArgs};
5+
use rustc_data_structures::fx::FxHashMap;
56
use rustc_lexer::{tokenize, TokenKind};
67
use rustc_lint::{EarlyContext, EarlyLintPass};
7-
use rustc_session::{declare_lint_pass, declare_tool_lint};
8-
use rustc_span::hygiene;
8+
use rustc_session::{declare_tool_lint, impl_lint_pass};
9+
use rustc_span::{hygiene, Span};
910
use std::iter::once;
11+
use std::mem;
12+
use std::rc::Rc;
1013

1114
declare_clippy_lint! {
1215
/// ### What it does
@@ -17,7 +20,12 @@ declare_clippy_lint! {
1720
"collects `format_args` AST nodes for use in later lints"
1821
}
1922

20-
declare_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]);
23+
#[derive(Default)]
24+
pub struct FormatArgsCollector {
25+
format_args: FxHashMap<Span, Rc<FormatArgs>>,
26+
}
27+
28+
impl_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]);
2129

2230
impl EarlyLintPass for FormatArgsCollector {
2331
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
@@ -26,9 +34,17 @@ impl EarlyLintPass for FormatArgsCollector {
2634
return;
2735
}
2836

29-
collect_ast_format_args(expr.span, args);
37+
self.format_args
38+
.insert(expr.span.with_parent(None), Rc::new((**args).clone()));
3039
}
3140
}
41+
42+
fn check_crate_post(&mut self, _: &EarlyContext<'_>, _: &Crate) {
43+
AST_FORMAT_ARGS.with(|ast_format_args| {
44+
let result = ast_format_args.set(mem::take(&mut self.format_args));
45+
debug_assert!(result.is_ok());
46+
});
47+
}
3248
}
3349

3450
/// Detects if the format string or an argument has its span set by a proc macro to something inside

clippy_lints/src/write.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -304,23 +304,23 @@ impl<'tcx> LateLintPass<'tcx> for Write {
304304
_ => return,
305305
}
306306

307-
find_format_args(cx, expr, macro_call.expn, |format_args| {
307+
if let Some(format_args) = find_format_args(cx, expr, macro_call.expn) {
308308
// ignore `writeln!(w)` and `write!(v, some_macro!())`
309309
if format_args.span.from_expansion() {
310310
return;
311311
}
312312

313313
match diag_name {
314314
sym::print_macro | sym::eprint_macro | sym::write_macro => {
315-
check_newline(cx, format_args, &macro_call, name);
315+
check_newline(cx, &format_args, &macro_call, name);
316316
},
317317
sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
318-
check_empty_string(cx, format_args, &macro_call, name);
318+
check_empty_string(cx, &format_args, &macro_call, name);
319319
},
320320
_ => {},
321321
}
322322

323-
check_literal(cx, format_args, name);
323+
check_literal(cx, &format_args, name);
324324

325325
if !self.in_debug_impl {
326326
for piece in &format_args.template {
@@ -334,7 +334,7 @@ impl<'tcx> LateLintPass<'tcx> for Write {
334334
}
335335
}
336336
}
337-
});
337+
}
338338
}
339339
}
340340

0 commit comments

Comments
 (0)