mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-13 08:27:17 +00:00
Auto merge of #12942 - lowr:fix/concat-with-char, r=Veykril
fix: make `concat!` work with char
Fixes #12921
- I avoided making `unquote_str()` take char literals as well because it's depended on by another function `parse_string()` that's only supposed to take strings.
- Even with this patch, we don't output `\0` as `\u{0}` which #12921 pointed out ~~, but we're not actually responsible for serializing it but rowan is~~. They are functionally equivalent and I don't think it'd cause any confusion, but we *could* try escaping them before serialization (for reference, `rustc -Zunpretty=expanded`, which `cargo expand` uses under the hood, [makes use of `str::escape_default()`](3830ecaa8d/compiler/rustc_ast/src/util/literal.rs (L161)
).
This commit is contained in:
commit
b569bbbacc
3 changed files with 16 additions and 6 deletions
|
@ -295,13 +295,13 @@ fn test_concat_expand() {
|
|||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {}
|
||||
|
||||
fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false); }
|
||||
fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '"', '\0'); }
|
||||
"##,
|
||||
expect![[r##"
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {}
|
||||
|
||||
fn main() { "foor0bar\nfalse"; }
|
||||
fn main() { "foor0bar\nfalse\"\u{0}"; }
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -357,6 +357,12 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> {
|
|||
token.value().map(|it| it.into_owned())
|
||||
}
|
||||
|
||||
fn unquote_char(lit: &tt::Literal) -> Option<char> {
|
||||
let lit = ast::make::tokens::literal(&lit.to_string());
|
||||
let token = ast::Char::cast(lit)?;
|
||||
token.value()
|
||||
}
|
||||
|
||||
fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
|
||||
let lit = ast::make::tokens::literal(&lit.to_string());
|
||||
let token = ast::ByteString::cast(lit)?;
|
||||
|
@ -408,8 +414,12 @@ fn concat_expand(
|
|||
// concat works with string and char literals, so remove any quotes.
|
||||
// It also works with integer, float and boolean literals, so just use the rest
|
||||
// as-is.
|
||||
let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
|
||||
text.push_str(&component);
|
||||
if let Some(c) = unquote_char(it) {
|
||||
text.push(c);
|
||||
} else {
|
||||
let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
|
||||
text.push_str(&component);
|
||||
}
|
||||
}
|
||||
// handle boolean literals
|
||||
tt::TokenTree::Leaf(tt::Leaf::Ident(id))
|
||||
|
|
|
@ -196,8 +196,8 @@ impl_to_to_tokentrees! {
|
|||
tt::Literal => self { self };
|
||||
tt::Ident => self { self };
|
||||
tt::Punct => self { self };
|
||||
&str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}};
|
||||
String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}
|
||||
&str => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}};
|
||||
String => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Reference in a new issue