aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/syntax/src/ast/token_ext.rs27
1 files changed, 18 insertions, 9 deletions
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index ac0326420..b985861f2 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -130,19 +130,28 @@ impl ast::String {
130 let text = self.text().as_str(); 130 let text = self.text().as_str();
131 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; 131 let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
132 132
133 let mut buf = String::with_capacity(text.len()); 133 let mut buf = String::new();
134 let mut text_iter = text.chars();
134 let mut has_error = false; 135 let mut has_error = false;
135 unescape_literal(text, Mode::Str, &mut |_, unescaped_char| match unescaped_char { 136 unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
136 Ok(c) => buf.push(c), 137 unescaped_char,
137 Err(_) => has_error = true, 138 buf.capacity() == 0,
139 ) {
140 (Ok(c), false) => buf.push(c),
141 (Ok(c), true) if Some(c) == text_iter.next() => (),
142 (Ok(c), true) => {
143 buf.reserve_exact(text.len());
144 buf.push_str(&text[..char_range.start]);
145 buf.push(c);
146 }
147 (Err(_), _) => has_error = true,
138 }); 148 });
139 149
140 if has_error { 150 match (has_error, buf.capacity() == 0) {
141 return None; 151 (true, _) => None,
152 (false, true) => Some(Cow::Borrowed(text)),
153 (false, false) => Some(Cow::Owned(buf)),
142 } 154 }
143 // FIXME: don't actually allocate for borrowed case
144 let res = if buf == text { Cow::Borrowed(text) } else { Cow::Owned(buf) };
145 Some(res)
146 } 155 }
147 156
148 pub fn quote_offsets(&self) -> Option<QuoteOffsets> { 157 pub fn quote_offsets(&self) -> Option<QuoteOffsets> {