@@ -221,6 +221,11 @@ pub enum Suggestion {
221
221
/// Remove `r#` from identifier:
222
222
/// `format!("{r#foo}")` -> `format!("{foo}")`
223
223
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 ) ,
224
229
}
225
230
226
231
/// The parser structure for interpreting the input format string. This is
@@ -731,6 +736,12 @@ impl<'a> Parser<'a> {
731
736
}
732
737
} else if self . consume ( '?' ) {
733
738
spec. ty = "?" ;
739
+ if let Some ( & ( _, maybe) ) = self . cur . peek ( ) {
740
+ match maybe {
741
+ '#' | 'x' | 'X' => self . suggest_format_parameter ( maybe) ,
742
+ _ => ( ) ,
743
+ }
744
+ }
734
745
} else {
735
746
spec. ty = self . word ( ) ;
736
747
if !spec. ty . is_empty ( ) {
@@ -932,6 +943,30 @@ impl<'a> Parser<'a> {
932
943
}
933
944
}
934
945
}
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
+ }
935
970
}
936
971
937
972
/// Finds the indices of all characters that have been processed and differ between the actual
0 commit comments