aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src')
-rw-r--r--crates/hir_expand/src/db.rs397
-rw-r--r--crates/hir_expand/src/hygiene.rs16
-rw-r--r--crates/hir_expand/src/lib.rs21
3 files changed, 222 insertions, 212 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 1e4b0cc19..3e9abd8a1 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -3,14 +3,14 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use base_db::{salsa, SourceDatabase}; 5use base_db::{salsa, SourceDatabase};
6use mbe::{ExpandError, ExpandResult, MacroDef, MacroRules}; 6use mbe::{ExpandError, ExpandResult};
7use parser::FragmentKind; 7use parser::FragmentKind;
8use syntax::{ 8use syntax::{
9 algo::diff, 9 algo::diff,
10 ast::{MacroStmts, NameOwner}, 10 ast::{self, NameOwner},
11 AstNode, GreenNode, Parse, 11 AstNode, GreenNode, Parse,
12 SyntaxKind::*, 12 SyntaxKind::*,
13 SyntaxNode, 13 SyntaxNode, SyntaxToken,
14}; 14};
15 15
16use crate::{ 16use crate::{
@@ -27,23 +27,28 @@ const TOKEN_LIMIT: usize = 524288;
27 27
28#[derive(Debug, Clone, Eq, PartialEq)] 28#[derive(Debug, Clone, Eq, PartialEq)]
29pub enum TokenExpander { 29pub enum TokenExpander {
30 MacroRules(mbe::MacroRules), 30 /// Old-style `macro_rules`.
31 MacroDef(mbe::MacroDef), 31 MacroRules { mac: mbe::MacroRules, def_site_token_map: mbe::TokenMap },
32 /// AKA macros 2.0.
33 MacroDef { mac: mbe::MacroDef, def_site_token_map: mbe::TokenMap },
34 /// Stuff like `line!` and `file!`.
32 Builtin(BuiltinFnLikeExpander), 35 Builtin(BuiltinFnLikeExpander),
36 /// `derive(Copy)` and such.
33 BuiltinDerive(BuiltinDeriveExpander), 37 BuiltinDerive(BuiltinDeriveExpander),
38 /// The thing we love the most here in rust-analyzer -- procedural macros.
34 ProcMacro(ProcMacroExpander), 39 ProcMacro(ProcMacroExpander),
35} 40}
36 41
37impl TokenExpander { 42impl TokenExpander {
38 pub fn expand( 43 fn expand(
39 &self, 44 &self,
40 db: &dyn AstDatabase, 45 db: &dyn AstDatabase,
41 id: LazyMacroId, 46 id: LazyMacroId,
42 tt: &tt::Subtree, 47 tt: &tt::Subtree,
43 ) -> mbe::ExpandResult<tt::Subtree> { 48 ) -> mbe::ExpandResult<tt::Subtree> {
44 match self { 49 match self {
45 TokenExpander::MacroRules(it) => it.expand(tt), 50 TokenExpander::MacroRules { mac, .. } => mac.expand(tt),
46 TokenExpander::MacroDef(it) => it.expand(tt), 51 TokenExpander::MacroDef { mac, .. } => mac.expand(tt),
47 TokenExpander::Builtin(it) => it.expand(db, id, tt), 52 TokenExpander::Builtin(it) => it.expand(db, id, tt),
48 // FIXME switch these to ExpandResult as well 53 // FIXME switch these to ExpandResult as well
49 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), 54 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(),
@@ -56,23 +61,23 @@ impl TokenExpander {
56 } 61 }
57 } 62 }
58 63
59 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { 64 pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
60 match self { 65 match self {
61 TokenExpander::MacroRules(it) => it.map_id_down(id), 66 TokenExpander::MacroRules { mac, .. } => mac.map_id_down(id),
62 TokenExpander::MacroDef(it) => it.map_id_down(id), 67 TokenExpander::MacroDef { mac, .. } => mac.map_id_down(id),
63 TokenExpander::Builtin(..) => id, 68 TokenExpander::Builtin(..)
64 TokenExpander::BuiltinDerive(..) => id, 69 | TokenExpander::BuiltinDerive(..)
65 TokenExpander::ProcMacro(..) => id, 70 | TokenExpander::ProcMacro(..) => id,
66 } 71 }
67 } 72 }
68 73
69 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { 74 pub(crate) fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
70 match self { 75 match self {
71 TokenExpander::MacroRules(it) => it.map_id_up(id), 76 TokenExpander::MacroRules { mac, .. } => mac.map_id_up(id),
72 TokenExpander::MacroDef(it) => it.map_id_up(id), 77 TokenExpander::MacroDef { mac, .. } => mac.map_id_up(id),
73 TokenExpander::Builtin(..) => (id, mbe::Origin::Call), 78 TokenExpander::Builtin(..)
74 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), 79 | TokenExpander::BuiltinDerive(..)
75 TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), 80 | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call),
76 } 81 }
77 } 82 }
78} 83}
@@ -82,28 +87,48 @@ impl TokenExpander {
82pub trait AstDatabase: SourceDatabase { 87pub trait AstDatabase: SourceDatabase {
83 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>; 88 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
84 89
90 /// Main public API -- parsis a hir file, not caring whether it's a real
91 /// file or a macro expansion.
85 #[salsa::transparent] 92 #[salsa::transparent]
86 fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>; 93 fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
87 94 /// Implementation for the macro case.
88 #[salsa::interned]
89 fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId;
90 fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>;
91 #[salsa::transparent]
92 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
93 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
94 fn parse_macro_expansion( 95 fn parse_macro_expansion(
95 &self, 96 &self,
96 macro_file: MacroFile, 97 macro_file: MacroFile,
97 ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>; 98 ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>;
98 fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>;
99
100 /// Firewall query that returns the error from the `macro_expand` query.
101 fn macro_expand_error(&self, macro_call: MacroCallId) -> Option<ExpandError>;
102 99
100 /// Macro ids. That's probably the tricksiest bit in rust-analyzer, and the
101 /// reason why we use salsa at all.
102 ///
103 /// We encode macro definitions into ids of macro calls, this what allows us
104 /// to be incremental.
105 #[salsa::interned]
106 fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId;
107 /// Certain built-in macros are eager (`format!(concat!("file: ", file!(), "{}"")), 92`).
108 /// For them, we actually want to encode the whole token tree as an argument.
103 #[salsa::interned] 109 #[salsa::interned]
104 fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; 110 fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId;
105 111
112 /// Lowers syntactic macro call to a token tree representation.
113 #[salsa::transparent]
114 fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
115 /// Extracts syntax node, corresponding to a macro call. That's a firewall
116 /// query, only typing in the macro call itself changes the returned
117 /// subtree.
118 fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>;
119 /// Gets the expander for this macro. This compiles declarative macros, and
120 /// just fetches procedural ones.
121 fn macro_def(&self, id: MacroDefId) -> Option<Arc<TokenExpander>>;
122
123 /// Expand macro call to a token tree. This query is LRUed (we keep 128 or so results in memory)
124 fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>;
125 /// Special case of the previous query for procedural macros. We can't LRU
126 /// proc macros, since they are not deterministic in general, and
127 /// non-determinism breaks salsa in a very, very, very bad way. @edwin0cheng
128 /// heroically debugged this once!
106 fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; 129 fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>;
130 /// Firewall query that returns the error from the `macro_expand` query.
131 fn macro_expand_error(&self, macro_call: MacroCallId) -> Option<ExpandError>;
107 132
108 fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>; 133 fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>;
109} 134}
@@ -115,36 +140,159 @@ pub trait AstDatabase: SourceDatabase {
115pub fn expand_hypothetical( 140pub fn expand_hypothetical(
116 db: &dyn AstDatabase, 141 db: &dyn AstDatabase,
117 actual_macro_call: MacroCallId, 142 actual_macro_call: MacroCallId,
118 hypothetical_args: &syntax::ast::TokenTree, 143 hypothetical_args: &ast::TokenTree,
119 token_to_map: syntax::SyntaxToken, 144 token_to_map: SyntaxToken,
120) -> Option<(SyntaxNode, syntax::SyntaxToken)> { 145) -> Option<(SyntaxNode, SyntaxToken)> {
121 let macro_file = MacroFile { macro_call_id: actual_macro_call };
122 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax()); 146 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax());
123 let range = 147 let range =
124 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; 148 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?;
125 let token_id = tmap_1.token_by_range(range)?; 149 let token_id = tmap_1.token_by_range(range)?;
126 let macro_def = expander(db, actual_macro_call)?; 150
151 let lazy_id = match actual_macro_call {
152 MacroCallId::LazyMacro(id) => id,
153 MacroCallId::EagerMacro(_) => return None,
154 };
155
156 let macro_def = {
157 let loc = db.lookup_intern_macro(lazy_id);
158 db.macro_def(loc.def)?
159 };
160
161 let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt);
162
163 let fragment_kind = to_fragment_kind(db, actual_macro_call);
164
127 let (node, tmap_2) = 165 let (node, tmap_2) =
128 parse_macro_with_arg(db, macro_file, Some(std::sync::Arc::new((tt, tmap_1)))).value?; 166 mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?;
129 let token_id = macro_def.0.map_id_down(token_id); 167
168 let token_id = macro_def.map_id_down(token_id);
130 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; 169 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?;
131 let token = node.syntax_node().covering_element(range).into_token()?; 170 let token = node.syntax_node().covering_element(range).into_token()?;
132 Some((node.syntax_node(), token)) 171 Some((node.syntax_node(), token))
133} 172}
134 173
135fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { 174fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
136 let map = 175 let map = db.parse_or_expand(file_id).map(|it| AstIdMap::from_source(&it)).unwrap_or_default();
137 db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it));
138 Arc::new(map) 176 Arc::new(map)
139} 177}
140 178
141fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 179fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
180 match file_id.0 {
181 HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
182 HirFileIdRepr::MacroFile(macro_file) => {
183 db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node())
184 }
185 }
186}
187
188fn parse_macro_expansion(
189 db: &dyn AstDatabase,
190 macro_file: MacroFile,
191) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> {
192 let _p = profile::span("parse_macro_expansion");
193 let result = db.macro_expand(macro_file.macro_call_id);
194
195 if let Some(err) = &result.err {
196 // Note:
197 // The final goal we would like to make all parse_macro success,
198 // such that the following log will not call anyway.
199 match macro_file.macro_call_id {
200 MacroCallId::LazyMacro(id) => {
201 let loc: MacroCallLoc = db.lookup_intern_macro(id);
202 let node = loc.kind.node(db);
203
204 // collect parent information for warning log
205 let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
206 it.file_id.call_node(db)
207 })
208 .map(|n| format!("{:#}", n.value))
209 .collect::<Vec<_>>()
210 .join("\n");
211
212 log::warn!(
213 "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}",
214 err,
215 node.value,
216 parents
217 );
218 }
219 _ => {
220 log::warn!("fail on macro_parse: (reason: {:?})", err);
221 }
222 }
223 }
224 let tt = match result.value {
225 Some(tt) => tt,
226 None => return ExpandResult { value: None, err: result.err },
227 };
228
229 let fragment_kind = to_fragment_kind(db, macro_file.macro_call_id);
230
231 log::debug!("expanded = {}", tt.as_debug_string());
232 log::debug!("kind = {:?}", fragment_kind);
233
234 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) {
235 Ok(it) => it,
236 Err(err) => {
237 log::debug!(
238 "failed to parse expanstion to {:?} = {}",
239 fragment_kind,
240 tt.as_debug_string()
241 );
242 return ExpandResult::only_err(err);
243 }
244 };
245
246 match result.err {
247 Some(err) => {
248 // Safety check for recursive identity macro.
249 let node = parse.syntax_node();
250 let file: HirFileId = macro_file.into();
251 let call_node = match file.call_node(db) {
252 Some(it) => it,
253 None => {
254 return ExpandResult::only_err(err);
255 }
256 };
257 if is_self_replicating(&node, &call_node.value) {
258 return ExpandResult::only_err(err);
259 } else {
260 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
261 }
262 }
263 None => {
264 log::debug!("parse = {:?}", parse.syntax_node().kind());
265 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }
266 }
267 }
268}
269
270fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
271 let arg = db.macro_arg_text(id)?;
272 let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg));
273 Some(Arc::new((tt, tmap)))
274}
275
276fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
277 let id = match id {
278 MacroCallId::LazyMacro(id) => id,
279 MacroCallId::EagerMacro(_id) => {
280 // FIXME: support macro_arg for eager macro
281 return None;
282 }
283 };
284 let loc = db.lookup_intern_macro(id);
285 let arg = loc.kind.arg(db)?;
286 Some(arg.green())
287}
288
289fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<TokenExpander>> {
142 match id.kind { 290 match id.kind {
143 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) { 291 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) {
144 syntax::ast::Macro::MacroRules(macro_rules) => { 292 ast::Macro::MacroRules(macro_rules) => {
145 let arg = macro_rules.token_tree()?; 293 let arg = macro_rules.token_tree()?;
146 let (tt, tmap) = mbe::ast_to_token_tree(&arg); 294 let (tt, def_site_token_map) = mbe::ast_to_token_tree(&arg);
147 let rules = match MacroRules::parse(&tt) { 295 let mac = match mbe::MacroRules::parse(&tt) {
148 Ok(it) => it, 296 Ok(it) => it,
149 Err(err) => { 297 Err(err) => {
150 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); 298 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default();
@@ -152,12 +300,12 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
152 return None; 300 return None;
153 } 301 }
154 }; 302 };
155 Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) 303 Some(Arc::new(TokenExpander::MacroRules { mac, def_site_token_map }))
156 } 304 }
157 syntax::ast::Macro::MacroDef(macro_def) => { 305 ast::Macro::MacroDef(macro_def) => {
158 let arg = macro_def.body()?; 306 let arg = macro_def.body()?;
159 let (tt, tmap) = mbe::ast_to_token_tree(&arg); 307 let (tt, def_site_token_map) = mbe::ast_to_token_tree(&arg);
160 let rules = match MacroDef::parse(&tt) { 308 let mac = match mbe::MacroDef::parse(&tt) {
161 Ok(it) => it, 309 Ok(it) => it,
162 Err(err) => { 310 Err(err) => {
163 let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default(); 311 let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default();
@@ -165,41 +313,18 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
165 return None; 313 return None;
166 } 314 }
167 }; 315 };
168 Some(Arc::new((TokenExpander::MacroDef(rules), tmap))) 316 Some(Arc::new(TokenExpander::MacroDef { mac, def_site_token_map }))
169 } 317 }
170 }, 318 },
171 MacroDefKind::BuiltIn(expander, _) => { 319 MacroDefKind::BuiltIn(expander, _) => Some(Arc::new(TokenExpander::Builtin(expander))),
172 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
173 }
174 MacroDefKind::BuiltInDerive(expander, _) => { 320 MacroDefKind::BuiltInDerive(expander, _) => {
175 Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) 321 Some(Arc::new(TokenExpander::BuiltinDerive(expander)))
176 } 322 }
177 MacroDefKind::BuiltInEager(..) => None, 323 MacroDefKind::BuiltInEager(..) => None,
178 MacroDefKind::ProcMacro(expander, ..) => { 324 MacroDefKind::ProcMacro(expander, ..) => Some(Arc::new(TokenExpander::ProcMacro(expander))),
179 Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default())))
180 }
181 } 325 }
182} 326}
183 327
184fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
185 let id = match id {
186 MacroCallId::LazyMacro(id) => id,
187 MacroCallId::EagerMacro(_id) => {
188 // FIXME: support macro_arg for eager macro
189 return None;
190 }
191 };
192 let loc = db.lookup_intern_macro(id);
193 let arg = loc.kind.arg(db)?;
194 Some(arg.green())
195}
196
197fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
198 let arg = db.macro_arg_text(id)?;
199 let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg));
200 Some(Arc::new((tt, tmap)))
201}
202
203fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> { 328fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> {
204 macro_expand_with_arg(db, id, None) 329 macro_expand_with_arg(db, id, None)
205} 330}
@@ -208,19 +333,6 @@ fn macro_expand_error(db: &dyn AstDatabase, macro_call: MacroCallId) -> Option<E
208 db.macro_expand(macro_call).err 333 db.macro_expand(macro_call).err
209} 334}
210 335
211fn expander(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
212 let lazy_id = match id {
213 MacroCallId::LazyMacro(id) => id,
214 MacroCallId::EagerMacro(_id) => {
215 return None;
216 }
217 };
218
219 let loc = db.lookup_intern_macro(lazy_id);
220 let macro_rules = db.macro_def(loc.def)?;
221 Some(macro_rules)
222}
223
224fn macro_expand_with_arg( 336fn macro_expand_with_arg(
225 db: &dyn AstDatabase, 337 db: &dyn AstDatabase,
226 id: MacroCallId, 338 id: MacroCallId,
@@ -254,7 +366,7 @@ fn macro_expand_with_arg(
254 Some(it) => it, 366 Some(it) => it,
255 None => return ExpandResult::str_err("Fail to find macro definition".into()), 367 None => return ExpandResult::str_err("Fail to find macro definition".into()),
256 }; 368 };
257 let ExpandResult { value: tt, err } = macro_rules.0.expand(db, lazy_id, &macro_arg.0); 369 let ExpandResult { value: tt, err } = macro_rules.expand(db, lazy_id, &macro_arg.0);
258 // Set a hard limit for the expanded tt 370 // Set a hard limit for the expanded tt
259 let count = tt.count(); 371 let count = tt.count();
260 if count > TOKEN_LIMIT { 372 if count > TOKEN_LIMIT {
@@ -294,116 +406,11 @@ fn expand_proc_macro(
294 expander.expand(db, loc.krate, &macro_arg.0) 406 expander.expand(db, loc.krate, &macro_arg.0)
295} 407}
296 408
297fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
298 match file_id.0 {
299 HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
300 HirFileIdRepr::MacroFile(macro_file) => {
301 db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node())
302 }
303 }
304}
305
306fn parse_macro_expansion(
307 db: &dyn AstDatabase,
308 macro_file: MacroFile,
309) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> {
310 parse_macro_with_arg(db, macro_file, None)
311}
312
313fn parse_macro_with_arg(
314 db: &dyn AstDatabase,
315 macro_file: MacroFile,
316 arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
317) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> {
318 let macro_call_id = macro_file.macro_call_id;
319 let result = if let Some(arg) = arg {
320 macro_expand_with_arg(db, macro_call_id, Some(arg))
321 } else {
322 db.macro_expand(macro_call_id)
323 };
324
325 let _p = profile::span("parse_macro_expansion");
326
327 if let Some(err) = &result.err {
328 // Note:
329 // The final goal we would like to make all parse_macro success,
330 // such that the following log will not call anyway.
331 match macro_call_id {
332 MacroCallId::LazyMacro(id) => {
333 let loc: MacroCallLoc = db.lookup_intern_macro(id);
334 let node = loc.kind.node(db);
335
336 // collect parent information for warning log
337 let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
338 it.file_id.call_node(db)
339 })
340 .map(|n| format!("{:#}", n.value))
341 .collect::<Vec<_>>()
342 .join("\n");
343
344 log::warn!(
345 "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}",
346 err,
347 node.value,
348 parents
349 );
350 }
351 _ => {
352 log::warn!("fail on macro_parse: (reason: {:?})", err);
353 }
354 }
355 }
356 let tt = match result.value {
357 Some(tt) => tt,
358 None => return ExpandResult { value: None, err: result.err },
359 };
360
361 let fragment_kind = to_fragment_kind(db, macro_call_id);
362
363 log::debug!("expanded = {}", tt.as_debug_string());
364 log::debug!("kind = {:?}", fragment_kind);
365
366 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) {
367 Ok(it) => it,
368 Err(err) => {
369 log::debug!(
370 "failed to parse expanstion to {:?} = {}",
371 fragment_kind,
372 tt.as_debug_string()
373 );
374 return ExpandResult::only_err(err);
375 }
376 };
377
378 match result.err {
379 Some(err) => {
380 // Safety check for recursive identity macro.
381 let node = parse.syntax_node();
382 let file: HirFileId = macro_file.into();
383 let call_node = match file.call_node(db) {
384 Some(it) => it,
385 None => {
386 return ExpandResult::only_err(err);
387 }
388 };
389 if is_self_replicating(&node, &call_node.value) {
390 return ExpandResult::only_err(err);
391 } else {
392 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
393 }
394 }
395 None => {
396 log::debug!("parse = {:?}", parse.syntax_node().kind());
397 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }
398 }
399 }
400}
401
402fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { 409fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool {
403 if diff(from, to).is_empty() { 410 if diff(from, to).is_empty() {
404 return true; 411 return true;
405 } 412 }
406 if let Some(stmts) = MacroStmts::cast(from.clone()) { 413 if let Some(stmts) = ast::MacroStmts::cast(from.clone()) {
407 if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) { 414 if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) {
408 return true; 415 return true;
409 } 416 }
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 779725629..ed61ebca3 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -5,6 +5,7 @@
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use base_db::CrateId; 7use base_db::CrateId;
8use db::TokenExpander;
8use either::Either; 9use either::Either;
9use mbe::Origin; 10use mbe::Origin;
10use parser::SyntaxKind; 11use parser::SyntaxKind;
@@ -115,7 +116,7 @@ struct HygieneInfo {
115 /// The `macro_rules!` arguments. 116 /// The `macro_rules!` arguments.
116 def_start: Option<InFile<TextSize>>, 117 def_start: Option<InFile<TextSize>>,
117 118
118 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 119 macro_def: Arc<TokenExpander>,
119 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, 120 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
120 exp_map: Arc<mbe::TokenMap>, 121 exp_map: Arc<mbe::TokenMap>,
121} 122}
@@ -124,13 +125,16 @@ impl HygieneInfo {
124 fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> { 125 fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> {
125 let token_id = self.exp_map.token_by_range(token)?; 126 let token_id = self.exp_map.token_by_range(token)?;
126 127
127 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 128 let (token_id, origin) = self.macro_def.map_id_up(token_id);
128 let (token_map, tt) = match origin { 129 let (token_map, tt) = match origin {
129 mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), 130 mbe::Origin::Call => (&self.macro_arg.1, self.arg_start),
130 mbe::Origin::Def => ( 131 mbe::Origin::Def => match (&*self.macro_def, self.def_start) {
131 &self.macro_def.1, 132 (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt))
132 *self.def_start.as_ref().expect("`Origin::Def` used with non-`macro_rules!` macro"), 133 | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => {
133 ), 134 (def_site_token_map, tt)
135 }
136 _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
137 },
134 }; 138 };
135 139
136 let range = token_map.range_by_token(token_id)?.by_kind(SyntaxKind::IDENT)?; 140 let range = token_map.range_by_token(token_id)?.by_kind(SyntaxKind::IDENT)?;
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index a0e6aec62..0402640de 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -351,7 +351,7 @@ pub struct ExpansionInfo {
351 /// The `macro_rules!` arguments. 351 /// The `macro_rules!` arguments.
352 def: Option<InFile<ast::TokenTree>>, 352 def: Option<InFile<ast::TokenTree>>,
353 353
354 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 354 macro_def: Arc<db::TokenExpander>,
355 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, 355 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
356 exp_map: Arc<mbe::TokenMap>, 356 exp_map: Arc<mbe::TokenMap>,
357} 357}
@@ -368,7 +368,7 @@ impl ExpansionInfo {
368 assert_eq!(token.file_id, self.arg.file_id); 368 assert_eq!(token.file_id, self.arg.file_id);
369 let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?; 369 let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
370 let token_id = self.macro_arg.1.token_by_range(range)?; 370 let token_id = self.macro_arg.1.token_by_range(range)?;
371 let token_id = self.macro_def.0.map_id_down(token_id); 371 let token_id = self.macro_def.map_id_down(token_id);
372 372
373 let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?; 373 let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
374 374
@@ -383,17 +383,16 @@ impl ExpansionInfo {
383 ) -> Option<(InFile<SyntaxToken>, Origin)> { 383 ) -> Option<(InFile<SyntaxToken>, Origin)> {
384 let token_id = self.exp_map.token_by_range(token.value.text_range())?; 384 let token_id = self.exp_map.token_by_range(token.value.text_range())?;
385 385
386 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 386 let (token_id, origin) = self.macro_def.map_id_up(token_id);
387 let (token_map, tt) = match origin { 387 let (token_map, tt) = match origin {
388 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()), 388 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
389 mbe::Origin::Def => ( 389 mbe::Origin::Def => match (&*self.macro_def, self.def.as_ref()) {
390 &self.macro_def.1, 390 (db::TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt))
391 self.def 391 | (db::TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) => {
392 .as_ref() 392 (def_site_token_map, tt.as_ref().map(|tt| tt.syntax().clone()))
393 .expect("`Origin::Def` used with non-`macro_rules!` macro") 393 }
394 .as_ref() 394 _ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
395 .map(|tt| tt.syntax().clone()), 395 },
396 ),
397 }; 396 };
398 397
399 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; 398 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;