about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorPatrick McCarter <p.mccarter@gmail.com>2019-02-16 19:56:30 -0500
committerPatrick McCarter <p.mccarter@gmail.com>2019-02-16 19:56:30 -0500
commitc34aac7b1703edc9ef4ebaa17c16b96a18ca1443 (patch)
treef346a3ef97e724a87f8def9bc26594788d037280 /src/libsyntax/parse
parenteac09088e1a8fc8a293028764e4e84da29469205 (diff)
downloadrust-c34aac7b1703edc9ef4ebaa17c16b96a18ca1443.tar.gz
rust-c34aac7b1703edc9ef4ebaa17c16b96a18ca1443.zip
help suggestion when trying to delimit string literals with directed unicode quotes #58436
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/lexer/mod.rs22
-rw-r--r--src/libsyntax/parse/lexer/unicode_chars.rs31
2 files changed, 44 insertions, 9 deletions
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index babe0eef20f..a7cde5fbb92 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -125,6 +125,28 @@ impl<'a> StringReader<'a> {
         Ok(ret_val)
     }
 
+    /// Immutably extract string if found at current position with given delimiters
+    pub fn peek_delimited(&self, from_ch: char, to_ch: char) -> Option<String> {
+        let mut pos = self.pos;
+        let mut idx = self.src_index(pos);
+        let mut ch = char_at(&self.src, idx);
+        if ch != from_ch {
+            return None;
+        }
+        pos = pos + Pos::from_usize(ch.len_utf8());
+        let start_pos = pos;
+        idx = self.src_index(pos);
+        while idx < self.end_src_index {
+            ch = char_at(&self.src, idx);
+            if ch == to_ch {
+                return Some(self.src[self.src_index(start_pos)..self.src_index(pos)].to_string());
+            }
+            pos = pos + Pos::from_usize(ch.len_utf8());
+            idx = self.src_index(pos);
+        }
+        return None;
+    }
+
     fn try_real_token(&mut self) -> Result<TokenAndSpan, ()> {
         let mut t = self.try_next_token()?;
         loop {
diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index 7da4284c0e4..94ce6297fbe 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -1,7 +1,7 @@
 // Characters and their corresponding confusables were collected from
 // http://www.unicode.org/Public/security/10.0.0/confusables.txt
 
-use syntax_pos::{Span, NO_EXPANSION};
+use syntax_pos::{Span, Pos, NO_EXPANSION};
 use errors::{Applicability, DiagnosticBuilder};
 use super::StringReader;
 
@@ -333,14 +333,27 @@ crate fn check_for_substitution<'a>(reader: &StringReader<'a>,
         let span = Span::new(reader.pos, reader.next_pos, NO_EXPANSION);
         match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) {
             Some(&(ascii_char, ascii_name)) => {
-                let msg =
-                    format!("Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
-                            ch, u_name, ascii_char, ascii_name);
-                err.span_suggestion(
-                    span,
-                    &msg,
-                    ascii_char.to_string(),
-                    Applicability::MaybeIncorrect);
+                // special help suggestion for "directed" double quotes
+                if let Some(s) = reader.peek_delimited('“', '”') {
+                    let msg = format!("Unicode characters '“' (Left Double Quotation Mark) and \
+                        '”' (Right Double Quotation Mark) look like '{}' ({}), but are not",
+                                ascii_char, ascii_name);
+                    err.span_suggestion(
+                        Span::new(reader.pos, reader.next_pos + Pos::from_usize(s.len()) +
+                            Pos::from_usize('”'.len_utf8()), NO_EXPANSION),
+                        &msg,
+                        format!("\"{}\"", s),
+                        Applicability::MaybeIncorrect);
+                } else {
+                    let msg =
+                        format!("Unicode character '{}' ({}) looks like '{}' ({}), but it is not",
+                                ch, u_name, ascii_char, ascii_name);
+                    err.span_suggestion(
+                        span,
+                        &msg,
+                        ascii_char.to_string(),
+                        Applicability::MaybeIncorrect);
+                }
                 true
             },
             None => {