diff options
Diffstat (limited to 'crates/ra_ide_api/src/expand_macro.rs')
-rw-r--r-- | crates/ra_ide_api/src/expand_macro.rs | 60 |
1 files changed, 56 insertions, 4 deletions
diff --git a/crates/ra_ide_api/src/expand_macro.rs b/crates/ra_ide_api/src/expand_macro.rs index 7dbf33a16..0b540b8cd 100644 --- a/crates/ra_ide_api/src/expand_macro.rs +++ b/crates/ra_ide_api/src/expand_macro.rs | |||
@@ -40,16 +40,23 @@ fn expand_macro_recur( | |||
40 | let analyzer = hir::SourceAnalyzer::new(db, source, None); | 40 | let analyzer = hir::SourceAnalyzer::new(db, source, None); |
41 | let expansion = analyzer.expand(db, macro_call)?; | 41 | let expansion = analyzer.expand(db, macro_call)?; |
42 | let macro_file_id = expansion.file_id(); | 42 | let macro_file_id = expansion.file_id(); |
43 | let expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?; | 43 | let mut expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?; |
44 | 44 | ||
45 | let children = expanded.descendants().filter_map(ast::MacroCall::cast); | 45 | let children = expanded.descendants().filter_map(ast::MacroCall::cast); |
46 | let mut replaces = FxHashMap::default(); | 46 | let mut replaces = FxHashMap::default(); |
47 | 47 | ||
48 | for child in children.into_iter() { | 48 | for child in children.into_iter() { |
49 | let node = hir::Source::new(macro_file_id, &child); | 49 | let node = hir::Source::new(macro_file_id, &child); |
50 | let new_node = expand_macro_recur(db, source, node)?; | 50 | if let Some(new_node) = expand_macro_recur(db, source, node) { |
51 | 51 | // Replace the whole node if it is root | |
52 | replaces.insert(child.syntax().clone().into(), new_node.into()); | 52 | // `replace_descendants` will not replace the parent node |
53 | // but `SyntaxNode::descendants include itself | ||
54 | if expanded == *child.syntax() { | ||
55 | expanded = new_node; | ||
56 | } else { | ||
57 | replaces.insert(child.syntax().clone().into(), new_node.into()); | ||
58 | } | ||
59 | } | ||
53 | } | 60 | } |
54 | 61 | ||
55 | Some(replace_descendants(&expanded, &replaces)) | 62 | Some(replace_descendants(&expanded, &replaces)) |
@@ -217,4 +224,49 @@ fn some_thing() -> u32 { | |||
217 | } | 224 | } |
218 | "###); | 225 | "###); |
219 | } | 226 | } |
227 | |||
228 | #[test] | ||
229 | fn macro_expand_match_ast_inside_let_statement() { | ||
230 | let res = check_expand_macro( | ||
231 | r#" | ||
232 | //- /lib.rs | ||
233 | macro_rules! match_ast { | ||
234 | (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; | ||
235 | (match ($node:expr) {}) => {{}}; | ||
236 | } | ||
237 | |||
238 | fn main() { | ||
239 | let p = f(|it| { | ||
240 | let res = mat<|>ch_ast! { match c {}}; | ||
241 | Some(res) | ||
242 | })?; | ||
243 | } | ||
244 | "#, | ||
245 | ); | ||
246 | |||
247 | assert_eq!(res.name, "match_ast"); | ||
248 | assert_snapshot!(res.expansion, @r###"{}"###); | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn macro_expand_inner_macro_fail_to_expand() { | ||
253 | let res = check_expand_macro( | ||
254 | r#" | ||
255 | //- /lib.rs | ||
256 | macro_rules! bar { | ||
257 | (BAD) => {}; | ||
258 | } | ||
259 | macro_rules! foo { | ||
260 | () => {bar!()}; | ||
261 | } | ||
262 | |||
263 | fn main() { | ||
264 | let res = fo<|>o!(); | ||
265 | } | ||
266 | "#, | ||
267 | ); | ||
268 | |||
269 | assert_eq!(res.name, "foo"); | ||
270 | assert_snapshot!(res.expansion, @r###"bar!()"###); | ||
271 | } | ||
220 | } | 272 | } |