about summary refs log tree commit diff
path: root/compiler/rustc_parse_format
diff options
context:
space:
mode:
authorDavis Muro <davis.ray.muro@gmail.com>2024-12-28 20:47:07 -0800
committerDavis Muro <davis.ray.muro@gmail.com>2024-12-30 06:14:26 -0800
commit62c3c9a5ae2072a04ba5f5d84055d38dcd043427 (patch)
treee69b23ef8f1f81efd26ade16fb6d6d09c17102c9 /compiler/rustc_parse_format
parent0b63477350d8b5d49b86e4f4aedf066b0a5846c0 (diff)
downloadrust-62c3c9a5ae2072a04ba5f5d84055d38dcd043427.tar.gz
rust-62c3c9a5ae2072a04ba5f5d84055d38dcd043427.zip
add suggestion for wrongly ordered format parameters
Diffstat (limited to 'compiler/rustc_parse_format')
-rw-r--r--compiler/rustc_parse_format/src/lib.rs35
1 files changed, 35 insertions, 0 deletions
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 1716f417969..9eb335cb34c 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -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
@@ -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() {
@@ -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