diff options
| author | roife <roifewu@gmail.com> | 2024-04-19 16:42:07 +0800 |
|---|---|---|
| committer | roife <roifewu@gmail.com> | 2024-04-19 20:32:53 +0800 |
| commit | 3e232bb78a362cb33420c329e7d17438987a9fb9 (patch) | |
| tree | 02dc4a594e3de5295ca98e1d8d264383ccd3c6db | |
| parent | a543516ea4e3f14e56fb6b04cce79e203ebab517 (diff) | |
| download | rust-3e232bb78a362cb33420c329e7d17438987a9fb9.tar.gz rust-3e232bb78a362cb33420c329e7d17438987a9fb9.zip | |
fix: replace unescape fn with the one in ra-ap-rustc_lexer
| -rw-r--r-- | crates/hir-expand/src/attrs.rs | 64 | ||||
| -rw-r--r-- | crates/syntax/src/lib.rs | 1 |
2 files changed, 31 insertions, 34 deletions
diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs index 7782b0fc81f..f8bf88d83cd 100644 --- a/crates/hir-expand/src/attrs.rs +++ b/crates/hir-expand/src/attrs.rs @@ -8,6 +8,7 @@ use intern::Interned; use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct}; use smallvec::{smallvec, SmallVec}; use span::{Span, SyntaxContextId}; +use syntax::unescape; use syntax::{ast, format_smolstr, match_ast, AstNode, AstToken, SmolStr, SyntaxNode}; use triomphe::ThinArc; @@ -54,8 +55,7 @@ impl RawAttrs { Attr { id, input: Some(Interned::new(AttrInput::Literal(tt::Literal { - // FIXME: Escape quotes from comment content - text: SmolStr::new(format_smolstr!("\"{doc}\"",)), + text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))), span, }))), path: Interned::new(ModPath::from(crate::name!(doc))), @@ -74,6 +74,10 @@ impl RawAttrs { RawAttrs { entries } } + fn escape_chars(s: &str) -> String { + s.replace('\\', r#"\\"#).replace('"', r#"\""#) + } + pub fn from_attrs_owner( db: &dyn ExpandDatabase, owner: InFile<&dyn ast::HasAttrs>, @@ -303,9 +307,7 @@ impl Attr { Some(it) => { it.trim_matches('#').strip_prefix('"')?.strip_suffix('"').map(Cow::Borrowed) } - None => { - it.text.strip_prefix('"')?.strip_suffix('"').and_then(unescape).map(Cow::Owned) - } + None => it.text.strip_prefix('"')?.strip_suffix('"').and_then(unescape), }, _ => None, } @@ -360,37 +362,31 @@ impl Attr { } } -fn unescape(s: &str) -> Option<String> { - let mut res = String::with_capacity(s.len()); - let mut chars = s.chars(); - - while let Some(c) = chars.next() { - if c == '\\' { - match chars.next()? { - 'n' => res.push('\n'), - 'r' => res.push('\r'), - 't' => res.push('\t'), - '\\' => res.push('\\'), - '\'' => res.push('\''), - '"' => res.push('"'), - '0' => res.push('\0'), - 'x' => { - let hex = chars.by_ref().take(2).collect::<String>(); - let c = u8::from_str_radix(&hex, 16).ok()?; - res.push(c as char); - } - 'u' => { - let hex = chars.by_ref().take(4).collect::<String>(); - let c = u32::from_str_radix(&hex, 16).ok()?; - res.push(char::from_u32(c)?); - } - _ => return None, - } - } else { - res.push(c); +fn unescape(s: &str) -> Option<Cow<'_, str>> { + let mut buf = String::new(); + let mut prev_end = 0; + let mut has_error = false; + unescape::unescape_unicode(s, unescape::Mode::Str, &mut |char_range, unescaped_char| match ( + unescaped_char, + buf.capacity() == 0, + ) { + (Ok(c), false) => buf.push(c), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end + } + (Ok(c), true) => { + buf.reserve_exact(s.len()); + buf.push_str(&s[..prev_end]); + buf.push(c); } + (Err(_), _) => has_error = true, + }); + + match (has_error, buf.capacity() == 0) { + (true, _) => None, + (false, false) => Some(Cow::Owned(buf)), + (false, true) => Some(Cow::Borrowed(s)), } - Some(res) } pub fn collect_attrs( diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index e7bbf936dc1..3a9ebafe87d 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -65,6 +65,7 @@ pub use rowan::{ api::Preorder, Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent, }; +pub use rustc_lexer::unescape; pub use smol_str::{format_smolstr, SmolStr}; /// `Parse` is the result of the parsing: a syntax tree and a collection of |
