aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2020-03-14 06:25:30 +0000
committerEdwin Cheng <[email protected]>2020-03-14 06:25:51 +0000
commitfe78a14bbb9769c8ccd5cc41415702f5176a8e88 (patch)
tree2ec165fbab4bba4d379d5b1936168456dab4585f
parent4c85e53531fc9e2e2c2f1368c01e08e10e190cd5 (diff)
Support local macro_rules
-rw-r--r--crates/ra_hir_def/src/body.rs12
-rw-r--r--crates/ra_hir_def/src/body/lower.rs48
-rw-r--r--crates/ra_hir_def/src/data.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs15
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs20
-rw-r--r--crates/ra_ide/src/goto_definition.rs15
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, &macro_call); 53 let macro_call = InFile::new(self.current_file_id, &macro_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
4use either::Either; 4use either::Either;
5 5
6use hir_expand::name::{name, AsName, Name}; 6use hir_expand::{
7 name::{name, AsName, Name},
8 MacroDefId, MacroDefKind,
9};
7use ra_arena::Arena; 10use ra_arena::Arena;
8use ra_syntax::{ 11use 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
703fn 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
689impl From<ast::BinOp> for BinaryOp { 713impl 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]
366fn infer_local_macro() {
367 assert_snapshot!(
368 infer(r#"
369fn 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]
366fn infer_builtin_macros_line() { 386fn 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(