Skip to content

Commit ded269f

Browse files
committed
Improve panic_fmt message for panic!("{}") with a fmt placeholder.
1 parent 451c986 commit ded269f

File tree

1 file changed

+45
-17
lines changed

1 file changed

+45
-17
lines changed

compiler/rustc_lint/src/panic_fmt.rs

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,52 @@ impl<'tcx> LateLintPass<'tcx> for PanicFmt {
4747
fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
4848
if let hir::ExprKind::Lit(lit) = &arg.kind {
4949
if let ast::LitKind::Str(sym, _) = lit.node {
50-
if sym.as_str().contains(&['{', '}'][..]) {
51-
let expn = f.span.ctxt().outer_expn_data();
52-
if let Some(id) = expn.macro_def_id {
53-
if cx.tcx.is_diagnostic_item(sym::std_panic_macro, id)
54-
|| cx.tcx.is_diagnostic_item(sym::core_panic_macro, id)
55-
{
56-
let expn = {
57-
// Unwrap another level of macro expansion if this
58-
// panic!() was expanded from assert!().
59-
let parent = expn.call_site.ctxt().outer_expn_data();
60-
if parent.macro_def_id.map_or(false, |id| {
61-
cx.tcx.is_diagnostic_item(sym::assert_macro, id)
62-
}) {
63-
parent
64-
} else {
65-
expn
50+
let s = sym.as_str();
51+
let open = s.find('{');
52+
let close = s[open.unwrap_or(0)..].find('}');
53+
let looks_like_placeholder = match (open, close) {
54+
(Some(_), Some(_)) => true,
55+
(Some(_), None) | (None, Some(_)) => false,
56+
(None, None) => return // OK, no braces.
57+
};
58+
let expn = f.span.ctxt().outer_expn_data();
59+
if let Some(id) = expn.macro_def_id {
60+
if cx.tcx.is_diagnostic_item(sym::std_panic_macro, id)
61+
|| cx.tcx.is_diagnostic_item(sym::core_panic_macro, id)
62+
{
63+
let expn = {
64+
// Unwrap another level of macro expansion if this
65+
// panic!() was expanded from assert!().
66+
let parent = expn.call_site.ctxt().outer_expn_data();
67+
if parent.macro_def_id.map_or(false, |id| {
68+
cx.tcx.is_diagnostic_item(sym::assert_macro, id)
69+
}) {
70+
parent
71+
} else {
72+
expn
73+
}
74+
};
75+
if looks_like_placeholder {
76+
cx.struct_span_lint(PANIC_FMT, arg.span.source_callsite(), |lint| {
77+
let mut l = lint.build("Panic message contains an unused formatting placeholder");
78+
l.note("This message is not used as a format string when given without arguments, but will be in a future Rust version");
79+
if expn.call_site.contains(arg.span) {
80+
l.span_suggestion(
81+
arg.span.shrink_to_hi(),
82+
"add the missing argument(s)",
83+
", argument".into(),
84+
Applicability::HasPlaceholders,
85+
);
86+
l.span_suggestion(
87+
arg.span.shrink_to_lo(),
88+
"or add a \"{}\" format string to use the message literally",
89+
"\"{}\", ".into(),
90+
Applicability::MaybeIncorrect,
91+
);
6692
}
67-
};
93+
l.emit();
94+
});
95+
} else {
6896
cx.struct_span_lint(PANIC_FMT, expn.call_site, |lint| {
6997
let mut l = lint.build("Panic message contains a brace");
7098
l.note("This message is not used as a format string, but will be in a future Rust version");

0 commit comments

Comments
 (0)