]> git.lizzy.rs Git - rust.git/blobdiff - src/comment.rs
Merge pull request #3035 from topecongiro/issue-3006
[rust.git] / src / comment.rs
index 4f2f813166b09d1080cd03fa0635d1804d100316..17ec29c3cbc575788748ebee2b76a1480658c788 100644 (file)
@@ -13,7 +13,7 @@
 use std::{self, borrow::Cow, iter};
 
 use itertools::{multipeek, MultiPeek};
-use syntax::codemap::Span;
+use syntax::source_map::Span;
 
 use config::Config;
 use rewrite::RewriteContext;
@@ -47,7 +47,7 @@ fn custom_opener(s: &str) -> &str {
     s.lines().next().map_or("", |first_line| {
         first_line
             .find(' ')
-            .map_or(first_line, |space_index| &first_line[0..space_index + 1])
+            .map_or(first_line, |space_index| &first_line[0..=space_index])
     })
 }
 
@@ -525,7 +525,7 @@ fn rewrite_comment_inner(
 
 const RUSTFMT_CUSTOM_COMMENT_PREFIX: &str = "//#### ";
 
-fn hide_sharp_behind_comment<'a>(s: &'a str) -> Cow<'a, str> {
+fn hide_sharp_behind_comment(s: &str) -> Cow<str> {
     if s.trim_left().starts_with("# ") {
         Cow::from(format!("{}{}", RUSTFMT_CUSTOM_COMMENT_PREFIX, s))
     } else {
@@ -785,6 +785,9 @@ enum CharClassesStatus {
     Normal,
     LitString,
     LitStringEscape,
+    LitRawString(u32),
+    RawStringPrefix(u32),
+    RawStringSuffix(u32),
     LitChar,
     LitCharEscape,
     // The u32 is the nesting deepness of the comment
@@ -818,13 +821,17 @@ pub enum FullCodeCharKind {
     InComment,
     /// Last character of a comment, '\n' for a line comment, '/' for a block comment.
     EndComment,
+    /// Start of a mutlitine string
+    StartString,
+    /// End of a mutlitine string
+    EndString,
     /// Inside a string.
     InString,
 }
 
 impl FullCodeCharKind {
-    pub fn is_comment(&self) -> bool {
-        match *self {
+    pub fn is_comment(self) -> bool {
+        match self {
             FullCodeCharKind::StartComment
             | FullCodeCharKind::InComment
             | FullCodeCharKind::EndComment => true,
@@ -832,11 +839,11 @@ pub fn is_comment(&self) -> bool {
         }
     }
 
-    pub fn is_string(&self) -> bool {
-        *self == FullCodeCharKind::InString
+    pub fn is_string(self) -> bool {
+        self == FullCodeCharKind::InString || self == FullCodeCharKind::StartString
     }
 
-    fn to_codecharkind(&self) -> CodeCharKind {
+    fn to_codecharkind(self) -> CodeCharKind {
         if self.is_comment() {
             CodeCharKind::Comment
         } else {
@@ -858,6 +865,20 @@ pub fn new(base: T) -> CharClasses<T> {
     }
 }
 
+fn is_raw_string_suffix<T>(iter: &mut MultiPeek<T>, count: u32) -> bool
+where
+    T: Iterator,
+    T::Item: RichChar,
+{
+    for _ in 0..count {
+        match iter.peek() {
+            Some(c) if c.get_char() == '#' => continue,
+            _ => return false,
+        }
+    }
+    true
+}
+
 impl<T> Iterator for CharClasses<T>
 where
     T: Iterator,
@@ -870,17 +891,51 @@ fn next(&mut self) -> Option<(FullCodeCharKind, T::Item)> {
         let chr = item.get_char();
         let mut char_kind = FullCodeCharKind::Normal;
         self.status = match self.status {
-            CharClassesStatus::LitString => match chr {
-                '"' => CharClassesStatus::Normal,
-                '\\' => {
-                    char_kind = FullCodeCharKind::InString;
-                    CharClassesStatus::LitStringEscape
+            CharClassesStatus::LitRawString(sharps) => {
+                char_kind = FullCodeCharKind::InString;
+                match chr {
+                    '"' => {
+                        if sharps == 0 {
+                            char_kind = FullCodeCharKind::Normal;
+                            CharClassesStatus::Normal
+                        } else if is_raw_string_suffix(&mut self.base, sharps) {
+                            CharClassesStatus::RawStringSuffix(sharps)
+                        } else {
+                            CharClassesStatus::LitRawString(sharps)
+                        }
+                    }
+                    _ => CharClassesStatus::LitRawString(sharps),
                 }
-                _ => {
-                    char_kind = FullCodeCharKind::InString;
-                    CharClassesStatus::LitString
+            }
+            CharClassesStatus::RawStringPrefix(sharps) => {
+                char_kind = FullCodeCharKind::InString;
+                match chr {
+                    '#' => CharClassesStatus::RawStringPrefix(sharps + 1),
+                    '"' => CharClassesStatus::LitRawString(sharps),
+                    _ => CharClassesStatus::Normal, // Unreachable.
                 }
-            },
+            }
+            CharClassesStatus::RawStringSuffix(sharps) => {
+                match chr {
+                    '#' => {
+                        if sharps == 1 {
+                            CharClassesStatus::Normal
+                        } else {
+                            char_kind = FullCodeCharKind::InString;
+                            CharClassesStatus::RawStringSuffix(sharps - 1)
+                        }
+                    }
+                    _ => CharClassesStatus::Normal, // Unreachable
+                }
+            }
+            CharClassesStatus::LitString => {
+                char_kind = FullCodeCharKind::InString;
+                match chr {
+                    '"' => CharClassesStatus::Normal,
+                    '\\' => CharClassesStatus::LitStringEscape,
+                    _ => CharClassesStatus::LitString,
+                }
+            }
             CharClassesStatus::LitStringEscape => {
                 char_kind = FullCodeCharKind::InString;
                 CharClassesStatus::LitString
@@ -892,6 +947,13 @@ fn next(&mut self) -> Option<(FullCodeCharKind, T::Item)> {
             },
             CharClassesStatus::LitCharEscape => CharClassesStatus::LitChar,
             CharClassesStatus::Normal => match chr {
+                'r' => match self.base.peek().map(|c| c.get_char()) {
+                    Some('#') | Some('"') => {
+                        char_kind = FullCodeCharKind::InString;
+                        CharClassesStatus::RawStringPrefix(0)
+                    }
+                    _ => CharClassesStatus::Normal,
+                },
                 '"' => {
                     char_kind = FullCodeCharKind::InString;
                     CharClassesStatus::LitString
@@ -987,15 +1049,26 @@ impl<'a> Iterator for LineClasses<'a> {
     type Item = (FullCodeCharKind, String);
 
     fn next(&mut self) -> Option<Self::Item> {
-        if self.base.peek().is_none() {
-            return None;
-        }
+        self.base.peek()?;
 
         let mut line = String::new();
 
+        let start_class = match self.base.peek() {
+            Some((kind, _)) => *kind,
+            None => FullCodeCharKind::Normal,
+        };
+
         while let Some((kind, c)) = self.base.next() {
-            self.kind = kind;
             if c == '\n' {
+                self.kind = match (start_class, kind) {
+                    (FullCodeCharKind::Normal, FullCodeCharKind::InString) => {
+                        FullCodeCharKind::StartString
+                    }
+                    (FullCodeCharKind::InString, FullCodeCharKind::Normal) => {
+                        FullCodeCharKind::EndString
+                    }
+                    _ => kind,
+                };
                 break;
             } else {
                 line.push(c);
@@ -1151,10 +1224,10 @@ pub fn recover_comment_removed(
         // We missed some comments. Warn and keep the original text.
         if context.config.error_on_unformatted() {
             context.report.append(
-                context.codemap.span_to_filename(span).into(),
+                context.source_map.span_to_filename(span).into(),
                 vec![FormattingError::from_span(
-                    &span,
-                    &context.codemap,
+                    span,
+                    &context.source_map,
                     ErrorKind::LostComment,
                 )],
             );
@@ -1168,13 +1241,16 @@ pub fn recover_comment_removed(
 pub fn filter_normal_code(code: &str) -> String {
     let mut buffer = String::with_capacity(code.len());
     LineClasses::new(code).for_each(|(kind, line)| match kind {
-        FullCodeCharKind::Normal | FullCodeCharKind::InString => {
+        FullCodeCharKind::Normal
+        | FullCodeCharKind::StartString
+        | FullCodeCharKind::InString
+        | FullCodeCharKind::EndString => {
             buffer.push_str(&line);
             buffer.push('\n');
         }
         _ => (),
     });
-    if !code.ends_with("\n") && buffer.ends_with("\n") {
+    if !code.ends_with('\n') && buffer.ends_with('\n') {
         buffer.pop();
     }
     buffer
@@ -1430,7 +1506,7 @@ fn check(haystack: &str, needle: &str, expected: Option<usize>) {
 
     #[test]
     fn test_remove_trailing_white_spaces() {
-        let s = format!("    r#\"\n        test\n    \"#");
+        let s = "    r#\"\n        test\n    \"#";
         assert_eq!(remove_trailing_white_spaces(&s), s);
     }