@@ -221,6 +221,11 @@ pub enum Suggestion {
221221 /// Remove `r#` from identifier:
222222 /// `format!("{r#foo}")` -> `format!("{foo}")`
223223 RemoveRawIdent ( InnerSpan ) ,
224+ /// Reorder format parameter:
225+ /// `format!("{foo:?#}")` -> `format!("{foo:#?}")`
226+ /// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
227+ /// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
228+ ReorderFormatParameter ( InnerSpan , string:: String ) ,
224229}
225230
226231/// The parser structure for interpreting the input format string. This is
@@ -731,6 +736,12 @@ impl<'a> Parser<'a> {
731736 }
732737 } else if self . consume ( '?' ) {
733738 spec. ty = "?" ;
739+ if let Some ( & ( _, maybe) ) = self . cur . peek ( ) {
740+ match maybe {
741+ '#' | 'x' | 'X' => self . suggest_format_parameter ( maybe) ,
742+ _ => ( ) ,
743+ }
744+ }
734745 } else {
735746 spec. ty = self . word ( ) ;
736747 if !spec. ty . is_empty ( ) {
@@ -932,6 +943,30 @@ impl<'a> Parser<'a> {
932943 }
933944 }
934945 }
946+
947+ fn suggest_format_parameter ( & mut self , c : char ) {
948+ let replacement = match c {
949+ '#' => "#?" ,
950+ 'x' => "x?" ,
951+ 'X' => "X?" ,
952+ _ => return ,
953+ } ;
954+ let Some ( pos) = self . consume_pos ( c) else {
955+ return ;
956+ } ;
957+
958+ let span = self . span ( pos - 1 , pos + 1 ) ;
959+ let pos = self . to_span_index ( pos) ;
960+
961+ self . errors . insert ( 0 , ParseError {
962+ description : format ! ( "expected `}}`, found `{c}`" ) ,
963+ note : None ,
964+ label : "expected `'}'`" . into ( ) ,
965+ span : pos. to ( pos) ,
966+ secondary_label : None ,
967+ suggestion : Suggestion :: ReorderFormatParameter ( span, format ! ( "{replacement}" ) ) ,
968+ } )
969+ }
935970}
936971
937972/// Finds the indices of all characters that have been processed and differ between the actual
0 commit comments