Skip to content

Commit

Permalink
Rollup merge of rust-lang#134877 - DavisRayM:129966-format-string-hel…
Browse files Browse the repository at this point in the history
…p-message, r=estebank

add suggestion for wrongly ordered format parameters

Add suggestion for wrongly ordered format parameters like `?#`.

Supersedes rust-lang#131004
Fix rust-lang#129966
  • Loading branch information
Zalathar authored Jan 1, 2025
2 parents 45d8d5f + 62c3c9a commit 38bc2be
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 0 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_builtin_macros/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ builtin_macros_format_redundant_args = redundant {$n ->
builtin_macros_format_remove_raw_ident = remove the `r#`
builtin_macros_format_reorder_format_parameter = did you mean `{$replacement}`?
builtin_macros_format_requires_string = requires at least a format string argument
builtin_macros_format_string_invalid = invalid format string: {$desc}
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,17 @@ pub(crate) enum InvalidFormatStringSuggestion {
#[primary_span]
span: Span,
},
#[suggestion(
builtin_macros_format_reorder_format_parameter,
code = "{replacement}",
style = "verbose",
applicability = "machine-applicable"
)]
ReorderFormatParameter {
#[primary_span]
span: Span,
replacement: String,
},
}

#[derive(Diagnostic)]
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,13 @@ fn make_format_args(
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
}
}
parse::Suggestion::ReorderFormatParameter(span, replacement) => {
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::ReorderFormatParameter {
span,
replacement,
});
}
}
let guar = ecx.dcx().emit_err(e);
return ExpandResult::Ready(Err(guar));
Expand Down
35 changes: 35 additions & 0 deletions compiler/rustc_parse_format/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ pub enum Suggestion {
/// Remove `r#` from identifier:
/// `format!("{r#foo}")` -> `format!("{foo}")`
RemoveRawIdent(InnerSpan),
/// Reorder format parameter:
/// `format!("{foo:?#}")` -> `format!("{foo:#?}")`
/// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
/// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
ReorderFormatParameter(InnerSpan, string::String),
}

/// The parser structure for interpreting the input format string. This is
Expand Down Expand Up @@ -731,6 +736,12 @@ impl<'a> Parser<'a> {
}
} else if self.consume('?') {
spec.ty = "?";
if let Some(&(_, maybe)) = self.cur.peek() {
match maybe {
'#' | 'x' | 'X' => self.suggest_format_parameter(maybe),
_ => (),
}
}
} else {
spec.ty = self.word();
if !spec.ty.is_empty() {
Expand Down Expand Up @@ -932,6 +943,30 @@ impl<'a> Parser<'a> {
}
}
}

fn suggest_format_parameter(&mut self, c: char) {
let replacement = match c {
'#' => "#?",
'x' => "x?",
'X' => "X?",
_ => return,
};
let Some(pos) = self.consume_pos(c) else {
return;
};

let span = self.span(pos - 1, pos + 1);
let pos = self.to_span_index(pos);

self.errors.insert(0, ParseError {
description: format!("expected `}}`, found `{c}`"),
note: None,
label: "expected `'}'`".into(),
span: pos.to(pos),
secondary_label: None,
suggestion: Suggestion::ReorderFormatParameter(span, format!("{replacement}")),
})
}
}

/// Finds the indices of all characters that have been processed and differ between the actual
Expand Down
25 changes: 25 additions & 0 deletions tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Regression test for https://github.com/rust-lang/rust/issues/129966
//!
//! Ensure we provide suggestion for wrongly ordered format parameters.
//@ run-rustfix
#![allow(dead_code)]

#[derive(Debug)]
struct Foo(u8, u8);

fn main() {
let f = Foo(1, 2);

println!("{f:#?}");
//~^ ERROR invalid format string: expected `}`, found `#`
//~| HELP did you mean `#?`?

println!("{f:x?}");
//~^ ERROR invalid format string: expected `}`, found `x`
//~| HELP did you mean `x?`?

println!("{f:X?}");
//~^ ERROR invalid format string: expected `}`, found `X`
//~| HELP did you mean `X?`?
}
25 changes: 25 additions & 0 deletions tests/ui/fmt/suggest-wrongly-order-format-parameter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! Regression test for https://github.com/rust-lang/rust/issues/129966
//!
//! Ensure we provide suggestion for wrongly ordered format parameters.
//@ run-rustfix
#![allow(dead_code)]

#[derive(Debug)]
struct Foo(u8, u8);

fn main() {
let f = Foo(1, 2);

println!("{f:?#}");
//~^ ERROR invalid format string: expected `}`, found `#`
//~| HELP did you mean `#?`?

println!("{f:?x}");
//~^ ERROR invalid format string: expected `}`, found `x`
//~| HELP did you mean `x?`?

println!("{f:?X}");
//~^ ERROR invalid format string: expected `}`, found `X`
//~| HELP did you mean `X?`?
}
35 changes: 35 additions & 0 deletions tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
error: invalid format string: expected `}`, found `#`
--> $DIR/suggest-wrongly-order-format-parameter.rs:14:19
|
LL | println!("{f:?#}");
| ^ expected `'}'` in format string
|
help: did you mean `#?`?
|
LL | println!("{f:#?}");
| ~~

error: invalid format string: expected `}`, found `x`
--> $DIR/suggest-wrongly-order-format-parameter.rs:18:19
|
LL | println!("{f:?x}");
| ^ expected `'}'` in format string
|
help: did you mean `x?`?
|
LL | println!("{f:x?}");
| ~~

error: invalid format string: expected `}`, found `X`
--> $DIR/suggest-wrongly-order-format-parameter.rs:22:19
|
LL | println!("{f:?X}");
| ^ expected `'}'` in format string
|
help: did you mean `X?`?
|
LL | println!("{f:X?}");
| ~~

error: aborting due to 3 previous errors

0 comments on commit 38bc2be

Please sign in to comment.