Skip to content

Commit 58fb801

Browse files
committed
Auto merge of rust-lang#10561 - Alexendoo:format-args-ast-3, r=Manishearth
Replace remaining usage of `FormatArgsExpn` Closes rust-lang#10233 Removes `FormatArgsExpn` & friends now that they're unused changelog: none r? `@Manishearth`
2 parents 84e42fb + 6589d79 commit 58fb801

File tree

6 files changed

+132
-803
lines changed

6 files changed

+132
-803
lines changed

clippy_lints/src/explicit_write.rs

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::macros::FormatArgsExpn;
2+
use clippy_utils::macros::{find_format_args, format_args_inputs_span};
33
use clippy_utils::source::snippet_with_applicability;
44
use clippy_utils::{is_expn_of, match_function_call, paths};
55
use if_chain::if_chain;
@@ -8,7 +8,7 @@ use rustc_hir::def::Res;
88
use rustc_hir::{BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_session::{declare_lint_pass, declare_tool_lint};
11-
use rustc_span::sym;
11+
use rustc_span::{sym, ExpnId};
1212

1313
declare_clippy_lint! {
1414
/// ### What it does
@@ -43,23 +43,22 @@ declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);
4343

4444
impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
4545
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
46-
if_chain! {
47-
// match call to unwrap
48-
if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind;
49-
if unwrap_fun.ident.name == sym::unwrap;
46+
// match call to unwrap
47+
if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind
48+
&& unwrap_fun.ident.name == sym::unwrap
5049
// match call to write_fmt
51-
if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind);
52-
if write_fun.ident.name == sym!(write_fmt);
50+
&& let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind)
51+
&& write_fun.ident.name == sym!(write_fmt)
5352
// match calls to std::io::stdout() / std::io::stderr ()
54-
if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
53+
&& let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
5554
Some("stdout")
5655
} else if match_function_call(cx, write_recv, &paths::STDERR).is_some() {
5756
Some("stderr")
5857
} else {
5958
None
60-
};
61-
if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg);
62-
then {
59+
}
60+
{
61+
find_format_args(cx, write_arg, ExpnId::root(), |format_args| {
6362
let calling_macro =
6463
// ordering is important here, since `writeln!` uses `write!` internally
6564
if is_expn_of(write_call.span, "writeln").is_some() {
@@ -92,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
9291
let mut applicability = Applicability::MachineApplicable;
9392
let inputs_snippet = snippet_with_applicability(
9493
cx,
95-
format_args.inputs_span(),
94+
format_args_inputs_span(format_args),
9695
"..",
9796
&mut applicability,
9897
);
@@ -104,8 +103,8 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
104103
"try this",
105104
format!("{prefix}{sugg_mac}!({inputs_snippet})"),
106105
applicability,
107-
)
108-
}
106+
);
107+
});
109108
}
110109
}
111110
}

clippy_lints/src/format.rs

+44-47
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
3-
use clippy_utils::source::snippet_with_context;
2+
use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node};
3+
use clippy_utils::source::{snippet_opt, snippet_with_context};
44
use clippy_utils::sugg::Sugg;
5-
use if_chain::if_chain;
5+
use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
66
use rustc_errors::Applicability;
77
use rustc_hir::{Expr, ExprKind};
88
use rustc_lint::{LateContext, LateLintPass};
99
use rustc_middle::ty;
1010
use rustc_session::{declare_lint_pass, declare_tool_lint};
11-
use rustc_span::symbol::kw;
1211
use rustc_span::{sym, Span};
1312

1413
declare_clippy_lint! {
@@ -44,55 +43,53 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
4443

4544
impl<'tcx> LateLintPass<'tcx> for UselessFormat {
4645
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
47-
let (format_args, call_site) = if_chain! {
48-
if let Some(macro_call) = root_macro_call_first_node(cx, expr);
49-
if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id);
50-
if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn);
51-
then {
52-
(format_args, macro_call.span)
53-
} else {
54-
return
55-
}
56-
};
46+
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
47+
if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
48+
return;
49+
}
50+
51+
find_format_args(cx, expr, macro_call.expn, |format_args| {
52+
let mut applicability = Applicability::MachineApplicable;
53+
let call_site = macro_call.span;
5754

58-
let mut applicability = Applicability::MachineApplicable;
59-
if format_args.args.is_empty() {
60-
match *format_args.format_string.parts {
61-
[] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
62-
[_] => {
55+
match (format_args.arguments.all_args(), &format_args.template[..]) {
56+
([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
57+
([], [_]) => {
6358
// Simulate macro expansion, converting {{ and }} to { and }.
64-
let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}");
59+
let Some(snippet) = snippet_opt(cx, format_args.span) else { return };
60+
let s_expand = snippet.replace("{{", "{").replace("}}", "}");
6561
let sugg = format!("{s_expand}.to_string()");
6662
span_useless_format(cx, call_site, sugg, applicability);
6763
},
68-
[..] => {},
69-
}
70-
} else if let [arg] = &*format_args.args {
71-
let value = arg.param.value;
72-
if_chain! {
73-
if format_args.format_string.parts == [kw::Empty];
74-
if arg.format.is_default();
75-
if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
76-
ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(),
77-
ty::Str => true,
78-
_ => false,
79-
};
80-
then {
81-
let is_new_string = match value.kind {
82-
ExprKind::Binary(..) => true,
83-
ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string,
84-
_ => false,
85-
};
86-
let sugg = if is_new_string {
87-
snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned()
88-
} else {
89-
let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability);
90-
format!("{}.to_string()", sugg.maybe_par())
91-
};
92-
span_useless_format(cx, call_site, sugg, applicability);
93-
}
64+
([arg], [piece]) => {
65+
if let Ok(value) = find_format_arg_expr(expr, arg)
66+
&& let FormatArgsPiece::Placeholder(placeholder) = piece
67+
&& placeholder.format_trait == FormatTrait::Display
68+
&& placeholder.format_options == FormatOptions::default()
69+
&& match cx.typeck_results().expr_ty(value).peel_refs().kind() {
70+
ty::Adt(adt, _) => Some(adt.did()) == cx.tcx.lang_items().string(),
71+
ty::Str => true,
72+
_ => false,
73+
}
74+
{
75+
let is_new_string = match value.kind {
76+
ExprKind::Binary(..) => true,
77+
ExprKind::MethodCall(path, ..) => path.ident.name == sym::to_string,
78+
_ => false,
79+
};
80+
let sugg = if is_new_string {
81+
snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned()
82+
} else {
83+
let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability);
84+
format!("{}.to_string()", sugg.maybe_par())
85+
};
86+
span_useless_format(cx, call_site, sugg, applicability);
87+
88+
}
89+
},
90+
_ => {},
9491
}
95-
};
92+
});
9693
}
9794
}
9895

clippy_lints/src/format_impl.rs

+38-22
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
2-
use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn};
2+
use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node};
33
use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
44
use if_chain::if_chain;
5+
use rustc_ast::{FormatArgsPiece, FormatTrait};
56
use rustc_errors::Applicability;
67
use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
78
use rustc_lint::{LateContext, LateLintPass};
89
use rustc_session::{declare_tool_lint, impl_lint_pass};
10+
use rustc_span::Span;
911
use rustc_span::{sym, symbol::kw, Symbol};
1012

1113
declare_clippy_lint! {
@@ -89,7 +91,7 @@ declare_clippy_lint! {
8991
}
9092

9193
#[derive(Clone, Copy)]
92-
struct FormatTrait {
94+
struct FormatTraitNames {
9395
/// e.g. `sym::Display`
9496
name: Symbol,
9597
/// `f` in `fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {}`
@@ -99,7 +101,7 @@ struct FormatTrait {
99101
#[derive(Default)]
100102
pub struct FormatImpl {
101103
// Whether we are inside Display or Debug trait impl - None for neither
102-
format_trait_impl: Option<FormatTrait>,
104+
format_trait_impl: Option<FormatTraitNames>,
103105
}
104106

105107
impl FormatImpl {
@@ -161,43 +163,57 @@ fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
161163
}
162164
}
163165

164-
fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTrait) {
166+
fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, impl_trait: FormatTraitNames) {
165167
// Check each arg in format calls - do we ever use Display on self (directly or via deref)?
166-
if_chain! {
167-
if let Some(outer_macro) = root_macro_call_first_node(cx, expr);
168-
if let macro_def_id = outer_macro.def_id;
169-
if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn);
170-
if is_format_macro(cx, macro_def_id);
171-
then {
172-
for arg in format_args.args {
173-
if arg.format.r#trait != impl_trait.name {
174-
continue;
168+
if let Some(outer_macro) = root_macro_call_first_node(cx, expr)
169+
&& let macro_def_id = outer_macro.def_id
170+
&& is_format_macro(cx, macro_def_id)
171+
{
172+
find_format_args(cx, expr, outer_macro.expn, |format_args| {
173+
for piece in &format_args.template {
174+
if let FormatArgsPiece::Placeholder(placeholder) = piece
175+
&& let trait_name = match placeholder.format_trait {
176+
FormatTrait::Display => sym::Display,
177+
FormatTrait::Debug => sym::Debug,
178+
FormatTrait::LowerExp => sym!(LowerExp),
179+
FormatTrait::UpperExp => sym!(UpperExp),
180+
FormatTrait::Octal => sym!(Octal),
181+
FormatTrait::Pointer => sym::Pointer,
182+
FormatTrait::Binary => sym!(Binary),
183+
FormatTrait::LowerHex => sym!(LowerHex),
184+
FormatTrait::UpperHex => sym!(UpperHex),
185+
}
186+
&& trait_name == impl_trait.name
187+
&& let Ok(index) = placeholder.argument.index
188+
&& let Some(arg) = format_args.arguments.all_args().get(index)
189+
&& let Ok(arg_expr) = find_format_arg_expr(expr, arg)
190+
{
191+
check_format_arg_self(cx, expr.span, arg_expr, impl_trait);
175192
}
176-
check_format_arg_self(cx, expr, &arg, impl_trait);
177193
}
178-
}
194+
});
179195
}
180196
}
181197

182-
fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) {
198+
fn check_format_arg_self(cx: &LateContext<'_>, span: Span, arg: &Expr<'_>, impl_trait: FormatTraitNames) {
183199
// Handle multiple dereferencing of references e.g. &&self
184200
// Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl)
185201
// Since the argument to fmt is itself a reference: &self
186-
let reference = peel_ref_operators(cx, arg.param.value);
202+
let reference = peel_ref_operators(cx, arg);
187203
let map = cx.tcx.hir();
188204
// Is the reference self?
189205
if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) {
190-
let FormatTrait { name, .. } = impl_trait;
206+
let FormatTraitNames { name, .. } = impl_trait;
191207
span_lint(
192208
cx,
193209
RECURSIVE_FORMAT_IMPL,
194-
expr.span,
210+
span,
195211
&format!("using `self` as `{name}` in `impl {name}` will cause infinite recursion"),
196212
);
197213
}
198214
}
199215

200-
fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTrait) {
216+
fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait: FormatTraitNames) {
201217
if_chain! {
202218
if let Some(macro_call) = root_macro_call_first_node(cx, expr);
203219
if let Some(name) = cx.tcx.get_diagnostic_name(macro_call.def_id);
@@ -227,7 +243,7 @@ fn check_print_in_format_impl(cx: &LateContext<'_>, expr: &Expr<'_>, impl_trait:
227243
}
228244
}
229245

230-
fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option<FormatTrait> {
246+
fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Option<FormatTraitNames> {
231247
if_chain! {
232248
if impl_item.ident.name == sym::fmt;
233249
if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
@@ -241,7 +257,7 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio
241257
.and_then(|param| param.pat.simple_ident())
242258
.map(|ident| ident.name);
243259

244-
Some(FormatTrait {
260+
Some(FormatTraitNames {
245261
name,
246262
formatter_name,
247263
})

clippy_lints/src/methods/expect_fun_call.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
2+
use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node};
33
use clippy_utils::source::snippet_with_applicability;
44
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
55
use rustc_errors::Applicability;
@@ -136,18 +136,19 @@ pub(super) fn check<'tcx>(
136136
if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
137137
return;
138138
}
139-
let Some(format_args) = FormatArgsExpn::find_nested(cx, arg_root, macro_call.expn) else { return };
140-
let span = format_args.inputs_span();
141-
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
142-
span_lint_and_sugg(
143-
cx,
144-
EXPECT_FUN_CALL,
145-
span_replace_word,
146-
&format!("use of `{name}` followed by a function call"),
147-
"try this",
148-
format!("unwrap_or_else({closure_args} panic!({sugg}))"),
149-
applicability,
150-
);
139+
find_format_args(cx, arg_root, macro_call.expn, |format_args| {
140+
let span = format_args_inputs_span(format_args);
141+
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
142+
span_lint_and_sugg(
143+
cx,
144+
EXPECT_FUN_CALL,
145+
span_replace_word,
146+
&format!("use of `{name}` followed by a function call"),
147+
"try this",
148+
format!("unwrap_or_else({closure_args} panic!({sugg}))"),
149+
applicability,
150+
);
151+
});
151152
return;
152153
}
153154

clippy_utils/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ extern crate rustc_lexer;
3333
extern crate rustc_lint;
3434
extern crate rustc_middle;
3535
extern crate rustc_mir_dataflow;
36-
extern crate rustc_parse_format;
3736
extern crate rustc_session;
3837
extern crate rustc_span;
3938
extern crate rustc_target;

0 commit comments

Comments
 (0)