about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNick Cameron <nrc@ncameron.org>2019-01-17 20:22:36 +1300
committerGitHub <noreply@github.com>2019-01-17 20:22:36 +1300
commitd2e91b5b68f4b163ab1c041e72028f33a9e3e075 (patch)
tree30e00c41758857082b872560949b1a73ee18ef02 /src
parenta01990c4d0f6415a1e4824cf109125effacaaa81 (diff)
parent083a20fb1aee4daef685735652ae21e9b370350d (diff)
Merge pull request #3284 from scampi/issue-3270
recognize strings inside comments in order to avoid indenting them
Diffstat (limited to 'src')
-rw-r--r--src/comment.rs84
-rw-r--r--src/utils.rs18
2 files changed, 82 insertions, 20 deletions
diff --git a/src/comment.rs b/src/comment.rs
index 3841424904f..4ceb2595e70 100644
--- a/src/comment.rs
+++ b/src/comment.rs
@@ -1047,21 +1047,28 @@ impl RichChar for (usize, char) {
 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
 enum CharClassesStatus {
     Normal,
+    /// Character is within a string
     LitString,
     LitStringEscape,
+    /// Character is within a raw string
     LitRawString(u32),
     RawStringPrefix(u32),
     RawStringSuffix(u32),
     LitChar,
     LitCharEscape,
-    // The u32 is the nesting deepness of the comment
+    /// Character inside a block comment, with the integer indicating the nesting deepness of the
+    /// comment
     BlockComment(u32),
-    // Status when the '/' has been consumed, but not yet the '*', deepness is
-    // the new deepness (after the comment opening).
+    /// Character inside a block-commented string, with the integer indicating the nesting deepness
+    /// of the comment
+    StringInBlockComment(u32),
+    /// Status when the '/' has been consumed, but not yet the '*', deepness is
+    /// the new deepness (after the comment opening).
     BlockCommentOpening(u32),
-    // Status when the '*' has been consumed, but not yet the '/', deepness is
-    // the new deepness (after the comment closing).
+    /// Status when the '*' has been consumed, but not yet the '/', deepness is
+    /// the new deepness (after the comment closing).
     BlockCommentClosing(u32),
+    /// Character is within a line comment
     LineComment,
 }
 
@@ -1085,6 +1092,12 @@ pub enum FullCodeCharKind {
     InComment,
     /// Last character of a comment, '\n' for a line comment, '/' for a block comment.
     EndComment,
+    /// Start of a mutlitine string inside a comment
+    StartStringCommented,
+    /// End of a mutlitine string inside a comment
+    EndStringCommented,
+    /// Inside a commented string
+    InStringCommented,
     /// Start of a mutlitine string
     StartString,
     /// End of a mutlitine string
@@ -1098,7 +1111,21 @@ impl FullCodeCharKind {
         match self {
             FullCodeCharKind::StartComment
             | FullCodeCharKind::InComment
-            | FullCodeCharKind::EndComment => true,
+            | FullCodeCharKind::EndComment
+            | FullCodeCharKind::StartStringCommented
+            | FullCodeCharKind::InStringCommented
+            | FullCodeCharKind::EndStringCommented => true,
+            _ => false,
+        }
+    }
+
+    /// Returns true if the character is inside a comment
+    pub fn inside_comment(self) -> bool {
+        match self {
+            FullCodeCharKind::InComment
+            | FullCodeCharKind::StartStringCommented
+            | FullCodeCharKind::InStringCommented
+            | FullCodeCharKind::EndStringCommented => true,
             _ => false,
         }
     }
@@ -1107,6 +1134,12 @@ impl FullCodeCharKind {
         self == FullCodeCharKind::InString || self == FullCodeCharKind::StartString
     }
 
+    /// Returns true if the character is within a commented string
+    pub fn is_commented_string(self) -> bool {
+        self == FullCodeCharKind::InStringCommented
+            || self == FullCodeCharKind::StartStringCommented
+    }
+
     fn to_codecharkind(self) -> CodeCharKind {
         if self.is_comment() {
             CodeCharKind::Comment
@@ -1250,18 +1283,27 @@ where
                 },
                 _ => CharClassesStatus::Normal,
             },
+            CharClassesStatus::StringInBlockComment(deepness) => {
+                char_kind = FullCodeCharKind::InStringCommented;
+                if chr == '"' {
+                    CharClassesStatus::BlockComment(deepness)
+                } else {
+                    CharClassesStatus::StringInBlockComment(deepness)
+                }
+            }
             CharClassesStatus::BlockComment(deepness) => {
                 assert_ne!(deepness, 0);
-                self.status = match self.base.peek() {
+                char_kind = FullCodeCharKind::InComment;
+                match self.base.peek() {
                     Some(next) if next.get_char() == '/' && chr == '*' => {
                         CharClassesStatus::BlockCommentClosing(deepness - 1)
                     }
                     Some(next) if next.get_char() == '*' && chr == '/' => {
                         CharClassesStatus::BlockCommentOpening(deepness + 1)
                     }
-                    _ => CharClassesStatus::BlockComment(deepness),
-                };
-                return Some((FullCodeCharKind::InComment, item));
+                    _ if chr == '"' => CharClassesStatus::StringInBlockComment(deepness),
+                    _ => self.status,
+                }
             }
             CharClassesStatus::BlockCommentOpening(deepness) => {
                 assert_eq!(chr, '*');
@@ -1317,26 +1359,33 @@ impl<'a> Iterator for LineClasses<'a> {
 
         let mut line = String::new();
 
-        let start_class = match self.base.peek() {
+        let start_kind = match self.base.peek() {
             Some((kind, _)) => *kind,
             None => unreachable!(),
         };
 
         while let Some((kind, c)) = self.base.next() {
+            // needed to set the kind of the ending character on the last line
+            self.kind = kind;
             if c == '\n' {
-                self.kind = match (start_class, kind) {
+                self.kind = match (start_kind, kind) {
                     (FullCodeCharKind::Normal, FullCodeCharKind::InString) => {
                         FullCodeCharKind::StartString
                     }
                     (FullCodeCharKind::InString, FullCodeCharKind::Normal) => {
                         FullCodeCharKind::EndString
                     }
+                    (FullCodeCharKind::InComment, FullCodeCharKind::InStringCommented) => {
+                        FullCodeCharKind::StartStringCommented
+                    }
+                    (FullCodeCharKind::InStringCommented, FullCodeCharKind::InComment) => {
+                        FullCodeCharKind::EndStringCommented
+                    }
                     _ => kind,
                 };
                 break;
-            } else {
-                line.push(c);
             }
+            line.push(c);
         }
 
         // Workaround for CRLF newline.
@@ -1382,7 +1431,12 @@ impl<'a> Iterator for UngroupedCommentCodeSlices<'a> {
             }
             FullCodeCharKind::StartComment => {
                 // Consume the whole comment
-                while let Some((FullCodeCharKind::InComment, (_, _))) = self.iter.next() {}
+                loop {
+                    match self.iter.next() {
+                        Some((kind, ..)) if kind.inside_comment() => continue,
+                        _ => break,
+                    }
+                }
             }
             _ => panic!(),
         }
diff --git a/src/utils.rs b/src/utils.rs
index 9efe57e7277..3c260cae22e 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -22,7 +22,7 @@ use syntax::source_map::{BytePos, Span, NO_EXPANSION};
 use syntax_pos::Mark;
 
 use comment::{filter_normal_code, CharClasses, FullCodeCharKind, LineClasses};
-use config::Config;
+use config::{Config, Version};
 use rewrite::RewriteContext;
 use shape::{Indent, Shape};
 
@@ -527,8 +527,11 @@ pub fn trim_left_preserve_layout(orig: &str, indent: Indent, config: &Config) ->
                 Some(get_prefix_space_width(config, &line))
             };
 
-            let line = if veto_trim || (kind.is_string() && !line.ends_with('\\')) {
-                veto_trim = kind.is_string() && !line.ends_with('\\');
+            let new_veto_trim_value = (kind.is_string()
+                || (config.version() == Version::Two && kind.is_commented_string()))
+                && !line.ends_with('\\');
+            let line = if veto_trim || new_veto_trim_value {
+                veto_trim = new_veto_trim_value;
                 trimmed = false;
                 line
             } else {
@@ -536,9 +539,14 @@ pub fn trim_left_preserve_layout(orig: &str, indent: Indent, config: &Config) ->
             };
             trimmed_lines.push((trimmed, line, prefix_space_width));
 
-            // When computing the minimum, do not consider lines within a string.
-            // The reason is there is a veto against trimming and indenting such lines
+            // Because there is a veto against trimming and indenting lines within a string,
+            // such lines should not be taken into account when computing the minimum.
             match kind {
+                FullCodeCharKind::InStringCommented | FullCodeCharKind::EndStringCommented
+                    if config.version() == Version::Two =>
+                {
+                    None
+                }
                 FullCodeCharKind::InString | FullCodeCharKind::EndString => None,
                 _ => prefix_space_width,
             }