From 2c16f9edf5633bc9dc791b6faf65402aba277f4b Mon Sep 17 00:00:00 2001 From: cclfmht Date: Sun, 26 Apr 2026 10:50:05 +0000 Subject: [PATCH] Suggest enclosing format string with `""` under special cases * Suggest enclosing format string under special cases This commit add suggestions about enclosing format string when it falls into the following cases: `{}`, `{:?}`, `{:#?}`. * Add HELP annotations in the UI test --- compiler/rustc_builtin_macros/src/format.rs | 26 ++++++- ...y-block-unit-tuple-suggestion-130170.fixed | 4 +- ...-block-unit-tuple-suggestion-130170.stderr | 10 +++ .../macros/suggest-enclosing-format-string.rs | 27 +++++++ .../suggest-enclosing-format-string.stderr | 72 +++++++++++++++++++ 5 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 tests/ui/macros/suggest-enclosing-format-string.rs create mode 100644 tests/ui/macros/suggest-enclosing-format-string.stderr diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 7d01868645a0..8e055c855c4f 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -173,6 +173,16 @@ fn make_format_args( style: fmt_style, uncooked_symbol: uncooked_fmt_str, } = { + // Extract snippet so that we can check cases `{}`, `{:?}` and `{:#?}` and emit help for + // them later. + let snippet = if let ExprKind::Block(b, None) = &efmt.kind + && b.stmts.len() <= 1 + { + Some(ecx.sess.source_map().span_to_snippet(unexpanded_fmt_span)) + } else { + None + }; + let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else { return ExpandResult::Retry(()); }; @@ -222,12 +232,26 @@ fn make_format_args( }); } sugg_fmt = sugg_fmt.trim_end().to_string(); - err.span_suggestion( + err.span_suggestion_verbose( unexpanded_fmt_span.shrink_to_lo(), "you might be missing a string literal to format with", format!("\"{sugg_fmt}\", "), Applicability::MaybeIncorrect, ); + + if let Some(Ok(snippet)) = snippet.as_ref() { + match snippet.as_str() { + "{}" | "{:?}" | "{:#?}" => { + err.span_suggestion_verbose( + unexpanded_fmt_span, + format!("you might want to enclose `{snippet}` with `\"\"`"), + format!("\"{snippet}\""), + Applicability::MaybeIncorrect, + ); + } + _ => {} + }; + } } } err.emit() diff --git a/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.fixed b/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.fixed index 1ca5125fe8bc..e7b443470b6c 100644 --- a/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.fixed +++ b/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.fixed @@ -2,9 +2,9 @@ fn main() { let s = "123"; - println!("{:?} {} {}", {}, "sss", s); + println!("{:?} {} {}", "{}", "sss", s); //~^ ERROR format argument must be a string literal - println!("{:?}", {}); + println!("{:?}", "{}"); //~^ ERROR format argument must be a string literal println!("{} {} {} {:?}", s, "sss", s, {}); //~^ ERROR format argument must be a string literal diff --git a/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.stderr b/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.stderr index 81fca8c03cc1..8a64db9218f3 100644 --- a/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.stderr +++ b/tests/ui/macros/format-empty-block-unit-tuple-suggestion-130170.stderr @@ -8,6 +8,11 @@ help: you might be missing a string literal to format with | LL | println!("{:?} {} {}", {}, "sss", s); | +++++++++++++ +help: you might want to enclose `{}` with `""` + | +LL - println!({}, "sss", s); +LL + println!("{}", "sss", s); + | error: format argument must be a string literal --> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:7:14 @@ -19,6 +24,11 @@ help: you might be missing a string literal to format with | LL | println!("{:?}", {}); | +++++++ +help: you might want to enclose `{}` with `""` + | +LL - println!({}); +LL + println!("{}"); + | error: format argument must be a string literal --> $DIR/format-empty-block-unit-tuple-suggestion-130170.rs:9:14 diff --git a/tests/ui/macros/suggest-enclosing-format-string.rs b/tests/ui/macros/suggest-enclosing-format-string.rs new file mode 100644 index 000000000000..ab1c6d2a1a19 --- /dev/null +++ b/tests/ui/macros/suggest-enclosing-format-string.rs @@ -0,0 +1,27 @@ +// Suggest enclosing the format string with `""` when it is one of `{}`, `{:?}`, and `{:#?}`. + +#[derive(Debug)] +enum UwU { + QwQ, + AwA, + QAQ, +} + +fn main() { + println!({}, UwU::QwQ); + //~^ ERROR format argument must be a string literal + //~| HELP you might be missing a string literal to format with + //~| HELP you might want to enclose `{}` with `""` + println!({:?}, UwU::QwQ); + //~^ ERROR expected expression, found `:` + //~| ERROR format argument must be a string literal + //~| HELP you might be missing a string literal to format with + //~| HELP maybe write a path separator here + //~| HELP you might want to enclose `{:?}` with `""` + println!({:#?}, UwU::QwQ); + //~^ ERROR expected expression, found `:` + //~| ERROR format argument must be a string literal + //~| HELP you might be missing a string literal to format with + //~| HELP maybe write a path separator here + //~| HELP you might want to enclose `{:#?}` with `""` +} diff --git a/tests/ui/macros/suggest-enclosing-format-string.stderr b/tests/ui/macros/suggest-enclosing-format-string.stderr new file mode 100644 index 000000000000..64f46d39af34 --- /dev/null +++ b/tests/ui/macros/suggest-enclosing-format-string.stderr @@ -0,0 +1,72 @@ +error: format argument must be a string literal + --> $DIR/suggest-enclosing-format-string.rs:11:14 + | +LL | println!({}, UwU::QwQ); + | ^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{:?} {}", {}, UwU::QwQ); + | ++++++++++ +help: you might want to enclose `{}` with `""` + | +LL - println!({}, UwU::QwQ); +LL + println!("{}", UwU::QwQ); + | + +error: expected expression, found `:` + --> $DIR/suggest-enclosing-format-string.rs:15:15 + | +LL | println!({:?}, UwU::QwQ); + | ^ expected expression + | +help: maybe write a path separator here + | +LL | println!({::?}, UwU::QwQ); + | + + +error: format argument must be a string literal + --> $DIR/suggest-enclosing-format-string.rs:15:14 + | +LL | println!({:?}, UwU::QwQ); + | ^^^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{} {}", {:?}, UwU::QwQ); + | ++++++++ +help: you might want to enclose `{:?}` with `""` + | +LL - println!({:?}, UwU::QwQ); +LL + println!("{:?}", UwU::QwQ); + | + +error: expected expression, found `:` + --> $DIR/suggest-enclosing-format-string.rs:21:15 + | +LL | println!({:#?}, UwU::QwQ); + | ^ expected expression + | +help: maybe write a path separator here + | +LL | println!({::#?}, UwU::QwQ); + | + + +error: format argument must be a string literal + --> $DIR/suggest-enclosing-format-string.rs:21:14 + | +LL | println!({:#?}, UwU::QwQ); + | ^^^^^ + | +help: you might be missing a string literal to format with + | +LL | println!("{} {}", {:#?}, UwU::QwQ); + | ++++++++ +help: you might want to enclose `{:#?}` with `""` + | +LL - println!({:#?}, UwU::QwQ); +LL + println!("{:#?}", UwU::QwQ); + | + +error: aborting due to 5 previous errors +