diff options
author | Edwin Cheng <[email protected]> | 2020-03-14 06:25:30 +0000 |
---|---|---|
committer | Edwin Cheng <[email protected]> | 2020-03-14 06:25:51 +0000 |
commit | fe78a14bbb9769c8ccd5cc41415702f5176a8e88 (patch) | |
tree | 2ec165fbab4bba4d379d5b1936168456dab4585f | |
parent | 4c85e53531fc9e2e2c2f1368c01e08e10e190cd5 (diff) |
Support local macro_rules
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/resolver.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/macros.rs | 20 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 15 |
6 files changed, 96 insertions, 16 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 57ba45b45..2bc405a59 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -47,13 +47,19 @@ impl Expander { | |||
47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( | 47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( |
48 | &mut self, | 48 | &mut self, |
49 | db: &DB, | 49 | db: &DB, |
50 | local_scope: Option<&ItemScope>, | ||
50 | macro_call: ast::MacroCall, | 51 | macro_call: ast::MacroCall, |
51 | ) -> Option<(Mark, T)> { | 52 | ) -> Option<(Mark, T)> { |
52 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 53 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
53 | 54 | ||
54 | if let Some(call_id) = | 55 | if let Some(call_id) = macro_call.as_call_id(db, |path| { |
55 | macro_call.as_call_id(db, |path| self.resolve_path_as_macro(db, &path)) | 56 | if let Some(local_scope) = local_scope { |
56 | { | 57 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { |
58 | return Some(def); | ||
59 | } | ||
60 | } | ||
61 | self.resolve_path_as_macro(db, &path) | ||
62 | }) { | ||
57 | let file_id = call_id.as_file(); | 63 | let file_id = call_id.as_file(); |
58 | if let Some(node) = db.parse_or_expand(file_id) { | 64 | if let Some(node) = db.parse_or_expand(file_id) { |
59 | if let Some(expr) = T::cast(node) { | 65 | if let Some(expr) = T::cast(node) { |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index ec1b0c2e7..54b5591d3 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -3,7 +3,10 @@ | |||
3 | 3 | ||
4 | use either::Either; | 4 | use either::Either; |
5 | 5 | ||
6 | use hir_expand::name::{name, AsName, Name}; | 6 | use hir_expand::{ |
7 | name::{name, AsName, Name}, | ||
8 | MacroDefId, MacroDefKind, | ||
9 | }; | ||
7 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
8 | use ra_syntax::{ | 11 | use ra_syntax::{ |
9 | ast::{ | 12 | ast::{ |
@@ -452,19 +455,30 @@ where | |||
452 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | 455 | None => self.alloc_expr(Expr::Missing, syntax_ptr), |
453 | } | 456 | } |
454 | } | 457 | } |
455 | // FIXME expand to statements in statement position | ||
456 | ast::Expr::MacroCall(e) => { | 458 | ast::Expr::MacroCall(e) => { |
457 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | 459 | if let Some(name) = is_macro_rules(&e) { |
458 | match self.expander.enter_expand(self.db, e) { | 460 | let mac = MacroDefId { |
459 | Some((mark, expansion)) => { | 461 | krate: Some(self.expander.module.krate), |
460 | self.source_map | 462 | ast_id: Some(self.expander.ast_id(&e)), |
461 | .expansions | 463 | kind: MacroDefKind::Declarative, |
462 | .insert(macro_call, self.expander.current_file_id); | 464 | }; |
463 | let id = self.collect_expr(expansion); | 465 | self.body.item_scope.define_legacy_macro(name, mac); |
464 | self.expander.exit(self.db, mark); | 466 | |
465 | id | 467 | // FIXME: do we still need to allocate this as missing ? |
468 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
469 | } else { | ||
470 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | ||
471 | match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { | ||
472 | Some((mark, expansion)) => { | ||
473 | self.source_map | ||
474 | .expansions | ||
475 | .insert(macro_call, self.expander.current_file_id); | ||
476 | let id = self.collect_expr(expansion); | ||
477 | self.expander.exit(self.db, mark); | ||
478 | id | ||
479 | } | ||
480 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
466 | } | 481 | } |
467 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
468 | } | 482 | } |
469 | } | 483 | } |
470 | 484 | ||
@@ -686,6 +700,16 @@ where | |||
686 | } | 700 | } |
687 | } | 701 | } |
688 | 702 | ||
703 | fn is_macro_rules(m: &ast::MacroCall) -> Option<Name> { | ||
704 | let name = m.path()?.segment()?.name_ref()?.as_name(); | ||
705 | |||
706 | if name == name![macro_rules] { | ||
707 | Some(m.name()?.as_name()) | ||
708 | } else { | ||
709 | None | ||
710 | } | ||
711 | } | ||
712 | |||
689 | impl From<ast::BinOp> for BinaryOp { | 713 | impl From<ast::BinOp> for BinaryOp { |
690 | fn from(ast_op: ast::BinOp) -> Self { | 714 | fn from(ast_op: ast::BinOp) -> Self { |
691 | match ast_op { | 715 | match ast_op { |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index a72eb5369..eb4c5de45 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -280,7 +280,7 @@ fn collect_impl_items_in_macro( | |||
280 | return Vec::new(); | 280 | return Vec::new(); |
281 | } | 281 | } |
282 | 282 | ||
283 | if let Some((mark, items)) = expander.enter_expand(db, m) { | 283 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { |
284 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 284 | let items: InFile<ast::MacroItems> = expander.to_source(items); |
285 | let mut res = collect_impl_items( | 285 | let mut res = collect_impl_items( |
286 | db, | 286 | db, |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 2734d51a0..123fae72a 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -381,6 +381,11 @@ impl Resolver { | |||
381 | db: &impl DefDatabase, | 381 | db: &impl DefDatabase, |
382 | path: &ModPath, | 382 | path: &ModPath, |
383 | ) -> Option<MacroDefId> { | 383 | ) -> Option<MacroDefId> { |
384 | // Search item scope legacy macro first | ||
385 | if let Some(def) = self.resolve_local_macro_def(path) { | ||
386 | return Some(def); | ||
387 | } | ||
388 | |||
384 | let (item_map, module) = self.module_scope()?; | 389 | let (item_map, module) = self.module_scope()?; |
385 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() | 390 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() |
386 | } | 391 | } |
@@ -413,6 +418,16 @@ impl Resolver { | |||
413 | }) | 418 | }) |
414 | } | 419 | } |
415 | 420 | ||
421 | fn resolve_local_macro_def(&self, path: &ModPath) -> Option<MacroDefId> { | ||
422 | let name = path.as_ident()?; | ||
423 | self.scopes.iter().rev().find_map(|scope| { | ||
424 | if let Scope::LocalItemsScope(body) = scope { | ||
425 | return body.item_scope.get_legacy_macro(name); | ||
426 | } | ||
427 | None | ||
428 | }) | ||
429 | } | ||
430 | |||
416 | pub fn module(&self) -> Option<ModuleId> { | 431 | pub fn module(&self) -> Option<ModuleId> { |
417 | let (def_map, local_id) = self.module_scope()?; | 432 | let (def_map, local_id) = self.module_scope()?; |
418 | Some(ModuleId { krate: def_map.krate, local_id }) | 433 | Some(ModuleId { krate: def_map.krate, local_id }) |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 32457bbf7..3b7022ad5 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -363,6 +363,26 @@ fn main() { | |||
363 | } | 363 | } |
364 | 364 | ||
365 | #[test] | 365 | #[test] |
366 | fn infer_local_macro() { | ||
367 | assert_snapshot!( | ||
368 | infer(r#" | ||
369 | fn main() { | ||
370 | macro_rules! foo { | ||
371 | () => { 1usize } | ||
372 | } | ||
373 | let _a = foo!(); | ||
374 | } | ||
375 | "#), | ||
376 | @r###" | ||
377 | ![0; 6) '1usize': usize | ||
378 | [11; 90) '{ ...!(); }': () | ||
379 | [17; 66) 'macro_... }': {unknown} | ||
380 | [75; 77) '_a': usize | ||
381 | "### | ||
382 | ); | ||
383 | } | ||
384 | |||
385 | #[test] | ||
366 | fn infer_builtin_macros_line() { | 386 | fn infer_builtin_macros_line() { |
367 | assert_snapshot!( | 387 | assert_snapshot!( |
368 | infer(r#" | 388 | infer(r#" |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index a55a13ffc..a7be92ce3 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -788,6 +788,21 @@ mod tests { | |||
788 | } | 788 | } |
789 | 789 | ||
790 | #[test] | 790 | #[test] |
791 | fn goto_def_in_local_macro() { | ||
792 | check_goto( | ||
793 | " | ||
794 | //- /lib.rs | ||
795 | fn bar() { | ||
796 | macro_rules! foo { () => { () } } | ||
797 | <|>foo!(); | ||
798 | } | ||
799 | ", | ||
800 | "foo MACRO_CALL FileId(1) [15; 48) [28; 31)", | ||
801 | "macro_rules! foo { () => { () } }|foo", | ||
802 | ); | ||
803 | } | ||
804 | |||
805 | #[test] | ||
791 | fn goto_def_for_field_init_shorthand() { | 806 | fn goto_def_for_field_init_shorthand() { |
792 | covers!(ra_ide_db::goto_def_for_field_init_shorthand); | 807 | covers!(ra_ide_db::goto_def_for_field_init_shorthand); |
793 | check_goto( | 808 | check_goto( |