about summary refs log tree commit diff
path: root/src/libfmt_macros
diff options
context:
space:
mode:
authorEsteban Küber <esteban@commure.com>2018-07-19 23:14:00 -0700
committerEsteban Küber <esteban@commure.com>2018-07-19 23:18:07 -0700
commitf4306ffbfcb2280f180e51ce6421e1c6c28dccec (patch)
treeed1c8c08d11b030da780ef599b66ae79b8d68e3c /src/libfmt_macros
parent154dee2dccd45f929b0a3d2ce2d45739513f77c8 (diff)
downloadrust-f4306ffbfcb2280f180e51ce6421e1c6c28dccec.tar.gz
rust-f4306ffbfcb2280f180e51ce6421e1c6c28dccec.zip
Use correct spans for format string errors
When encountering format string errors in a raw string, or regular
string literal with embedded newlines, account for the positional
change to use correct spans.

:drive by fix: 🚗
Diffstat (limited to 'src/libfmt_macros')
-rw-r--r--src/libfmt_macros/Cargo.toml3
-rw-r--r--src/libfmt_macros/lib.rs40
2 files changed, 34 insertions, 9 deletions
diff --git a/src/libfmt_macros/Cargo.toml b/src/libfmt_macros/Cargo.toml
index b3f4d2deae2..6e6af9c2ff5 100644
--- a/src/libfmt_macros/Cargo.toml
+++ b/src/libfmt_macros/Cargo.toml
@@ -7,3 +7,6 @@ version = "0.0.0"
 name = "fmt_macros"
 path = "lib.rs"
 crate-type = ["dylib"]
+
+[dependencies]
+syntax = { path = "../libsyntax" }
diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs
index ee590bc3b5e..54cf3d24173 100644
--- a/src/libfmt_macros/lib.rs
+++ b/src/libfmt_macros/lib.rs
@@ -28,6 +28,8 @@ pub use self::Alignment::*;
 pub use self::Flag::*;
 pub use self::Count::*;
 
+extern crate syntax;
+
 use std::str;
 use std::string;
 use std::iter;
@@ -150,18 +152,27 @@ pub struct Parser<'a> {
     pub errors: Vec<ParseError>,
     /// Current position of implicit positional argument pointer
     curarg: usize,
+    /// The style of the string (raw or not), used to position spans correctly
+    style: syntax::ast::StrStyle,
+    /// How many newlines have been seen in the string so far, to adjust the error spans
+    seen_newlines: usize,
 }
 
 impl<'a> Iterator for Parser<'a> {
     type Item = Piece<'a>;
 
     fn next(&mut self) -> Option<Piece<'a>> {
+        let raw = match self.style {
+            syntax::ast::StrStyle::Raw(raw) => raw as usize + self.seen_newlines,
+            _ => 0,
+        };
         if let Some(&(pos, c)) = self.cur.peek() {
             match c {
                 '{' => {
+                    let pos = pos + raw + 1;
                     self.cur.next();
                     if self.consume('{') {
-                        Some(String(self.string(pos + 1)))
+                        Some(String(self.string(pos)))
                     } else {
                         let ret = Some(NextArgument(self.argument()));
                         self.must_consume('}');
@@ -169,8 +180,8 @@ impl<'a> Iterator for Parser<'a> {
                     }
                 }
                 '}' => {
+                    let pos = pos + raw + 1;
                     self.cur.next();
-                    let pos = pos + 1;
                     if self.consume('}') {
                         Some(String(self.string(pos)))
                     } else {
@@ -184,6 +195,10 @@ impl<'a> Iterator for Parser<'a> {
                         None
                     }
                 }
+                '\n' => {
+                    self.seen_newlines += 1;
+                    Some(String(self.string(pos)))
+                }
                 _ => Some(String(self.string(pos))),
             }
         } else {
@@ -194,12 +209,14 @@ impl<'a> Iterator for Parser<'a> {
 
 impl<'a> Parser<'a> {
     /// Creates a new parser for the given format string
-    pub fn new(s: &'a str) -> Parser<'a> {
+    pub fn new(s: &'a str, style: syntax::ast::StrStyle) -> Parser<'a> {
         Parser {
             input: s,
             cur: s.char_indices().peekable(),
             errors: vec![],
             curarg: 0,
+            style,
+            seen_newlines: 0,
         }
     }
 
@@ -262,14 +279,19 @@ impl<'a> Parser<'a> {
     /// found, an error is emitted.
     fn must_consume(&mut self, c: char) {
         self.ws();
+        let raw = match self.style {
+            syntax::ast::StrStyle::Raw(raw) => raw as usize,
+            _ => 0,
+        };
+        let padding = raw + self.seen_newlines;
         if let Some(&(pos, maybe)) = self.cur.peek() {
             if c == maybe {
                 self.cur.next();
             } else {
                 self.err(format!("expected `{:?}`, found `{:?}`", c, maybe),
                          format!("expected `{}`", c),
-                         pos + 1,
-                         pos + 1);
+                         pos + padding + 1,
+                         pos + padding + 1);
             }
         } else {
             let msg = format!("expected `{:?}` but string was terminated", c);
@@ -282,8 +304,8 @@ impl<'a> Parser<'a> {
                 self.err_with_note(msg,
                                    format!("expected `{:?}`", c),
                                    "if you intended to print `{`, you can escape it using `{{`",
-                                   pos,
-                                   pos);
+                                   pos + padding,
+                                   pos + padding);
             } else {
                 self.err(msg, format!("expected `{:?}`", c), pos, pos);
             }
@@ -540,7 +562,7 @@ mod tests {
     use super::*;
 
     fn same(fmt: &'static str, p: &[Piece<'static>]) {
-        let parser = Parser::new(fmt);
+        let parser = Parser::new(fmt, syntax::ast::StrStyle::Cooked);
         assert!(parser.collect::<Vec<Piece<'static>>>() == p);
     }
 
@@ -556,7 +578,7 @@ mod tests {
     }
 
     fn musterr(s: &str) {
-        let mut p = Parser::new(s);
+        let mut p = Parser::new(fmt, syntax::ast::StrStyle::Cooked);
         p.next();
         assert!(!p.errors.is_empty());
     }