From 7c44d453c88fe0a981f823f264cd03a3805da862 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 10 Sep 2024 18:48:54 +0300 Subject: [PATCH] Correctly escape strings in our quote macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a small change, but it was the cause of 90% of the errors in `rust-analyzer diagnostics .` 🫢 With this change and #18085 together, all remaining errors are type errors. This may mean we can enable more errors, but this is out of scope for this PR. --- .../macro_expansion_tests/builtin_fn_macro.rs | 18 ++++++++++++++++++ crates/hir-expand/src/builtin/fn_macro.rs | 8 ++++---- crates/hir-expand/src/builtin/quote.rs | 5 +++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 37ae1ab39b49..a3b48831a0b0 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -528,3 +528,21 @@ fn main() { foobar; } "##]], ); } + +#[test] +fn test_quote_string() { + check( + r##" +#[rustc_builtin_macro] +macro_rules! stringify {} + +fn main() { stringify!("hello"); } +"##, + expect![[r##" +#[rustc_builtin_macro] +macro_rules! stringify {} + +fn main() { "\"hello\""; } +"##]], + ); +} diff --git a/crates/hir-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs index 15fed45caf02..d04225b87227 100644 --- a/crates/hir-expand/src/builtin/fn_macro.rs +++ b/crates/hir-expand/src/builtin/fn_macro.rs @@ -483,7 +483,7 @@ fn concat_expand( match it.kind { tt::LitKind::Char => { if let Ok(c) = unescape_char(it.symbol.as_str()) { - text.extend(c.escape_default()); + text.push(c); } record_span(it.span); } @@ -491,11 +491,11 @@ fn concat_expand( format_to!(text, "{}", it.symbol.as_str()) } tt::LitKind::Str => { - text.push_str(it.symbol.as_str()); + text.push_str(unescape_str(&it.symbol).as_str()); record_span(it.span); } tt::LitKind::StrRaw(_) => { - format_to!(text, "{}", it.symbol.as_str().escape_debug()); + format_to!(text, "{}", it.symbol.as_str()); record_span(it.span); } tt::LitKind::Byte @@ -813,7 +813,7 @@ fn include_str_expand( fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option { let krate = db.lookup_intern_macro_call(arg_id).krate; - db.crate_graph()[krate].env.get(key.as_str()).map(|it| it.escape_debug().to_string()) + db.crate_graph()[krate].env.get(key.as_str()) } fn env_expand( diff --git a/crates/hir-expand/src/builtin/quote.rs b/crates/hir-expand/src/builtin/quote.rs index 5c33f817f9e4..fc248c906dac 100644 --- a/crates/hir-expand/src/builtin/quote.rs +++ b/crates/hir-expand/src/builtin/quote.rs @@ -3,6 +3,7 @@ use intern::{sym, Symbol}; use span::Span; +use syntax::ToSmolStr; use tt::IdentIsRaw; use crate::name::Name; @@ -211,8 +212,8 @@ impl_to_to_tokentrees! { _span: crate::tt::Literal => self { self }; _span: crate::tt::Ident => self { self }; _span: crate::tt::Punct => self { self }; - span: &str => self { crate::tt::Literal{symbol: Symbol::intern(self), span, kind: tt::LitKind::Str, suffix: None }}; - span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self), span, kind: tt::LitKind::Str, suffix: None }}; + span: &str => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }}; + span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }}; span: Name => self { let (is_raw, s) = IdentIsRaw::split_from_symbol(self.as_str()); crate::tt::Ident{sym: Symbol::intern(s), span, is_raw }