]> git.lizzy.rs Git - rust.git/commitdiff
Fix the length displayed for byte string literals with escaped newlines
authorNoritada Kobayashi <noritada.kobayashi@gmail.com>
Mon, 7 Nov 2022 10:25:07 +0000 (19:25 +0900)
committerNoritada Kobayashi <noritada.kobayashi@gmail.com>
Mon, 7 Nov 2022 11:07:16 +0000 (20:07 +0900)
The length of byte strings containing escaped newlines is displayed two
bytes longer when the first escaped character is a newline.

This is due to a small bug in handling the first escaped newline in
string literals.

Closes #13567

crates/syntax/src/ast/token_ext.rs

index ba72e64425b23c095063a54e3aa7cf1edef2e618..22ad6db9aef37cec65100abf8e937388c2381f26 100644 (file)
@@ -209,17 +209,19 @@ pub fn value(&self) -> Option<Cow<'_, str>> {
         let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 
         let mut buf = String::new();
-        let mut text_iter = text.chars();
+        let mut prev = 0;
         let mut has_error = false;
         unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
             (Ok(c), false) => buf.push(c),
-            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
+            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => {
+                prev = char_range.end
+            }
             (Ok(c), true) => {
                 buf.reserve_exact(text.len());
-                buf.push_str(&text[..char_range.start]);
+                buf.push_str(&text[..prev]);
                 buf.push(c);
             }
             (Err(_), _) => has_error = true,
@@ -252,17 +254,19 @@ pub fn value(&self) -> Option<Cow<'_, [u8]>> {
         let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 
         let mut buf: Vec<u8> = Vec::new();
-        let mut text_iter = text.chars();
+        let mut prev = 0;
         let mut has_error = false;
         unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
             (Ok(c), false) => buf.push(c as u8),
-            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
+            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => {
+                prev = char_range.end
+            }
             (Ok(c), true) => {
                 buf.reserve_exact(text.len());
-                buf.extend_from_slice(text[..char_range.start].as_bytes());
+                buf.extend_from_slice(text[..prev].as_bytes());
                 buf.push(c as u8);
             }
             (Err(_), _) => has_error = true,
@@ -445,6 +449,12 @@ fn test_string_escape() {
         check_string_value(r"\foobar", None);
         check_string_value(r"\nfoobar", "\nfoobar");
         check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
+        check_string_value(r"\x61bcde", "a\x62cde");
+        check_string_value(
+            r"a\
+bcde", "a\
+bcde",
+        );
     }
 
     #[test]