about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-01-14 17:29:07 +0000
committerDavid Wood <david@davidtw.co>2018-01-27 11:46:27 +0000
commitc71cec8834bf30032a8e49d2949f6d8d4080b639 (patch)
tree49dc11292d287459c01aeddbd4c40240de9b2e16 /src/libsyntax
parentc6e6428d1a13f61f5ffbe43697a21f3cd82cd01d (diff)
downloadrust-c71cec8834bf30032a8e49d2949f6d8d4080b639.tar.gz
rust-c71cec8834bf30032a8e49d2949f6d8d4080b639.zip
end_point handling multibyte characters correctly.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/codemap.rs37
-rw-r--r--src/libsyntax/parse/parser.rs8
2 files changed, 42 insertions, 3 deletions
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index a58a61c3636..e74066da0ac 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -25,6 +25,7 @@ pub use self::ExpnFormat::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use std::cell::{RefCell, Ref};
+use std::cmp;
 use std::hash::Hash;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
@@ -607,6 +608,42 @@ impl CodeMap {
         self.span_until_char(sp, '{')
     }
 
+    /// Returns a new span representing just the end-point of this span
+    pub fn end_point(&self, sp: Span) -> Span {
+        let hi = sp.hi().0.checked_sub(1).unwrap_or(sp.hi().0);
+        let hi = self.get_start_of_char_bytepos(BytePos(hi));
+        let lo = cmp::max(hi.0, sp.lo().0);
+        sp.with_lo(BytePos(lo))
+    }
+
+    /// Returns a new span representing the next character after the end-point of this span
+    pub fn next_point(&self, sp: Span) -> Span {
+        let hi = sp.lo().0.checked_add(1).unwrap_or(sp.lo().0);
+        let hi = self.get_start_of_char_bytepos(BytePos(hi));
+        let lo = cmp::max(sp.hi().0, hi.0);
+        Span::new(BytePos(lo), BytePos(lo), sp.ctxt())
+    }
+
+    fn get_start_of_char_bytepos(&self, bpos: BytePos) -> BytePos {
+        let idx = self.lookup_filemap_idx(bpos);
+        let files = self.files.borrow();
+        let map = &(*files)[idx];
+
+        for mbc in map.multibyte_chars.borrow().iter() {
+            if mbc.pos < bpos {
+                if bpos.to_usize() >= mbc.pos.to_usize() + mbc.bytes {
+                    // If we do, then return the start of the character.
+                    return mbc.pos;
+                }
+            } else {
+                break;
+            }
+        }
+
+        // If this isn't a multibyte character, return the original position.
+        return bpos;
+    }
+
     pub fn get_filemap(&self, filename: &FileName) -> Option<Rc<FileMap>> {
         for fm in self.files.borrow().iter() {
             if *filename == fm.name {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d393cab4718..e8e87e2854b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -704,13 +704,15 @@ impl<'a> Parser<'a> {
                     expect.clone()
                 };
                 (format!("expected one of {}, found `{}`", expect, actual),
-                 (self.prev_span.next_point(), format!("expected one of {} here", short_expect)))
+                 (self.sess.codemap().next_point(self.prev_span),
+                  format!("expected one of {} here", short_expect)))
             } else if expected.is_empty() {
                 (format!("unexpected token: `{}`", actual),
                  (self.prev_span, "unexpected token after this".to_string()))
             } else {
                 (format!("expected {}, found `{}`", expect, actual),
-                 (self.prev_span.next_point(), format!("expected {} here", expect)))
+                 (self.sess.codemap().next_point(self.prev_span),
+                  format!("expected {} here", expect)))
             };
             let mut err = self.fatal(&msg_exp);
             let sp = if self.token == token::Token::Eof {
@@ -3190,7 +3192,7 @@ impl<'a> Parser<'a> {
         // return. This won't catch blocks with an explicit `return`, but that would be caught by
         // the dead code lint.
         if self.eat_keyword(keywords::Else) || !cond.returns() {
-            let sp = lo.next_point();
+            let sp = self.sess.codemap().next_point(lo);
             let mut err = self.diagnostic()
                 .struct_span_err(sp, "missing condition for `if` statemement");
             err.span_label(sp, "expected if condition here");