add suggestion for wrongly ordered format parameters
This commit is contained in:
parent
0b63477350
commit
62c3c9a5ae
7 changed files with 140 additions and 0 deletions
|
@ -197,6 +197,8 @@ builtin_macros_format_redundant_args = redundant {$n ->
|
||||||
|
|
||||||
builtin_macros_format_remove_raw_ident = remove the `r#`
|
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_requires_string = requires at least a format string argument
|
||||||
|
|
||||||
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
||||||
|
|
|
@ -618,6 +618,17 @@ pub(crate) enum InvalidFormatStringSuggestion {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: 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)]
|
#[derive(Diagnostic)]
|
||||||
|
|
|
@ -316,6 +316,13 @@ fn make_format_args(
|
||||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
|
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);
|
let guar = ecx.dcx().emit_err(e);
|
||||||
return ExpandResult::Ready(Err(guar));
|
return ExpandResult::Ready(Err(guar));
|
||||||
|
|
|
@ -221,6 +221,11 @@ pub enum Suggestion {
|
||||||
/// Remove `r#` from identifier:
|
/// Remove `r#` from identifier:
|
||||||
/// `format!("{r#foo}")` -> `format!("{foo}")`
|
/// `format!("{r#foo}")` -> `format!("{foo}")`
|
||||||
RemoveRawIdent(InnerSpan),
|
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
|
/// The parser structure for interpreting the input format string. This is
|
||||||
|
@ -731,6 +736,12 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
} else if self.consume('?') {
|
} else if self.consume('?') {
|
||||||
spec.ty = "?";
|
spec.ty = "?";
|
||||||
|
if let Some(&(_, maybe)) = self.cur.peek() {
|
||||||
|
match maybe {
|
||||||
|
'#' | 'x' | 'X' => self.suggest_format_parameter(maybe),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
spec.ty = self.word();
|
spec.ty = self.word();
|
||||||
if !spec.ty.is_empty() {
|
if !spec.ty.is_empty() {
|
||||||
|
@ -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
|
/// Finds the indices of all characters that have been processed and differ between the actual
|
||||||
|
|
25
tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed
Normal file
25
tests/ui/fmt/suggest-wrongly-order-format-parameter.fixed
Normal file
|
@ -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
tests/ui/fmt/suggest-wrongly-order-format-parameter.rs
Normal file
25
tests/ui/fmt/suggest-wrongly-order-format-parameter.rs
Normal file
|
@ -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
tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr
Normal file
35
tests/ui/fmt/suggest-wrongly-order-format-parameter.stderr
Normal file
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue