|
2 | 2 |
|
3 | 3 | use std::borrow::Cow;
|
4 | 4 |
|
5 |
| -use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode}; |
| 5 | +use rustc_lexer::unescape::{ |
| 6 | + unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode, |
| 7 | +}; |
6 | 8 |
|
7 | 9 | use crate::{
|
8 | 10 | ast::{self, AstToken},
|
@@ -285,45 +287,70 @@ impl ast::ByteString {
|
285 | 287 |
|
286 | 288 | impl IsString for ast::CString {
|
287 | 289 | const RAW_PREFIX: &'static str = "cr";
|
288 |
| - // XXX: `Mode::CStr` is not supported by `unescape_literal` of ra-ap-rustc_lexer yet. |
289 |
| - // Here we pretend it to be a byte string. |
290 |
| - const MODE: Mode = Mode::ByteStr; |
| 290 | + const MODE: Mode = Mode::CStr; |
| 291 | + |
| 292 | + fn escaped_char_ranges( |
| 293 | + &self, |
| 294 | + cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>), |
| 295 | + ) { |
| 296 | + let text_range_no_quotes = match self.text_range_between_quotes() { |
| 297 | + Some(it) => it, |
| 298 | + None => return, |
| 299 | + }; |
| 300 | + |
| 301 | + let start = self.syntax().text_range().start(); |
| 302 | + let text = &self.text()[text_range_no_quotes - start]; |
| 303 | + let offset = text_range_no_quotes.start() - start; |
| 304 | + |
| 305 | + unescape_c_string(text, Self::MODE, &mut |range, unescaped_char| { |
| 306 | + let text_range = |
| 307 | + TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap()); |
| 308 | + // XXX: This method should only be used for highlighting ranges. The unescaped |
| 309 | + // char/byte is not used. For simplicity, we return an arbitrary placeholder char. |
| 310 | + cb(text_range + offset, unescaped_char.map(|_| ' ')); |
| 311 | + }); |
| 312 | + } |
291 | 313 | }
|
292 | 314 |
|
293 | 315 | impl ast::CString {
|
294 |
| - pub fn value(&self) -> Option<Cow<'_, str>> { |
| 316 | + pub fn value(&self) -> Option<Cow<'_, [u8]>> { |
295 | 317 | if self.is_raw() {
|
296 | 318 | let text = self.text();
|
297 | 319 | let text =
|
298 | 320 | &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
299 |
| - return Some(Cow::Borrowed(text)); |
| 321 | + return Some(Cow::Borrowed(text.as_bytes())); |
300 | 322 | }
|
301 | 323 |
|
302 | 324 | let text = self.text();
|
303 | 325 | let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
304 | 326 |
|
305 |
| - let mut buf = String::new(); |
| 327 | + let mut buf = Vec::new(); |
306 | 328 | let mut prev_end = 0;
|
307 | 329 | let mut has_error = false;
|
308 |
| - unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match ( |
309 |
| - unescaped_char, |
| 330 | + let mut char_buf = [0u8; 4]; |
| 331 | + let mut extend_unit = |buf: &mut Vec<u8>, unit: CStrUnit| match unit { |
| 332 | + CStrUnit::Byte(b) => buf.push(b), |
| 333 | + CStrUnit::Char(c) => buf.extend(c.encode_utf8(&mut char_buf).as_bytes()), |
| 334 | + }; |
| 335 | + unescape_c_string(text, Self::MODE, &mut |char_range, unescaped| match ( |
| 336 | + unescaped, |
310 | 337 | buf.capacity() == 0,
|
311 | 338 | ) {
|
312 |
| - (Ok(c), false) => buf.push(c), |
| 339 | + (Ok(u), false) => extend_unit(&mut buf, u), |
313 | 340 | (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
|
314 | 341 | prev_end = char_range.end
|
315 | 342 | }
|
316 |
| - (Ok(c), true) => { |
| 343 | + (Ok(u), true) => { |
317 | 344 | buf.reserve_exact(text.len());
|
318 |
| - buf.push_str(&text[..prev_end]); |
319 |
| - buf.push(c); |
| 345 | + buf.extend(text[..prev_end].as_bytes()); |
| 346 | + extend_unit(&mut buf, u); |
320 | 347 | }
|
321 | 348 | (Err(_), _) => has_error = true,
|
322 | 349 | });
|
323 | 350 |
|
324 | 351 | match (has_error, buf.capacity() == 0) {
|
325 | 352 | (true, _) => None,
|
326 |
| - (false, true) => Some(Cow::Borrowed(text)), |
| 353 | + (false, true) => Some(Cow::Borrowed(text.as_bytes())), |
327 | 354 | (false, false) => Some(Cow::Owned(buf)),
|
328 | 355 | }
|
329 | 356 | }
|
|
0 commit comments