@@ -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
@@ -389,6 +394,7 @@ impl<'a> Parser<'a> {
389394 description : S1 ,
390395 label : S2 ,
391396 note : S3 ,
397+
392398 span : InnerSpan ,
393399 ) {
394400 self . errors . push ( ParseError {
@@ -731,6 +737,12 @@ impl<'a> Parser<'a> {
731737 }
732738 } else if self . consume ( '?' ) {
733739 spec. ty = "?" ;
740+ if let Some ( & ( _, maybe) ) = self . cur . peek ( ) {
741+ match maybe {
742+ '#' | 'x' | 'X' => self . suggest_format_parameter ( maybe) ,
743+ _ => ( ) ,
744+ }
745+ }
734746 } else {
735747 spec. ty = self . word ( ) ;
736748 if !spec. ty . is_empty ( ) {
@@ -932,6 +944,30 @@ impl<'a> Parser<'a> {
932944 }
933945 }
934946 }
947+
948+ fn suggest_format_parameter ( & mut self , c : char ) {
949+ let replacement = match c {
950+ '#' => "#?" ,
951+ 'x' => "x?" ,
952+ 'X' => "X?" ,
953+ _ => return ,
954+ } ;
955+ let Some ( pos) = self . consume_pos ( c) else {
956+ return ;
957+ } ;
958+
959+ let span = self . span ( pos - 1 , pos + 1 ) ;
960+ let pos = self . to_span_index ( pos) ;
961+
962+ self . errors . insert ( 0 , ParseError {
963+ description : format ! ( "expected `}}`, found `{c}`" ) ,
964+ note : None ,
965+ label : "expected `'}'`" . into ( ) ,
966+ span : pos. to ( pos) ,
967+ secondary_label : None ,
968+ suggestion : Suggestion :: ReorderFormatParameter ( span, format ! ( "{replacement}" ) ) ,
969+ } )
970+ }
935971}
936972
937973/// Finds the indices of all characters that have been processed and differ between the actual
0 commit comments