Skip to content

Commit 6b44662

Browse files
committed
Parse the format string for the panic_fmt lint for better warnings.
1 parent 0f193d1 commit 6b44662

File tree

5 files changed

+47
-21
lines changed

5 files changed

+47
-21
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3831,6 +3831,7 @@ dependencies = [
38313831
"rustc_hir",
38323832
"rustc_index",
38333833
"rustc_middle",
3834+
"rustc_parse_format",
38343835
"rustc_session",
38353836
"rustc_span",
38363837
"rustc_target",

compiler/rustc_lint/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ rustc_feature = { path = "../rustc_feature" }
2020
rustc_index = { path = "../rustc_index" }
2121
rustc_session = { path = "../rustc_session" }
2222
rustc_trait_selection = { path = "../rustc_trait_selection" }
23+
rustc_parse_format = { path = "../rustc_parse_format" }

compiler/rustc_lint/src/panic_fmt.rs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_ast as ast;
33
use rustc_errors::Applicability;
44
use rustc_hir as hir;
55
use rustc_middle::ty;
6+
use rustc_parse_format::{ParseMode, Parser, Piece};
67
use rustc_span::sym;
78

89
declare_lint! {
@@ -52,13 +53,28 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
5253
if cx.tcx.is_diagnostic_item(sym::std_panic_macro, id)
5354
|| cx.tcx.is_diagnostic_item(sym::core_panic_macro, id)
5455
{
55-
let s = sym.as_str();
56-
if !s.contains(&['{', '}'][..]) {
56+
let fmt = sym.as_str();
57+
if !fmt.contains(&['{', '}'][..]) {
5758
return;
5859
}
59-
let s = s.replace("{{", "").replace("}}", "");
60-
let looks_like_placeholder =
61-
s.find('{').map_or(false, |i| s[i + 1..].contains('}'));
60+
61+
let fmt_span = arg.span.source_callsite();
62+
63+
let (snippet, style) =
64+
match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
65+
Ok(snippet) => {
66+
// Count the number of `#`s between the `r` and `"`.
67+
let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
68+
(Some(snippet), style)
69+
}
70+
Err(_) => (None, None),
71+
};
72+
73+
let mut fmt_parser =
74+
Parser::new(fmt.as_ref(), style, snippet, false, ParseMode::Format);
75+
let n_arguments =
76+
(&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
77+
6278
// Unwrap another level of macro expansion if this panic!()
6379
// was expanded from assert!() or debug_assert!().
6480
for &assert in &[sym::assert_macro, sym::debug_assert_macro] {
@@ -70,15 +86,23 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
7086
expn = parent;
7187
}
7288
}
73-
if looks_like_placeholder {
74-
cx.struct_span_lint(PANIC_FMT, arg.span.source_callsite(), |lint| {
75-
let mut l = lint.build("panic message contains an unused formatting placeholder");
89+
90+
if n_arguments > 0 && fmt_parser.errors.is_empty() {
91+
let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
92+
[] => vec![fmt_span],
93+
v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
94+
};
95+
cx.struct_span_lint(PANIC_FMT, arg_spans, |lint| {
96+
let mut l = lint.build(match n_arguments {
97+
1 => "panic message contains an unused formatting placeholder",
98+
_ => "panic message contains unused formatting placeholders",
99+
});
76100
l.note("this message is not used as a format string when given without arguments, but will be in a future Rust version");
77101
if expn.call_site.contains(arg.span) {
78102
l.span_suggestion(
79103
arg.span.shrink_to_hi(),
80104
"add the missing argument(s)",
81-
", argument".into(),
105+
", ...".into(),
82106
Applicability::HasPlaceholders,
83107
);
84108
l.span_suggestion(

src/test/ui/panic-brace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ fn main() {
55
panic!("here's a brace: {"); //~ WARN panic message contains a brace
66
std::panic!("another one: }"); //~ WARN panic message contains a brace
77
core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder
8-
assert!(false, "{:03x} bla"); //~ WARN panic message contains an unused formatting placeholder
8+
assert!(false, "{:03x} {test} bla"); //~ WARN panic message contains unused formatting placeholders
99
debug_assert!(false, "{{}} bla"); //~ WARN panic message contains a brace
1010
}

src/test/ui/panic-brace.stderr

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,35 @@ LL | std::panic!("{}", "another one: }");
2424
| ^^^^^
2525

2626
warning: panic message contains an unused formatting placeholder
27-
--> $DIR/panic-brace.rs:7:18
27+
--> $DIR/panic-brace.rs:7:25
2828
|
2929
LL | core::panic!("Hello {}");
30-
| ^^^^^^^^^^
30+
| ^^
3131
|
3232
= note: this message is not used as a format string when given without arguments, but will be in a future Rust version
3333
help: add the missing argument(s)
3434
|
35-
LL | core::panic!("Hello {}", argument);
36-
| ^^^^^^^^^^
35+
LL | core::panic!("Hello {}", ...);
36+
| ^^^^^
3737
help: or add a "{}" format string to use the message literally
3838
|
3939
LL | core::panic!("{}", "Hello {}");
4040
| ^^^^^
4141

42-
warning: panic message contains an unused formatting placeholder
43-
--> $DIR/panic-brace.rs:8:20
42+
warning: panic message contains unused formatting placeholders
43+
--> $DIR/panic-brace.rs:8:21
4444
|
45-
LL | assert!(false, "{:03x} bla");
46-
| ^^^^^^^^^^^^
45+
LL | assert!(false, "{:03x} {test} bla");
46+
| ^^^^^^ ^^^^^^
4747
|
4848
= note: this message is not used as a format string when given without arguments, but will be in a future Rust version
4949
help: add the missing argument(s)
5050
|
51-
LL | assert!(false, "{:03x} bla", argument);
52-
| ^^^^^^^^^^
51+
LL | assert!(false, "{:03x} {test} bla", ...);
52+
| ^^^^^
5353
help: or add a "{}" format string to use the message literally
5454
|
55-
LL | assert!(false, "{}", "{:03x} bla");
55+
LL | assert!(false, "{}", "{:03x} {test} bla");
5656
| ^^^^^
5757

5858
warning: panic message contains a brace

0 commit comments

Comments
 (0)