aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-03-28 16:43:11 +0100
committerGitHub <[email protected]>2021-03-28 16:43:11 +0100
commitbb1d925dab36372c6bd1fb5671bb68ce938ff009 (patch)
treead32fbab8caf6563961b1366c726d8323fb303f5 /crates
parentce6bb5ccca48b177f6cd12b42b4c52f3e1b44e0c (diff)
parent772987911851d6480ec8c905c0cac1e2f881152c (diff)
Merge #8212
8212: Basic support macro 2.0 r=jonas-schievink a=edwin0cheng Turn out it is quite straight forward :) r @jonas-schievink ![m2](https://user-images.githubusercontent.com/11014119/112712565-6eb99380-8f0b-11eb-88de-5d7f974dfe6d.png) Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir/src/semantics/source_to_def.rs5
-rw-r--r--crates/hir_def/src/nameres/collector.rs102
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs18
-rw-r--r--crates/hir_expand/src/db.rs60
-rw-r--r--crates/hir_expand/src/hygiene.rs2
-rw-r--r--crates/hir_expand/src/lib.rs2
-rw-r--r--crates/hir_ty/src/tests/macros.rs83
-rw-r--r--crates/ide/src/doc_links.rs2
-rw-r--r--crates/ide/src/file_structure.rs2
-rw-r--r--crates/ide/src/hover.rs31
-rw-r--r--crates/ide/src/move_item.rs1
-rw-r--r--crates/ide/src/syntax_highlighting.rs28
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/macro_.rs (renamed from crates/ide/src/syntax_highlighting/macro_rules.rs)10
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html12
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs10
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/symbol_index.rs3
-rw-r--r--crates/syntax/src/ast/node_ext.rs1
-rw-r--r--crates/syntax/src/parsing/text_tree_sink.rs4
21 files changed, 287 insertions, 96 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 3ff135f41..d3caeef4e 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -768,7 +768,7 @@ to_def_impls![
768 (crate::TypeParam, ast::TypeParam, type_param_to_def), 768 (crate::TypeParam, ast::TypeParam, type_param_to_def),
769 (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), 769 (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
770 (crate::ConstParam, ast::ConstParam, const_param_to_def), 770 (crate::ConstParam, ast::ConstParam, const_param_to_def),
771 (crate::MacroDef, ast::MacroRules, macro_rules_to_def), 771 (crate::MacroDef, ast::Macro, macro_to_def),
772 (crate::Local, ast::IdentPat, bind_pat_to_def), 772 (crate::Local, ast::IdentPat, bind_pat_to_def),
773 (crate::Local, ast::SelfParam, self_param_to_def), 773 (crate::Local, ast::SelfParam, self_param_to_def),
774 (crate::Label, ast::Label, label_to_def), 774 (crate::Label, ast::Label, label_to_def),
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 762809fcd..9a5a2255f 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -191,10 +191,7 @@ impl SourceToDefCtx<'_, '_> {
191 } 191 }
192 192
193 // FIXME: use DynMap as well? 193 // FIXME: use DynMap as well?
194 pub(super) fn macro_rules_to_def( 194 pub(super) fn macro_to_def(&mut self, src: InFile<ast::Macro>) -> Option<MacroDefId> {
195 &mut self,
196 src: InFile<ast::MacroRules>,
197 ) -> Option<MacroDefId> {
198 let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); 195 let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
199 let ast_id = AstId::new(src.file_id, file_ast_id.upcast()); 196 let ast_id = AstId::new(src.file_id, file_ast_id.upcast());
200 let kind = MacroDefKind::Declarative(ast_id); 197 let kind = MacroDefKind::Declarative(ast_id);
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d8fabe49b..d58135ec9 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -25,8 +25,8 @@ use crate::{
25 derive_macro_as_call_id, 25 derive_macro_as_call_id,
26 item_scope::{ImportType, PerNsGlobImports}, 26 item_scope::{ImportType, PerNsGlobImports},
27 item_tree::{ 27 item_tree::{
28 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, 28 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem,
29 StructDefKind, 29 ModKind, StructDefKind,
30 }, 30 },
31 macro_call_as_call_id, 31 macro_call_as_call_id,
32 nameres::{ 32 nameres::{
@@ -395,7 +395,7 @@ impl DefCollector<'_> {
395 /// macro_rules! foo { () => {} } 395 /// macro_rules! foo { () => {} }
396 /// use foo as bar; 396 /// use foo as bar;
397 /// ``` 397 /// ```
398 fn define_macro( 398 fn define_macro_rules(
399 &mut self, 399 &mut self,
400 module_id: LocalModuleId, 400 module_id: LocalModuleId,
401 name: Name, 401 name: Name,
@@ -430,6 +430,21 @@ impl DefCollector<'_> {
430 self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); 430 self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
431 } 431 }
432 432
433 /// Define a macro 2.0 macro
434 ///
435 /// The scoped of macro 2.0 macro is equal to normal function
436 fn define_macro_def(
437 &mut self,
438 module_id: LocalModuleId,
439 name: Name,
440 macro_: MacroDefId,
441 vis: &RawVisibility,
442 ) {
443 let vis =
444 self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public);
445 self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named);
446 }
447
433 /// Define a proc macro 448 /// Define a proc macro
434 /// 449 ///
435 /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. 450 /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
@@ -1067,40 +1082,7 @@ impl ModCollector<'_, '_> {
1067 } 1082 }
1068 ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), 1083 ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
1069 ModItem::MacroRules(id) => self.collect_macro_rules(id), 1084 ModItem::MacroRules(id) => self.collect_macro_rules(id),
1070 ModItem::MacroDef(id) => { 1085 ModItem::MacroDef(id) => self.collect_macro_def(id),
1071 let mac = &self.item_tree[id];
1072 let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
1073
1074 // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it
1075 // to define builtin macros, so we support at least that part.
1076 let attrs = self.item_tree.attrs(
1077 self.def_collector.db,
1078 krate,
1079 ModItem::from(id).into(),
1080 );
1081 if attrs.by_key("rustc_builtin_macro").exists() {
1082 let krate = self.def_collector.def_map.krate;
1083 let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
1084 .or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
1085 if let Some(macro_id) = macro_id {
1086 let vis = self
1087 .def_collector
1088 .def_map
1089 .resolve_visibility(
1090 self.def_collector.db,
1091 self.module_id,
1092 &self.item_tree[mac.visibility],
1093 )
1094 .unwrap_or(Visibility::Public);
1095 self.def_collector.update(
1096 self.module_id,
1097 &[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))],
1098 vis,
1099 ImportType::Named,
1100 );
1101 }
1102 }
1103 }
1104 ModItem::Impl(imp) => { 1086 ModItem::Impl(imp) => {
1105 let module = self.def_collector.def_map.module_id(self.module_id); 1087 let module = self.def_collector.def_map.module_id(self.module_id);
1106 let impl_id = 1088 let impl_id =
@@ -1420,7 +1402,7 @@ impl ModCollector<'_, '_> {
1420 if attrs.by_key("rustc_builtin_macro").exists() { 1402 if attrs.by_key("rustc_builtin_macro").exists() {
1421 let krate = self.def_collector.def_map.krate; 1403 let krate = self.def_collector.def_map.krate;
1422 if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { 1404 if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) {
1423 self.def_collector.define_macro( 1405 self.def_collector.define_macro_rules(
1424 self.module_id, 1406 self.module_id,
1425 mac.name.clone(), 1407 mac.name.clone(),
1426 macro_id, 1408 macro_id,
@@ -1436,7 +1418,49 @@ impl ModCollector<'_, '_> {
1436 kind: MacroDefKind::Declarative(ast_id), 1418 kind: MacroDefKind::Declarative(ast_id),
1437 local_inner: is_local_inner, 1419 local_inner: is_local_inner,
1438 }; 1420 };
1439 self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); 1421 self.def_collector.define_macro_rules(
1422 self.module_id,
1423 mac.name.clone(),
1424 macro_id,
1425 is_export,
1426 );
1427 }
1428
1429 fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) {
1430 let krate = self.def_collector.def_map.krate;
1431 let mac = &self.item_tree[id];
1432 let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
1433
1434 // Case 1: bulitin macros
1435 let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
1436 if attrs.by_key("rustc_builtin_macro").exists() {
1437 let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
1438 .or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
1439
1440 if let Some(macro_id) = macro_id {
1441 self.def_collector.define_macro_def(
1442 self.module_id,
1443 mac.name.clone(),
1444 macro_id,
1445 &self.item_tree[mac.visibility],
1446 );
1447 }
1448 return;
1449 }
1450
1451 // Case 2: normal `macro`
1452 let macro_id = MacroDefId {
1453 krate: self.def_collector.def_map.krate,
1454 kind: MacroDefKind::Declarative(ast_id),
1455 local_inner: false,
1456 };
1457
1458 self.def_collector.define_macro_def(
1459 self.module_id,
1460 mac.name.clone(),
1461 macro_id,
1462 &self.item_tree[mac.visibility],
1463 );
1440 } 1464 }
1441 1465
1442 fn collect_macro_call(&mut self, mac: &MacroCall) { 1466 fn collect_macro_call(&mut self, mac: &MacroCall) {
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index 6d3cb8d7a..c37f915ab 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -837,3 +837,21 @@ fn collects_derive_helpers() {
837 _ => unreachable!(), 837 _ => unreachable!(),
838 } 838 }
839} 839}
840
841#[test]
842fn resolve_macro_def() {
843 check(
844 r#"
845//- /lib.rs
846pub macro structs($($i:ident),*) {
847 $(struct $i { field: u32 } )*
848}
849structs!(Foo);
850"#,
851 expect![[r#"
852 crate
853 Foo: t
854 structs: m
855 "#]],
856 );
857}
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index d672f6723..c0ab70b60 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use base_db::{salsa, SourceDatabase}; 5use base_db::{salsa, SourceDatabase};
6use mbe::{ExpandError, ExpandResult, MacroRules}; 6use mbe::{ExpandError, ExpandResult, MacroDef, MacroRules};
7use parser::FragmentKind; 7use parser::FragmentKind;
8use syntax::{ 8use syntax::{
9 algo::diff, 9 algo::diff,
@@ -28,6 +28,7 @@ const TOKEN_LIMIT: usize = 524288;
28#[derive(Debug, Clone, Eq, PartialEq)] 28#[derive(Debug, Clone, Eq, PartialEq)]
29pub enum TokenExpander { 29pub enum TokenExpander {
30 MacroRules(mbe::MacroRules), 30 MacroRules(mbe::MacroRules),
31 MacroDef(mbe::MacroDef),
31 Builtin(BuiltinFnLikeExpander), 32 Builtin(BuiltinFnLikeExpander),
32 BuiltinDerive(BuiltinDeriveExpander), 33 BuiltinDerive(BuiltinDeriveExpander),
33 ProcMacro(ProcMacroExpander), 34 ProcMacro(ProcMacroExpander),
@@ -42,6 +43,7 @@ impl TokenExpander {
42 ) -> mbe::ExpandResult<tt::Subtree> { 43 ) -> mbe::ExpandResult<tt::Subtree> {
43 match self { 44 match self {
44 TokenExpander::MacroRules(it) => it.expand(tt), 45 TokenExpander::MacroRules(it) => it.expand(tt),
46 TokenExpander::MacroDef(it) => it.expand(tt),
45 TokenExpander::Builtin(it) => it.expand(db, id, tt), 47 TokenExpander::Builtin(it) => it.expand(db, id, tt),
46 // FIXME switch these to ExpandResult as well 48 // FIXME switch these to ExpandResult as well
47 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), 49 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(),
@@ -57,6 +59,7 @@ impl TokenExpander {
57 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { 59 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
58 match self { 60 match self {
59 TokenExpander::MacroRules(it) => it.map_id_down(id), 61 TokenExpander::MacroRules(it) => it.map_id_down(id),
62 TokenExpander::MacroDef(it) => it.map_id_down(id),
60 TokenExpander::Builtin(..) => id, 63 TokenExpander::Builtin(..) => id,
61 TokenExpander::BuiltinDerive(..) => id, 64 TokenExpander::BuiltinDerive(..) => id,
62 TokenExpander::ProcMacro(..) => id, 65 TokenExpander::ProcMacro(..) => id,
@@ -66,6 +69,7 @@ impl TokenExpander {
66 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { 69 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
67 match self { 70 match self {
68 TokenExpander::MacroRules(it) => it.map_id_up(id), 71 TokenExpander::MacroRules(it) => it.map_id_up(id),
72 TokenExpander::MacroDef(it) => it.map_id_up(id),
69 TokenExpander::Builtin(..) => (id, mbe::Origin::Call), 73 TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
70 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), 74 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
71 TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), 75 TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call),
@@ -136,26 +140,40 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
136 140
137fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 141fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
138 match id.kind { 142 match id.kind {
139 MacroDefKind::Declarative(ast_id) => { 143 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) {
140 let macro_rules = match ast_id.to_node(db) { 144 syntax::ast::Macro::MacroRules(macro_rules) => {
141 syntax::ast::Macro::MacroRules(mac) => mac, 145 let arg = macro_rules.token_tree()?;
142 syntax::ast::Macro::MacroDef(_) => return None, 146 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
143 }; 147 log::warn!("fail on macro_rules to token tree: {:#?}", arg);
144 let arg = macro_rules.token_tree()?; 148 None
145 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { 149 })?;
146 log::warn!("fail on macro_def to token tree: {:#?}", arg); 150 let rules = match MacroRules::parse(&tt) {
147 None 151 Ok(it) => it,
148 })?; 152 Err(err) => {
149 let rules = match MacroRules::parse(&tt) { 153 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default();
150 Ok(it) => it, 154 log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt);
151 Err(err) => { 155 return None;
152 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); 156 }
153 log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); 157 };
154 return None; 158 Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
155 } 159 }
156 }; 160 syntax::ast::Macro::MacroDef(macro_def) => {
157 Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) 161 let arg = macro_def.body()?;
158 } 162 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
163 log::warn!("fail on macro_def to token tree: {:#?}", arg);
164 None
165 })?;
166 let rules = match MacroDef::parse(&tt) {
167 Ok(it) => it,
168 Err(err) => {
169 let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default();
170 log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt);
171 return None;
172 }
173 };
174 Some(Arc::new((TokenExpander::MacroDef(rules), tmap)))
175 }
176 },
159 MacroDefKind::BuiltIn(expander, _) => { 177 MacroDefKind::BuiltIn(expander, _) => {
160 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) 178 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
161 } 179 }
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 0e0f7214a..779725629 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -148,7 +148,7 @@ fn make_hygiene_info(
148 let def_offset = loc.def.ast_id().left().and_then(|id| { 148 let def_offset = loc.def.ast_id().left().and_then(|id| {
149 let def_tt = match id.to_node(db) { 149 let def_tt = match id.to_node(db) {
150 ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), 150 ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(),
151 ast::Macro::MacroDef(_) => return None, 151 ast::Macro::MacroDef(mac) => mac.body()?.syntax().text_range().start(),
152 }; 152 };
153 Some(InFile::new(id.file_id, def_tt)) 153 Some(InFile::new(id.file_id, def_tt))
154 }); 154 });
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index b8045fda9..3e332ee47 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -151,7 +151,7 @@ impl HirFileId {
151 let def = loc.def.ast_id().left().and_then(|id| { 151 let def = loc.def.ast_id().left().and_then(|id| {
152 let def_tt = match id.to_node(db) { 152 let def_tt = match id.to_node(db) {
153 ast::Macro::MacroRules(mac) => mac.token_tree()?, 153 ast::Macro::MacroRules(mac) => mac.token_tree()?,
154 ast::Macro::MacroDef(_) => return None, 154 ast::Macro::MacroDef(mac) => mac.body()?,
155 }; 155 };
156 Some(InFile::new(id.file_id, def_tt)) 156 Some(InFile::new(id.file_id, def_tt))
157 }); 157 });
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 01935ec99..3eb01dbd0 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -135,7 +135,88 @@ fn infer_path_qualified_macros_expanded() {
135} 135}
136 136
137#[test] 137#[test]
138fn expr_macro_expanded_in_various_places() { 138fn expr_macro_def_expanded_in_various_places() {
139 check_infer(
140 r#"
141 macro spam() {
142 1isize
143 }
144
145 fn spam() {
146 spam!();
147 (spam!());
148 spam!().spam(spam!());
149 for _ in spam!() {}
150 || spam!();
151 while spam!() {}
152 break spam!();
153 return spam!();
154 match spam!() {
155 _ if spam!() => spam!(),
156 }
157 spam!()(spam!());
158 Spam { spam: spam!() };
159 spam!()[spam!()];
160 await spam!();
161 spam!() as usize;
162 &spam!();
163 -spam!();
164 spam!()..spam!();
165 spam!() + spam!();
166 }
167 "#,
168 expect![[r#"
169 !0..6 '1isize': isize
170 !0..6 '1isize': isize
171 !0..6 '1isize': isize
172 !0..6 '1isize': isize
173 !0..6 '1isize': isize
174 !0..6 '1isize': isize
175 !0..6 '1isize': isize
176 !0..6 '1isize': isize
177 !0..6 '1isize': isize
178 !0..6 '1isize': isize
179 !0..6 '1isize': isize
180 !0..6 '1isize': isize
181 !0..6 '1isize': isize
182 !0..6 '1isize': isize
183 !0..6 '1isize': isize
184 !0..6 '1isize': isize
185 !0..6 '1isize': isize
186 !0..6 '1isize': isize
187 !0..6 '1isize': isize
188 !0..6 '1isize': isize
189 !0..6 '1isize': isize
190 !0..6 '1isize': isize
191 !0..6 '1isize': isize
192 !0..6 '1isize': isize
193 !0..6 '1isize': isize
194 39..442 '{ ...!(); }': ()
195 73..94 'spam!(...am!())': {unknown}
196 100..119 'for _ ...!() {}': ()
197 104..105 '_': {unknown}
198 117..119 '{}': ()
199 124..134 '|| spam!()': || -> isize
200 140..156 'while ...!() {}': ()
201 154..156 '{}': ()
202 161..174 'break spam!()': !
203 180..194 'return spam!()': !
204 200..254 'match ... }': isize
205 224..225 '_': isize
206 259..275 'spam!(...am!())': {unknown}
207 281..303 'Spam {...m!() }': {unknown}
208 309..325 'spam!(...am!()]': {unknown}
209 350..366 'spam!(... usize': usize
210 372..380 '&spam!()': &isize
211 386..394 '-spam!()': isize
212 400..416 'spam!(...pam!()': {unknown}
213 422..439 'spam!(...pam!()': isize
214 "#]],
215 );
216}
217
218#[test]
219fn expr_macro_rules_expanded_in_various_places() {
139 check_infer( 220 check_infer(
140 r#" 221 r#"
141 macro_rules! spam { 222 macro_rules! spam {
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 0cee741ac..9301cdeff 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -161,7 +161,7 @@ pub(crate) fn doc_owner_to_def(
161 ast::Variant(it) => sema.to_def(&it)?.into(), 161 ast::Variant(it) => sema.to_def(&it)?.into(),
162 ast::Trait(it) => sema.to_def(&it)?.into(), 162 ast::Trait(it) => sema.to_def(&it)?.into(),
163 ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType), 163 ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType),
164 ast::MacroRules(it) => return sema.to_def(&it).map(Definition::Macro), 164 ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro),
165 ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field), 165 ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field),
166 ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field), 166 ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field),
167 _ => return None, 167 _ => return None,
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 9f879a66e..2c898eae8 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -172,7 +172,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
172 }; 172 };
173 Some(node) 173 Some(node)
174 }, 174 },
175 ast::MacroRules(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), 175 ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
176 _ => None, 176 _ => None,
177 } 177 }
178 } 178 }
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c43089476..3c951c507 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1235,6 +1235,37 @@ fn f() { fo$0o!(); }
1235 } 1235 }
1236 1236
1237 #[test] 1237 #[test]
1238 fn test_hover_macro2_invocation() {
1239 check(
1240 r#"
1241/// foo bar
1242///
1243/// foo bar baz
1244macro foo() {}
1245
1246fn f() { fo$0o!(); }
1247"#,
1248 expect![[r#"
1249 *foo*
1250
1251 ```rust
1252 test
1253 ```
1254
1255 ```rust
1256 macro foo
1257 ```
1258
1259 ---
1260
1261 foo bar
1262
1263 foo bar baz
1264 "#]],
1265 )
1266 }
1267
1268 #[test]
1238 fn test_hover_tuple_field() { 1269 fn test_hover_tuple_field() {
1239 check( 1270 check(
1240 r#"struct TS(String, i32$0);"#, 1271 r#"struct TS(String, i32$0);"#,
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs
index 48690b073..05fa8fc13 100644
--- a/crates/ide/src/move_item.rs
+++ b/crates/ide/src/move_item.rs
@@ -66,6 +66,7 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -
66 SyntaxKind::STATIC, 66 SyntaxKind::STATIC,
67 SyntaxKind::CONST, 67 SyntaxKind::CONST,
68 SyntaxKind::MACRO_RULES, 68 SyntaxKind::MACRO_RULES,
69 SyntaxKind::MACRO_DEF,
69 ]; 70 ];
70 71
71 let ancestor = once(root.clone()) 72 let ancestor = once(root.clone())
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index e25b698e0..67a10766b 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -5,7 +5,7 @@ mod injector;
5 5
6mod highlight; 6mod highlight;
7mod format; 7mod format;
8mod macro_rules; 8mod macro_;
9mod inject; 9mod inject;
10 10
11mod html; 11mod html;
@@ -24,8 +24,8 @@ use syntax::{
24 24
25use crate::{ 25use crate::{
26 syntax_highlighting::{ 26 syntax_highlighting::{
27 format::highlight_format_string, highlights::Highlights, 27 format::highlight_format_string, highlights::Highlights, macro_::MacroHighlighter,
28 macro_rules::MacroRulesHighlighter, tags::Highlight, 28 tags::Highlight,
29 }, 29 },
30 FileId, HlMod, HlTag, 30 FileId, HlMod, HlTag,
31}; 31};
@@ -93,8 +93,8 @@ fn traverse(
93 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); 93 let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
94 94
95 let mut current_macro_call: Option<ast::MacroCall> = None; 95 let mut current_macro_call: Option<ast::MacroCall> = None;
96 let mut current_macro_rules: Option<ast::MacroRules> = None; 96 let mut current_macro: Option<ast::Macro> = None;
97 let mut macro_rules_highlighter = MacroRulesHighlighter::default(); 97 let mut macro_highlighter = MacroHighlighter::default();
98 let mut inside_attribute = false; 98 let mut inside_attribute = false;
99 99
100 // Walk all nodes, keeping track of whether we are inside a macro or not. 100 // Walk all nodes, keeping track of whether we are inside a macro or not.
@@ -129,16 +129,16 @@ fn traverse(
129 _ => (), 129 _ => (),
130 } 130 }
131 131
132 match event.clone().map(|it| it.into_node().and_then(ast::MacroRules::cast)) { 132 match event.clone().map(|it| it.into_node().and_then(ast::Macro::cast)) {
133 WalkEvent::Enter(Some(mac)) => { 133 WalkEvent::Enter(Some(mac)) => {
134 macro_rules_highlighter.init(); 134 macro_highlighter.init();
135 current_macro_rules = Some(mac); 135 current_macro = Some(mac);
136 continue; 136 continue;
137 } 137 }
138 WalkEvent::Leave(Some(mac)) => { 138 WalkEvent::Leave(Some(mac)) => {
139 assert_eq!(current_macro_rules, Some(mac)); 139 assert_eq!(current_macro, Some(mac));
140 current_macro_rules = None; 140 current_macro = None;
141 macro_rules_highlighter = MacroRulesHighlighter::default(); 141 macro_highlighter = MacroHighlighter::default();
142 } 142 }
143 _ => (), 143 _ => (),
144 } 144 }
@@ -164,9 +164,9 @@ fn traverse(
164 164
165 let range = element.text_range(); 165 let range = element.text_range();
166 166
167 if current_macro_rules.is_some() { 167 if current_macro.is_some() {
168 if let Some(tok) = element.as_token() { 168 if let Some(tok) = element.as_token() {
169 macro_rules_highlighter.advance(tok); 169 macro_highlighter.advance(tok);
170 } 170 }
171 } 171 }
172 172
@@ -200,7 +200,7 @@ fn traverse(
200 } 200 }
201 } 201 }
202 202
203 if let Some(_) = macro_rules_highlighter.highlight(element_to_highlight.clone()) { 203 if let Some(_) = macro_highlighter.highlight(element_to_highlight.clone()) {
204 continue; 204 continue;
205 } 205 }
206 206
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 38bf49348..963c3fb59 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -109,8 +109,7 @@ fn doc_attributes<'node>(
109 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))), 109 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
110 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), 110 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
111 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))), 111 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
112 ast::MacroRules(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))), 112 ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
113 // ast::MacroDef(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
114 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))), 113 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
115 _ => return None 114 _ => return None
116 } 115 }
diff --git a/crates/ide/src/syntax_highlighting/macro_rules.rs b/crates/ide/src/syntax_highlighting/macro_.rs
index 44620e912..819704294 100644
--- a/crates/ide/src/syntax_highlighting/macro_rules.rs
+++ b/crates/ide/src/syntax_highlighting/macro_.rs
@@ -4,18 +4,18 @@ use syntax::{SyntaxElement, SyntaxKind, SyntaxToken, TextRange, T};
4use crate::{HlRange, HlTag}; 4use crate::{HlRange, HlTag};
5 5
6#[derive(Default)] 6#[derive(Default)]
7pub(super) struct MacroRulesHighlighter { 7pub(super) struct MacroHighlighter {
8 state: Option<MacroMatcherParseState>, 8 state: Option<MacroMatcherParseState>,
9} 9}
10 10
11impl MacroRulesHighlighter { 11impl MacroHighlighter {
12 pub(super) fn init(&mut self) { 12 pub(super) fn init(&mut self) {
13 self.state = Some(MacroMatcherParseState::default()); 13 self.state = Some(MacroMatcherParseState::default());
14 } 14 }
15 15
16 pub(super) fn advance(&mut self, token: &SyntaxToken) { 16 pub(super) fn advance(&mut self, token: &SyntaxToken) {
17 if let Some(state) = self.state.as_mut() { 17 if let Some(state) = self.state.as_mut() {
18 update_macro_rules_state(state, token); 18 update_macro_state(state, token);
19 } 19 }
20 } 20 }
21 21
@@ -74,9 +74,9 @@ impl RuleState {
74 } 74 }
75} 75}
76 76
77fn update_macro_rules_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { 77fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) {
78 if !state.in_invoc_body { 78 if !state.in_invoc_body {
79 if tok.kind() == T!['{'] { 79 if tok.kind() == T!['{'] || tok.kind() == T!['('] {
80 state.in_invoc_body = true; 80 state.in_invoc_body = true;
81 } 81 }
82 return; 82 return;
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 8b2dd3b70..1eaa7b75b 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
41<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span> 41<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
42 42
43<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span> 43<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="function attribute">rustc_builtin_macro</span><span class="attribute attribute">]</span>
44<span class="keyword">macro</span> <span class="unresolved_reference declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span> 44<span class="keyword">macro</span> <span class="macro declaration">Copy</span> <span class="brace">{</span><span class="brace">}</span>
45 45
46<span class="comment">// Needed for function consuming vs normal</span> 46<span class="comment">// Needed for function consuming vs normal</span>
47<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span> 47<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">marker</span> <span class="brace">{</span>
@@ -158,6 +158,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
158 <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> 158 <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span>
159<span class="brace">}</span> 159<span class="brace">}</span>
160 160
161<span class="keyword">macro</span> <span class="macro declaration">with_args</span><span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="brace">{</span>
162 <span class="punctuation">$</span>i
163<span class="brace">}</span>
164
165<span class="keyword">macro</span> <span class="macro declaration">without_args</span> <span class="brace">{</span>
166 <span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
167 <span class="punctuation">$</span>i
168 <span class="brace">}</span>
169<span class="brace">}</span>
170
161<span class="comment">// comment</span> 171<span class="comment">// comment</span>
162<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 172<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
163 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span> 173 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"Hello, {}!"</span><span class="comma">,</span> <span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 7b2922b0d..369ae0972 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -129,6 +129,16 @@ macro_rules! keyword_frag {
129 ($type:ty) => ($type) 129 ($type:ty) => ($type)
130} 130}
131 131
132macro with_args($i:ident) {
133 $i
134}
135
136macro without_args {
137 ($i:ident) => {
138 $i
139 }
140}
141
132// comment 142// comment
133fn main() { 143fn main() {
134 println!("Hello, {}!", 92); 144 println!("Hello, {}!", 92);
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index ab23dd7ac..0d9808d24 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -227,7 +227,7 @@ impl NameClass {
227 let def: hir::TypeAlias = sema.to_def(&it)?; 227 let def: hir::TypeAlias = sema.to_def(&it)?;
228 Some(NameClass::Definition(Definition::ModuleDef(def.into()))) 228 Some(NameClass::Definition(Definition::ModuleDef(def.into())))
229 }, 229 },
230 ast::MacroRules(it) => { 230 ast::Macro(it) => {
231 let def = sema.to_def(&it)?; 231 let def = sema.to_def(&it)?;
232 Some(NameClass::Definition(Definition::Macro(def))) 232 Some(NameClass::Definition(Definition::Macro(def)))
233 }, 233 },
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 35e382b5c..da427d686 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -438,7 +438,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
438 ast::TypeAlias(it) => decl(it), 438 ast::TypeAlias(it) => decl(it),
439 ast::Const(it) => decl(it), 439 ast::Const(it) => decl(it),
440 ast::Static(it) => decl(it), 440 ast::Static(it) => decl(it),
441 ast::MacroRules(it) => decl(it), 441 ast::Macro(it) => decl(it),
442 ast::Union(it) => decl(it), 442 ast::Union(it) => decl(it),
443 _ => None, 443 _ => None,
444 } 444 }
@@ -458,6 +458,7 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
458 CONST => FileSymbolKind::Const, 458 CONST => FileSymbolKind::Const,
459 STATIC => FileSymbolKind::Static, 459 STATIC => FileSymbolKind::Static,
460 MACRO_RULES => FileSymbolKind::Macro, 460 MACRO_RULES => FileSymbolKind::Macro,
461 MACRO_DEF => FileSymbolKind::Macro,
461 UNION => FileSymbolKind::Union, 462 UNION => FileSymbolKind::Union,
462 kind => unreachable!("{:?}", kind), 463 kind => unreachable!("{:?}", kind),
463 }, 464 },
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 2772d7364..ae98dbd26 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -40,6 +40,7 @@ fn text_of_first_token(node: &SyntaxNode) -> TokenText {
40 TokenText(first_token) 40 TokenText(first_token)
41} 41}
42 42
43#[derive(Debug, PartialEq, Eq, Clone)]
43pub enum Macro { 44pub enum Macro {
44 MacroRules(ast::MacroRules), 45 MacroRules(ast::MacroRules),
45 MacroDef(ast::MacroDef), 46 MacroDef(ast::MacroDef),
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs
index bb10f20c9..1934204ea 100644
--- a/crates/syntax/src/parsing/text_tree_sink.rs
+++ b/crates/syntax/src/parsing/text_tree_sink.rs
@@ -147,8 +147,8 @@ fn n_attached_trivias<'a>(
147 trivias: impl Iterator<Item = (SyntaxKind, &'a str)>, 147 trivias: impl Iterator<Item = (SyntaxKind, &'a str)>,
148) -> usize { 148) -> usize {
149 match kind { 149 match kind {
150 MACRO_CALL | MACRO_RULES | CONST | TYPE_ALIAS | STRUCT | UNION | ENUM | VARIANT | FN 150 MACRO_CALL | MACRO_RULES | MACRO_DEF | CONST | TYPE_ALIAS | STRUCT | UNION | ENUM
151 | TRAIT | MODULE | RECORD_FIELD | STATIC | USE => { 151 | VARIANT | FN | TRAIT | MODULE | RECORD_FIELD | STATIC | USE => {
152 let mut res = 0; 152 let mut res = 0;
153 let mut trivias = trivias.enumerate().peekable(); 153 let mut trivias = trivias.enumerate().peekable();
154 154