diff options
Diffstat (limited to 'crates')
25 files changed, 310 insertions, 115 deletions
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 262002671..d57fad9ed 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs | |||
@@ -6,7 +6,7 @@ use hir_def::{ | |||
6 | src::{HasChildSource, HasSource as _}, | 6 | src::{HasChildSource, HasSource as _}, |
7 | Lookup, VariantId, | 7 | Lookup, VariantId, |
8 | }; | 8 | }; |
9 | use hir_expand::InFile; | 9 | use hir_expand::{InFile, MacroDefKind}; |
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
@@ -111,10 +111,17 @@ impl HasSource for TypeAlias { | |||
111 | } | 111 | } |
112 | } | 112 | } |
113 | impl HasSource for MacroDef { | 113 | impl HasSource for MacroDef { |
114 | type Ast = ast::Macro; | 114 | type Ast = Either<ast::Macro, ast::Fn>; |
115 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { | 115 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
116 | let ast_id = self.id.ast_id?; | 116 | Some(match &self.id.kind { |
117 | Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) }) | 117 | MacroDefKind::Declarative(id) |
118 | | MacroDefKind::BuiltIn(_, id) | ||
119 | | MacroDefKind::BuiltInDerive(_, id) | ||
120 | | MacroDefKind::BuiltInEager(_, id) => { | ||
121 | id.with_value(Either::Left(id.to_node(db.upcast()))) | ||
122 | } | ||
123 | MacroDefKind::ProcMacro(_, id) => id.map(|_| Either::Right(id.to_node(db.upcast()))), | ||
124 | }) | ||
118 | } | 125 | } |
119 | } | 126 | } |
120 | impl HasSource for Impl { | 127 | impl HasSource for Impl { |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index b41a36a78..95cfde61c 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -1144,17 +1144,21 @@ impl MacroDef { | |||
1144 | 1144 | ||
1145 | /// XXX: this parses the file | 1145 | /// XXX: this parses the file |
1146 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 1146 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
1147 | self.source(db)?.value.name().map(|it| it.as_name()) | 1147 | match self.source(db)?.value { |
1148 | Either::Left(it) => it.name().map(|it| it.as_name()), | ||
1149 | Either::Right(it) => it.name().map(|it| it.as_name()), | ||
1150 | } | ||
1148 | } | 1151 | } |
1149 | 1152 | ||
1150 | /// Indicate it is a proc-macro | 1153 | /// Indicate it is a proc-macro |
1151 | pub fn is_proc_macro(&self) -> bool { | 1154 | pub fn is_proc_macro(&self) -> bool { |
1152 | matches!(self.id.kind, MacroDefKind::ProcMacro(_)) | 1155 | matches!(self.id.kind, MacroDefKind::ProcMacro(..)) |
1153 | } | 1156 | } |
1154 | 1157 | ||
1155 | /// Indicate it is a derive macro | 1158 | /// Indicate it is a derive macro |
1156 | pub fn is_derive_macro(&self) -> bool { | 1159 | pub fn is_derive_macro(&self) -> bool { |
1157 | matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_)) | 1160 | // FIXME: wrong for `ProcMacro` |
1161 | matches!(self.id.kind, MacroDefKind::ProcMacro(..) | MacroDefKind::BuiltInDerive(..)) | ||
1158 | } | 1162 | } |
1159 | } | 1163 | } |
1160 | 1164 | ||
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index c6ad5ecb5..762809fcd 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -195,12 +195,12 @@ impl SourceToDefCtx<'_, '_> { | |||
195 | &mut self, | 195 | &mut self, |
196 | src: InFile<ast::MacroRules>, | 196 | src: InFile<ast::MacroRules>, |
197 | ) -> Option<MacroDefId> { | 197 | ) -> Option<MacroDefId> { |
198 | let kind = MacroDefKind::Declarative; | 198 | 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()); | ||
200 | let kind = MacroDefKind::Declarative(ast_id); | ||
199 | let file_id = src.file_id.original_file(self.db.upcast()); | 201 | let file_id = src.file_id.original_file(self.db.upcast()); |
200 | let krate = self.file_to_def(file_id).get(0).copied()?.krate(); | 202 | let krate = self.file_to_def(file_id).get(0).copied()?.krate(); |
201 | let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); | 203 | Some(MacroDefId { krate, kind, local_inner: false }) |
202 | let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast())); | ||
203 | Some(MacroDefId { krate, ast_id, kind, local_inner: false }) | ||
204 | } | 204 | } |
205 | 205 | ||
206 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { | 206 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 739e3f5e3..1cab0e363 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -209,7 +209,7 @@ impl Attrs { | |||
209 | }, | 209 | }, |
210 | AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 210 | AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
211 | AttrDefId::MacroDefId(it) => { | 211 | AttrDefId::MacroDefId(it) => { |
212 | it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) | 212 | it.ast_id().map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) |
213 | } | 213 | } |
214 | AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 214 | AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
215 | AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 215 | AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 369bc3350..960cabb5f 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -912,10 +912,10 @@ mod tests { | |||
912 | dep::fmt (t) | 912 | dep::fmt (t) |
913 | dep::format (f) | 913 | dep::format (f) |
914 | dep::Fmt (v) | 914 | dep::Fmt (v) |
915 | dep::fmt::Display (t) | 915 | dep::Fmt (m) |
916 | dep::Fmt (t) | 916 | dep::Fmt (t) |
917 | dep::fmt::Display::fmt (a) | 917 | dep::fmt::Display::fmt (a) |
918 | dep::Fmt (m) | 918 | dep::fmt::Display (t) |
919 | "#]], | 919 | "#]], |
920 | ); | 920 | ); |
921 | 921 | ||
@@ -926,9 +926,9 @@ mod tests { | |||
926 | expect![[r#" | 926 | expect![[r#" |
927 | dep::fmt (t) | 927 | dep::fmt (t) |
928 | dep::Fmt (v) | 928 | dep::Fmt (v) |
929 | dep::Fmt (m) | ||
929 | dep::Fmt (t) | 930 | dep::Fmt (t) |
930 | dep::fmt::Display::fmt (a) | 931 | dep::fmt::Display::fmt (a) |
931 | dep::Fmt (m) | ||
932 | "#]], | 932 | "#]], |
933 | ); | 933 | ); |
934 | 934 | ||
@@ -939,10 +939,10 @@ mod tests { | |||
939 | expect![[r#" | 939 | expect![[r#" |
940 | dep::fmt (t) | 940 | dep::fmt (t) |
941 | dep::Fmt (v) | 941 | dep::Fmt (v) |
942 | dep::fmt::Display (t) | 942 | dep::Fmt (m) |
943 | dep::Fmt (t) | 943 | dep::Fmt (t) |
944 | dep::fmt::Display::fmt (a) | 944 | dep::fmt::Display::fmt (a) |
945 | dep::Fmt (m) | 945 | dep::fmt::Display (t) |
946 | "#]], | 946 | "#]], |
947 | ); | 947 | ); |
948 | } | 948 | } |
@@ -980,10 +980,10 @@ mod tests { | |||
980 | expect![[r#" | 980 | expect![[r#" |
981 | dep::fmt (t) | 981 | dep::fmt (t) |
982 | dep::Fmt (v) | 982 | dep::Fmt (v) |
983 | dep::fmt::Display (t) | 983 | dep::Fmt (m) |
984 | dep::Fmt (t) | 984 | dep::Fmt (t) |
985 | dep::fmt::Display::fmt (a) | 985 | dep::fmt::Display::fmt (a) |
986 | dep::Fmt (m) | 986 | dep::fmt::Display (t) |
987 | "#]], | 987 | "#]], |
988 | ); | 988 | ); |
989 | 989 | ||
@@ -994,9 +994,9 @@ mod tests { | |||
994 | expect![[r#" | 994 | expect![[r#" |
995 | dep::fmt (t) | 995 | dep::fmt (t) |
996 | dep::Fmt (v) | 996 | dep::Fmt (v) |
997 | dep::Fmt (m) | ||
997 | dep::Fmt (t) | 998 | dep::Fmt (t) |
998 | dep::fmt::Display::fmt (a) | 999 | dep::fmt::Display::fmt (a) |
999 | dep::Fmt (m) | ||
1000 | "#]], | 1000 | "#]], |
1001 | ); | 1001 | ); |
1002 | } | 1002 | } |
@@ -1058,8 +1058,8 @@ mod tests { | |||
1058 | Query::new("".to_string()).limit(2), | 1058 | Query::new("".to_string()).limit(2), |
1059 | expect![[r#" | 1059 | expect![[r#" |
1060 | dep::fmt (t) | 1060 | dep::fmt (t) |
1061 | dep::Fmt (t) | ||
1062 | dep::Fmt (m) | 1061 | dep::Fmt (m) |
1062 | dep::Fmt (t) | ||
1063 | dep::Fmt (v) | 1063 | dep::Fmt (v) |
1064 | "#]], | 1064 | "#]], |
1065 | ); | 1065 | ); |
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index aafd73b60..f3ebe7c72 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -252,7 +252,7 @@ impl ItemScope { | |||
252 | .for_each(|vis| *vis = Visibility::Module(this_module)); | 252 | .for_each(|vis| *vis = Visibility::Module(this_module)); |
253 | 253 | ||
254 | for (mac, vis) in self.macros.values_mut() { | 254 | for (mac, vis) in self.macros.values_mut() { |
255 | if let MacroDefKind::ProcMacro(_) = mac.kind { | 255 | if let MacroDefKind::ProcMacro(..) = mac.kind { |
256 | // FIXME: Technically this is insufficient since reexports of proc macros are also | 256 | // FIXME: Technically this is insufficient since reexports of proc macros are also |
257 | // forbidden. Practically nobody does that. | 257 | // forbidden. Practically nobody does that. |
258 | continue; | 258 | continue; |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 5f5b7151a..ae2475b4e 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -115,6 +115,10 @@ impl ItemTree { | |||
115 | // still need to collect inner items. | 115 | // still need to collect inner items. |
116 | ctx.lower_inner_items(stmt.syntax()) | 116 | ctx.lower_inner_items(stmt.syntax()) |
117 | }, | 117 | }, |
118 | ast::Item(item) => { | ||
119 | // Macros can expand to stmt and other item, and we add it as top level item | ||
120 | ctx.lower_single_item(item) | ||
121 | }, | ||
118 | _ => { | 122 | _ => { |
119 | panic!("cannot create item tree from {:?} {}", syntax, syntax); | 123 | panic!("cannot create item tree from {:?} {}", syntax, syntax); |
120 | }, | 124 | }, |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 3f558edd8..d3fe1ce1e 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -87,6 +87,14 @@ impl Ctx { | |||
87 | self.tree | 87 | self.tree |
88 | } | 88 | } |
89 | 89 | ||
90 | pub(super) fn lower_single_item(mut self, item: ast::Item) -> ItemTree { | ||
91 | self.tree.top_level = self | ||
92 | .lower_mod_item(&item, false) | ||
93 | .map(|item| item.0) | ||
94 | .unwrap_or_else(|| Default::default()); | ||
95 | self.tree | ||
96 | } | ||
97 | |||
90 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { | 98 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { |
91 | self.collect_inner_items(within); | 99 | self.collect_inner_items(within); |
92 | self.tree | 100 | self.tree |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 6758411a0..21add086d 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -650,7 +650,7 @@ fn macro_call_as_call_id( | |||
650 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { | 650 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { |
651 | let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; | 651 | let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; |
652 | 652 | ||
653 | let res = if let MacroDefKind::BuiltInEager(_) = def.kind { | 653 | let res = if let MacroDefKind::BuiltInEager(..) = def.kind { |
654 | let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); | 654 | let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); |
655 | let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id); | 655 | let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id); |
656 | 656 | ||
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index c97be584e..1ac326f97 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -53,11 +53,12 @@ mod path_resolution; | |||
53 | 53 | ||
54 | #[cfg(test)] | 54 | #[cfg(test)] |
55 | mod tests; | 55 | mod tests; |
56 | mod proc_macro; | ||
56 | 57 | ||
57 | use std::sync::Arc; | 58 | use std::sync::Arc; |
58 | 59 | ||
59 | use base_db::{CrateId, Edition, FileId}; | 60 | use base_db::{CrateId, Edition, FileId}; |
60 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; | 61 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId}; |
61 | use la_arena::Arena; | 62 | use la_arena::Arena; |
62 | use profile::Count; | 63 | use profile::Count; |
63 | use rustc_hash::FxHashMap; | 64 | use rustc_hash::FxHashMap; |
@@ -73,6 +74,8 @@ use crate::{ | |||
73 | AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId, | 74 | AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId, |
74 | }; | 75 | }; |
75 | 76 | ||
77 | use self::proc_macro::ProcMacroDef; | ||
78 | |||
76 | /// Contains the results of (early) name resolution. | 79 | /// Contains the results of (early) name resolution. |
77 | /// | 80 | /// |
78 | /// A `DefMap` stores the module tree and the definitions that are in scope in every module after | 81 | /// A `DefMap` stores the module tree and the definitions that are in scope in every module after |
@@ -95,6 +98,12 @@ pub struct DefMap { | |||
95 | prelude: Option<ModuleId>, | 98 | prelude: Option<ModuleId>, |
96 | extern_prelude: FxHashMap<Name, ModuleDefId>, | 99 | extern_prelude: FxHashMap<Name, ModuleDefId>, |
97 | 100 | ||
101 | /// Side table with additional proc. macro info, for use by name resolution in downstream | ||
102 | /// crates. | ||
103 | /// | ||
104 | /// (the primary purpose is to resolve derive helpers) | ||
105 | exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>, | ||
106 | |||
98 | edition: Edition, | 107 | edition: Edition, |
99 | diagnostics: Vec<DefDiagnostic>, | 108 | diagnostics: Vec<DefDiagnostic>, |
100 | } | 109 | } |
@@ -237,6 +246,7 @@ impl DefMap { | |||
237 | krate, | 246 | krate, |
238 | edition, | 247 | edition, |
239 | extern_prelude: FxHashMap::default(), | 248 | extern_prelude: FxHashMap::default(), |
249 | exported_proc_macros: FxHashMap::default(), | ||
240 | prelude: None, | 250 | prelude: None, |
241 | root, | 251 | root, |
242 | modules, | 252 | modules, |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d0fefb5af..dcedf7766 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -18,7 +18,6 @@ use hir_expand::{ | |||
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | use syntax::ast; | 20 | use syntax::ast; |
21 | use tt::{Leaf, TokenTree}; | ||
22 | 21 | ||
23 | use crate::{ | 22 | use crate::{ |
24 | attr::Attrs, | 23 | attr::Attrs, |
@@ -42,6 +41,8 @@ use crate::{ | |||
42 | UnresolvedMacro, | 41 | UnresolvedMacro, |
43 | }; | 42 | }; |
44 | 43 | ||
44 | use super::proc_macro::ProcMacroDef; | ||
45 | |||
45 | const GLOB_RECURSION_LIMIT: usize = 100; | 46 | const GLOB_RECURSION_LIMIT: usize = 100; |
46 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 47 | const EXPANSION_DEPTH_LIMIT: usize = 128; |
47 | const FIXED_POINT_LIMIT: usize = 8192; | 48 | const FIXED_POINT_LIMIT: usize = 8192; |
@@ -353,24 +354,23 @@ impl DefCollector<'_> { | |||
353 | /// use a dummy expander that always errors. This comes with the drawback of macros potentially | 354 | /// use a dummy expander that always errors. This comes with the drawback of macros potentially |
354 | /// going out of sync with what the build system sees (since we resolve using VFS state, but | 355 | /// going out of sync with what the build system sees (since we resolve using VFS state, but |
355 | /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. | 356 | /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. |
356 | fn resolve_proc_macro(&mut self, name: &Name) { | 357 | fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) { |
357 | self.exports_proc_macros = true; | 358 | self.exports_proc_macros = true; |
358 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) { | 359 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { |
359 | Some((_, expander)) => MacroDefId { | 360 | Some((_, expander)) => MacroDefId { |
360 | ast_id: None, | ||
361 | krate: self.def_map.krate, | 361 | krate: self.def_map.krate, |
362 | kind: MacroDefKind::ProcMacro(*expander), | 362 | kind: MacroDefKind::ProcMacro(*expander, ast_id), |
363 | local_inner: false, | 363 | local_inner: false, |
364 | }, | 364 | }, |
365 | None => MacroDefId { | 365 | None => MacroDefId { |
366 | ast_id: None, | ||
367 | krate: self.def_map.krate, | 366 | krate: self.def_map.krate, |
368 | kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)), | 367 | kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate), ast_id), |
369 | local_inner: false, | 368 | local_inner: false, |
370 | }, | 369 | }, |
371 | }; | 370 | }; |
372 | 371 | ||
373 | self.define_proc_macro(name.clone(), macro_def); | 372 | self.define_proc_macro(def.name.clone(), macro_def); |
373 | self.def_map.exported_proc_macros.insert(macro_def, def); | ||
374 | } | 374 | } |
375 | 375 | ||
376 | /// Define a macro with `macro_rules`. | 376 | /// Define a macro with `macro_rules`. |
@@ -1118,7 +1118,8 @@ impl ModCollector<'_, '_> { | |||
1118 | ModItem::Function(id) => { | 1118 | ModItem::Function(id) => { |
1119 | let func = &self.item_tree[id]; | 1119 | let func = &self.item_tree[id]; |
1120 | 1120 | ||
1121 | self.collect_proc_macro_def(&func.name, &attrs); | 1121 | let ast_id = InFile::new(self.file_id, func.ast_id); |
1122 | self.collect_proc_macro_def(&func.name, ast_id, &attrs); | ||
1122 | 1123 | ||
1123 | def = Some(DefData { | 1124 | def = Some(DefData { |
1124 | id: FunctionLoc { | 1125 | id: FunctionLoc { |
@@ -1385,28 +1386,11 @@ impl ModCollector<'_, '_> { | |||
1385 | } | 1386 | } |
1386 | 1387 | ||
1387 | /// If `attrs` registers a procedural macro, collects its definition. | 1388 | /// If `attrs` registers a procedural macro, collects its definition. |
1388 | fn collect_proc_macro_def(&mut self, func_name: &Name, attrs: &Attrs) { | 1389 | fn collect_proc_macro_def(&mut self, func_name: &Name, ast_id: AstId<ast::Fn>, attrs: &Attrs) { |
1389 | // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere | 1390 | // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere |
1390 | // FIXME: distinguish the type of macro | 1391 | if let Some(proc_macro) = attrs.parse_proc_macro_decl(func_name) { |
1391 | let macro_name = if attrs.by_key("proc_macro").exists() | 1392 | self.def_collector.export_proc_macro(proc_macro, ast_id); |
1392 | || attrs.by_key("proc_macro_attribute").exists() | 1393 | } |
1393 | { | ||
1394 | func_name.clone() | ||
1395 | } else { | ||
1396 | let derive = attrs.by_key("proc_macro_derive"); | ||
1397 | if let Some(arg) = derive.tt_values().next() { | ||
1398 | if let [TokenTree::Leaf(Leaf::Ident(trait_name)), ..] = &*arg.token_trees { | ||
1399 | trait_name.as_name() | ||
1400 | } else { | ||
1401 | log::trace!("malformed `#[proc_macro_derive]`: {}", arg); | ||
1402 | return; | ||
1403 | } | ||
1404 | } else { | ||
1405 | return; | ||
1406 | } | ||
1407 | }; | ||
1408 | |||
1409 | self.def_collector.resolve_proc_macro(¯o_name); | ||
1410 | } | 1394 | } |
1411 | 1395 | ||
1412 | fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { | 1396 | fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { |
@@ -1445,9 +1429,8 @@ impl ModCollector<'_, '_> { | |||
1445 | 1429 | ||
1446 | // Case 2: normal `macro_rules!` macro | 1430 | // Case 2: normal `macro_rules!` macro |
1447 | let macro_id = MacroDefId { | 1431 | let macro_id = MacroDefId { |
1448 | ast_id: Some(ast_id), | ||
1449 | krate: self.def_collector.def_map.krate, | 1432 | krate: self.def_collector.def_map.krate, |
1450 | kind: MacroDefKind::Declarative, | 1433 | kind: MacroDefKind::Declarative(ast_id), |
1451 | local_inner: is_local_inner, | 1434 | local_inner: is_local_inner, |
1452 | }; | 1435 | }; |
1453 | self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); | 1436 | self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); |
diff --git a/crates/hir_def/src/nameres/proc_macro.rs b/crates/hir_def/src/nameres/proc_macro.rs new file mode 100644 index 000000000..156598f19 --- /dev/null +++ b/crates/hir_def/src/nameres/proc_macro.rs | |||
@@ -0,0 +1,71 @@ | |||
1 | //! Nameres-specific procedural macro data and helpers. | ||
2 | |||
3 | use hir_expand::name::{AsName, Name}; | ||
4 | use tt::{Leaf, TokenTree}; | ||
5 | |||
6 | use crate::attr::Attrs; | ||
7 | |||
8 | #[derive(Debug, PartialEq, Eq)] | ||
9 | pub(super) struct ProcMacroDef { | ||
10 | pub(super) name: Name, | ||
11 | pub(super) kind: ProcMacroKind, | ||
12 | } | ||
13 | |||
14 | #[derive(Debug, PartialEq, Eq)] | ||
15 | pub(super) enum ProcMacroKind { | ||
16 | CustomDerive { helpers: Box<[Name]> }, | ||
17 | FnLike, | ||
18 | Attr, | ||
19 | } | ||
20 | |||
21 | impl Attrs { | ||
22 | #[rustfmt::skip] | ||
23 | pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> { | ||
24 | if self.by_key("proc_macro").exists() { | ||
25 | Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike }) | ||
26 | } else if self.by_key("proc_macro_attribute").exists() { | ||
27 | Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr }) | ||
28 | } else if self.by_key("proc_macro_derive").exists() { | ||
29 | let derive = self.by_key("proc_macro_derive").tt_values().next().unwrap(); | ||
30 | |||
31 | match &*derive.token_trees { | ||
32 | // `#[proc_macro_derive(Trait)]` | ||
33 | [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef { | ||
34 | name: trait_name.as_name(), | ||
35 | kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) }, | ||
36 | }), | ||
37 | |||
38 | // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]` | ||
39 | [ | ||
40 | TokenTree::Leaf(Leaf::Ident(trait_name)), | ||
41 | TokenTree::Leaf(Leaf::Punct(comma)), | ||
42 | TokenTree::Leaf(Leaf::Ident(attributes)), | ||
43 | TokenTree::Subtree(helpers) | ||
44 | ] if comma.char == ',' && attributes.text == "attributes" => | ||
45 | { | ||
46 | let helpers = helpers.token_trees.iter() | ||
47 | .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ',')) | ||
48 | .map(|tt| { | ||
49 | match tt { | ||
50 | TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()), | ||
51 | _ => None | ||
52 | } | ||
53 | }) | ||
54 | .collect::<Option<Box<[_]>>>()?; | ||
55 | |||
56 | Some(ProcMacroDef { | ||
57 | name: trait_name.as_name(), | ||
58 | kind: ProcMacroKind::CustomDerive { helpers }, | ||
59 | }) | ||
60 | } | ||
61 | |||
62 | _ => { | ||
63 | log::trace!("malformed `#[proc_macro_derive]`: {}", derive); | ||
64 | None | ||
65 | } | ||
66 | } | ||
67 | } else { | ||
68 | None | ||
69 | } | ||
70 | } | ||
71 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index f65a655bf..d59d3c0db 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use super::*; | 1 | use super::*; |
2 | use crate::nameres::proc_macro::{ProcMacroDef, ProcMacroKind}; | ||
2 | 3 | ||
3 | #[test] | 4 | #[test] |
4 | fn macro_rules_are_globally_visible() { | 5 | fn macro_rules_are_globally_visible() { |
@@ -790,3 +791,28 @@ fn proc_macro_censoring() { | |||
790 | "#]], | 791 | "#]], |
791 | ); | 792 | ); |
792 | } | 793 | } |
794 | |||
795 | #[test] | ||
796 | fn collects_derive_helpers() { | ||
797 | let def_map = compute_crate_def_map( | ||
798 | r" | ||
799 | struct TokenStream; | ||
800 | |||
801 | #[proc_macro_derive(AnotherTrait, attributes(helper_attr))] | ||
802 | pub fn derive_macro_2(_item: TokenStream) -> TokenStream { | ||
803 | TokenStream | ||
804 | } | ||
805 | ", | ||
806 | ); | ||
807 | |||
808 | assert_eq!(def_map.exported_proc_macros.len(), 1); | ||
809 | match def_map.exported_proc_macros.values().next() { | ||
810 | Some(ProcMacroDef { kind: ProcMacroKind::CustomDerive { helpers }, .. }) => { | ||
811 | match &**helpers { | ||
812 | [attr] => assert_eq!(attr.to_string(), "helper_attr"), | ||
813 | _ => unreachable!(), | ||
814 | } | ||
815 | } | ||
816 | _ => unreachable!(), | ||
817 | } | ||
818 | } | ||
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs index 5e908b223..60fd2ebdd 100644 --- a/crates/hir_expand/src/builtin_derive.rs +++ b/crates/hir_expand/src/builtin_derive.rs | |||
@@ -61,8 +61,7 @@ pub fn find_builtin_derive( | |||
61 | let expander = BuiltinDeriveExpander::find_by_name(ident)?; | 61 | let expander = BuiltinDeriveExpander::find_by_name(ident)?; |
62 | Some(MacroDefId { | 62 | Some(MacroDefId { |
63 | krate, | 63 | krate, |
64 | ast_id: Some(ast_id), | 64 | kind: MacroDefKind::BuiltInDerive(expander, ast_id), |
65 | kind: MacroDefKind::BuiltInDerive(expander), | ||
66 | local_inner: false, | 65 | local_inner: false, |
67 | }) | 66 | }) |
68 | } | 67 | } |
@@ -268,14 +267,13 @@ fn partial_ord_expand( | |||
268 | mod tests { | 267 | mod tests { |
269 | use base_db::{fixture::WithFixture, CrateId, SourceDatabase}; | 268 | use base_db::{fixture::WithFixture, CrateId, SourceDatabase}; |
270 | use expect_test::{expect, Expect}; | 269 | use expect_test::{expect, Expect}; |
271 | use name::{known, Name}; | 270 | use name::AsName; |
272 | 271 | ||
273 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | 272 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; |
274 | 273 | ||
275 | use super::*; | 274 | use super::*; |
276 | 275 | ||
277 | fn expand_builtin_derive(ra_fixture: &str, name: Name) -> String { | 276 | fn expand_builtin_derive(ra_fixture: &str) -> String { |
278 | let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); | ||
279 | let fixture = format!( | 277 | let fixture = format!( |
280 | r#"//- /main.rs crate:main deps:core | 278 | r#"//- /main.rs crate:main deps:core |
281 | $0 | 279 | $0 |
@@ -288,19 +286,34 @@ $0 | |||
288 | 286 | ||
289 | let (db, file_pos) = TestDB::with_position(&fixture); | 287 | let (db, file_pos) = TestDB::with_position(&fixture); |
290 | let file_id = file_pos.file_id; | 288 | let file_id = file_pos.file_id; |
289 | let ast_id_map = db.ast_id_map(file_id.into()); | ||
291 | let parsed = db.parse(file_id); | 290 | let parsed = db.parse(file_id); |
292 | let items: Vec<_> = | 291 | let macros: Vec<_> = |
293 | parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect(); | 292 | parsed.syntax_node().descendants().filter_map(ast::Macro::cast).collect(); |
293 | let items: Vec<_> = parsed | ||
294 | .syntax_node() | ||
295 | .descendants() | ||
296 | .filter(|node| !ast::Macro::can_cast(node.kind())) | ||
297 | .filter_map(ast::Item::cast) | ||
298 | .collect(); | ||
299 | |||
300 | assert_eq!(macros.len(), 1, "test must contain exactly 1 macro definition"); | ||
301 | assert_eq!(items.len(), 1, "test must contain exactly 1 item"); | ||
302 | |||
303 | let macro_ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯os[0])); | ||
304 | let name = match ¯os[0] { | ||
305 | ast::Macro::MacroRules(rules) => rules.name().unwrap().as_name(), | ||
306 | ast::Macro::MacroDef(def) => def.name().unwrap().as_name(), | ||
307 | }; | ||
294 | 308 | ||
295 | let ast_id_map = db.ast_id_map(file_id.into()); | 309 | let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); |
296 | 310 | ||
297 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); | 311 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); |
298 | 312 | ||
299 | let loc = MacroCallLoc { | 313 | let loc = MacroCallLoc { |
300 | def: MacroDefId { | 314 | def: MacroDefId { |
301 | krate: CrateId(0), | 315 | krate: CrateId(0), |
302 | ast_id: None, | 316 | kind: MacroDefKind::BuiltInDerive(expander, macro_ast_id), |
303 | kind: MacroDefKind::BuiltInDerive(expander), | ||
304 | local_inner: false, | 317 | local_inner: false, |
305 | }, | 318 | }, |
306 | krate: CrateId(0), | 319 | krate: CrateId(0), |
@@ -315,8 +328,8 @@ $0 | |||
315 | parsed.text().to_string() | 328 | parsed.text().to_string() |
316 | } | 329 | } |
317 | 330 | ||
318 | fn check_derive(ra_fixture: &str, name: Name, expected: Expect) { | 331 | fn check_derive(ra_fixture: &str, expected: Expect) { |
319 | let expanded = expand_builtin_derive(ra_fixture, name); | 332 | let expanded = expand_builtin_derive(ra_fixture); |
320 | expected.assert_eq(&expanded); | 333 | expected.assert_eq(&expanded); |
321 | } | 334 | } |
322 | 335 | ||
@@ -324,10 +337,10 @@ $0 | |||
324 | fn test_copy_expand_simple() { | 337 | fn test_copy_expand_simple() { |
325 | check_derive( | 338 | check_derive( |
326 | r#" | 339 | r#" |
340 | macro Copy {} | ||
327 | #[derive(Copy)] | 341 | #[derive(Copy)] |
328 | struct Foo; | 342 | struct Foo; |
329 | "#, | 343 | "#, |
330 | known::Copy, | ||
331 | expect![["impl< >core::marker::CopyforFoo< >{}"]], | 344 | expect![["impl< >core::marker::CopyforFoo< >{}"]], |
332 | ); | 345 | ); |
333 | } | 346 | } |
@@ -336,10 +349,10 @@ $0 | |||
336 | fn test_copy_expand_with_type_params() { | 349 | fn test_copy_expand_with_type_params() { |
337 | check_derive( | 350 | check_derive( |
338 | r#" | 351 | r#" |
352 | macro Copy {} | ||
339 | #[derive(Copy)] | 353 | #[derive(Copy)] |
340 | struct Foo<A, B>; | 354 | struct Foo<A, B>; |
341 | "#, | 355 | "#, |
342 | known::Copy, | ||
343 | expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]], | 356 | expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]], |
344 | ); | 357 | ); |
345 | } | 358 | } |
@@ -348,10 +361,10 @@ $0 | |||
348 | fn test_copy_expand_with_lifetimes() { | 361 | fn test_copy_expand_with_lifetimes() { |
349 | check_derive( | 362 | check_derive( |
350 | r#" | 363 | r#" |
364 | macro Copy {} | ||
351 | #[derive(Copy)] | 365 | #[derive(Copy)] |
352 | struct Foo<A, B, 'a, 'b>; | 366 | struct Foo<A, B, 'a, 'b>; |
353 | "#, | 367 | "#, |
354 | known::Copy, | ||
355 | // We currently just ignore lifetimes | 368 | // We currently just ignore lifetimes |
356 | expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]], | 369 | expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]], |
357 | ); | 370 | ); |
@@ -361,10 +374,10 @@ $0 | |||
361 | fn test_clone_expand() { | 374 | fn test_clone_expand() { |
362 | check_derive( | 375 | check_derive( |
363 | r#" | 376 | r#" |
377 | macro Clone {} | ||
364 | #[derive(Clone)] | 378 | #[derive(Clone)] |
365 | struct Foo<A, B>; | 379 | struct Foo<A, B>; |
366 | "#, | 380 | "#, |
367 | known::Clone, | ||
368 | expect![["impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"]], | 381 | expect![["impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"]], |
369 | ); | 382 | ); |
370 | } | 383 | } |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index fce09a9e7..8529b43b6 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -71,14 +71,12 @@ pub fn find_builtin_macro( | |||
71 | match kind { | 71 | match kind { |
72 | Either::Left(kind) => Some(MacroDefId { | 72 | Either::Left(kind) => Some(MacroDefId { |
73 | krate, | 73 | krate, |
74 | ast_id: Some(ast_id), | 74 | kind: MacroDefKind::BuiltIn(kind, ast_id), |
75 | kind: MacroDefKind::BuiltIn(kind), | ||
76 | local_inner: false, | 75 | local_inner: false, |
77 | }), | 76 | }), |
78 | Either::Right(kind) => Some(MacroDefId { | 77 | Either::Right(kind) => Some(MacroDefId { |
79 | krate, | 78 | krate, |
80 | ast_id: Some(ast_id), | 79 | kind: MacroDefKind::BuiltInEager(kind, ast_id), |
81 | kind: MacroDefKind::BuiltInEager(kind), | ||
82 | local_inner: false, | 80 | local_inner: false, |
83 | }), | 81 | }), |
84 | } | 82 | } |
@@ -512,6 +510,7 @@ mod tests { | |||
512 | let macro_call = macro_calls.pop().unwrap(); | 510 | let macro_call = macro_calls.pop().unwrap(); |
513 | 511 | ||
514 | let expander = find_by_name(¯o_rules.name().unwrap().as_name()).unwrap(); | 512 | let expander = find_by_name(¯o_rules.name().unwrap().as_name()).unwrap(); |
513 | let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules)); | ||
515 | 514 | ||
516 | let krate = CrateId(0); | 515 | let krate = CrateId(0); |
517 | let file_id = match expander { | 516 | let file_id = match expander { |
@@ -519,8 +518,7 @@ mod tests { | |||
519 | // the first one should be a macro_rules | 518 | // the first one should be a macro_rules |
520 | let def = MacroDefId { | 519 | let def = MacroDefId { |
521 | krate: CrateId(0), | 520 | krate: CrateId(0), |
522 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))), | 521 | kind: MacroDefKind::BuiltIn(expander, ast_id), |
523 | kind: MacroDefKind::BuiltIn(expander), | ||
524 | local_inner: false, | 522 | local_inner: false, |
525 | }; | 523 | }; |
526 | 524 | ||
@@ -540,8 +538,7 @@ mod tests { | |||
540 | // the first one should be a macro_rules | 538 | // the first one should be a macro_rules |
541 | let def = MacroDefId { | 539 | let def = MacroDefId { |
542 | krate, | 540 | krate, |
543 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))), | 541 | kind: MacroDefKind::BuiltInEager(expander, ast_id), |
544 | kind: MacroDefKind::BuiltInEager(expander), | ||
545 | local_inner: false, | 542 | local_inner: false, |
546 | }; | 543 | }; |
547 | 544 | ||
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index a3070f1f9..2748e25cf 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -130,8 +130,8 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | |||
130 | 130 | ||
131 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 131 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
132 | match id.kind { | 132 | match id.kind { |
133 | MacroDefKind::Declarative => { | 133 | MacroDefKind::Declarative(ast_id) => { |
134 | let macro_rules = match id.ast_id?.to_node(db) { | 134 | let macro_rules = match ast_id.to_node(db) { |
135 | syntax::ast::Macro::MacroRules(mac) => mac, | 135 | syntax::ast::Macro::MacroRules(mac) => mac, |
136 | syntax::ast::Macro::MacroDef(_) => return None, | 136 | syntax::ast::Macro::MacroDef(_) => return None, |
137 | }; | 137 | }; |
@@ -150,14 +150,14 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, | |||
150 | }; | 150 | }; |
151 | Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) | 151 | Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) |
152 | } | 152 | } |
153 | MacroDefKind::BuiltIn(expander) => { | 153 | MacroDefKind::BuiltIn(expander, _) => { |
154 | Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) | 154 | Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) |
155 | } | 155 | } |
156 | MacroDefKind::BuiltInDerive(expander) => { | 156 | MacroDefKind::BuiltInDerive(expander, _) => { |
157 | Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) | 157 | Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) |
158 | } | 158 | } |
159 | MacroDefKind::BuiltInEager(_) => None, | 159 | MacroDefKind::BuiltInEager(..) => None, |
160 | MacroDefKind::ProcMacro(expander) => { | 160 | MacroDefKind::ProcMacro(expander, ..) => { |
161 | Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default()))) | 161 | Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default()))) |
162 | } | 162 | } |
163 | } | 163 | } |
@@ -269,7 +269,7 @@ fn expand_proc_macro( | |||
269 | }; | 269 | }; |
270 | 270 | ||
271 | let expander = match loc.def.kind { | 271 | let expander = match loc.def.kind { |
272 | MacroDefKind::ProcMacro(expander) => expander, | 272 | MacroDefKind::ProcMacro(expander, ..) => expander, |
273 | _ => unreachable!(), | 273 | _ => unreachable!(), |
274 | }; | 274 | }; |
275 | 275 | ||
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index dc618a9ee..04f374a29 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -140,7 +140,7 @@ pub fn expand_eager_macro( | |||
140 | let subtree = | 140 | let subtree = |
141 | diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?; | 141 | diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?; |
142 | 142 | ||
143 | if let MacroDefKind::BuiltInEager(eager) = def.kind { | 143 | if let MacroDefKind::BuiltInEager(eager, _) = def.kind { |
144 | let res = eager.expand(db, arg_id, &subtree); | 144 | let res = eager.expand(db, arg_id, &subtree); |
145 | 145 | ||
146 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; | 146 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; |
@@ -193,7 +193,7 @@ fn eager_macro_recur( | |||
193 | let def = diagnostic_sink | 193 | let def = diagnostic_sink |
194 | .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?; | 194 | .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?; |
195 | let insert = match def.kind { | 195 | let insert = match def.kind { |
196 | MacroDefKind::BuiltInEager(_) => { | 196 | MacroDefKind::BuiltInEager(..) => { |
197 | let id: MacroCallId = expand_eager_macro( | 197 | let id: MacroCallId = expand_eager_macro( |
198 | db, | 198 | db, |
199 | krate, | 199 | krate, |
@@ -206,10 +206,10 @@ fn eager_macro_recur( | |||
206 | db.parse_or_expand(id.as_file()) | 206 | db.parse_or_expand(id.as_file()) |
207 | .expect("successful macro expansion should be parseable") | 207 | .expect("successful macro expansion should be parseable") |
208 | } | 208 | } |
209 | MacroDefKind::Declarative | 209 | MacroDefKind::Declarative(_) |
210 | | MacroDefKind::BuiltIn(_) | 210 | | MacroDefKind::BuiltIn(..) |
211 | | MacroDefKind::BuiltInDerive(_) | 211 | | MacroDefKind::BuiltInDerive(..) |
212 | | MacroDefKind::ProcMacro(_) => { | 212 | | MacroDefKind::ProcMacro(..) => { |
213 | let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); | 213 | let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate); |
214 | let val = diagnostic_sink.expand_result_option(res)?; | 214 | let val = diagnostic_sink.expand_result_option(res)?; |
215 | 215 | ||
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 87cad326d..20cda1683 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -145,7 +145,7 @@ fn make_hygiene_info( | |||
145 | ) -> Option<HygieneInfo> { | 145 | ) -> Option<HygieneInfo> { |
146 | let arg_tt = loc.kind.arg(db)?; | 146 | let arg_tt = loc.kind.arg(db)?; |
147 | 147 | ||
148 | let def_offset = loc.def.ast_id.and_then(|id| { | 148 | let def_offset = loc.def.ast_id().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(_) => return None, |
@@ -176,13 +176,13 @@ impl HygieneFrame { | |||
176 | let loc = db.lookup_intern_macro(id); | 176 | let loc = db.lookup_intern_macro(id); |
177 | let info = make_hygiene_info(db, macro_file, &loc); | 177 | let info = make_hygiene_info(db, macro_file, &loc); |
178 | match loc.def.kind { | 178 | match loc.def.kind { |
179 | MacroDefKind::Declarative => { | 179 | MacroDefKind::Declarative(_) => { |
180 | (info, Some(loc.def.krate), loc.def.local_inner) | 180 | (info, Some(loc.def.krate), loc.def.local_inner) |
181 | } | 181 | } |
182 | MacroDefKind::BuiltIn(_) => (info, Some(loc.def.krate), false), | 182 | MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false), |
183 | MacroDefKind::BuiltInDerive(_) => (info, None, false), | 183 | MacroDefKind::BuiltInDerive(..) => (info, None, false), |
184 | MacroDefKind::BuiltInEager(_) => (info, None, false), | 184 | MacroDefKind::BuiltInEager(..) => (info, None, false), |
185 | MacroDefKind::ProcMacro(_) => (info, None, false), | 185 | MacroDefKind::ProcMacro(..) => (info, None, false), |
186 | } | 186 | } |
187 | } | 187 | } |
188 | }, | 188 | }, |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 7532d00b8..0a379651f 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -143,7 +143,7 @@ impl HirFileId { | |||
143 | 143 | ||
144 | let arg_tt = loc.kind.arg(db)?; | 144 | let arg_tt = loc.kind.arg(db)?; |
145 | 145 | ||
146 | let def = loc.def.ast_id.and_then(|id| { | 146 | let def = loc.def.ast_id().and_then(|id| { |
147 | let def_tt = match id.to_node(db) { | 147 | let def_tt = match id.to_node(db) { |
148 | ast::Macro::MacroRules(mac) => mac.token_tree()?, | 148 | ast::Macro::MacroRules(mac) => mac.token_tree()?, |
149 | ast::Macro::MacroDef(_) => return None, | 149 | ast::Macro::MacroDef(_) => return None, |
@@ -180,7 +180,7 @@ impl HirFileId { | |||
180 | }; | 180 | }; |
181 | let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); | 181 | let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); |
182 | let item = match loc.def.kind { | 182 | let item = match loc.def.kind { |
183 | MacroDefKind::BuiltInDerive(_) => loc.kind.node(db), | 183 | MacroDefKind::BuiltInDerive(..) => loc.kind.node(db), |
184 | _ => return None, | 184 | _ => return None, |
185 | }; | 185 | }; |
186 | Some(item.with_value(ast::Item::cast(item.value.clone())?)) | 186 | Some(item.with_value(ast::Item::cast(item.value.clone())?)) |
@@ -224,7 +224,6 @@ impl From<EagerMacroId> for MacroCallId { | |||
224 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 224 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
225 | pub struct MacroDefId { | 225 | pub struct MacroDefId { |
226 | pub krate: CrateId, | 226 | pub krate: CrateId, |
227 | pub ast_id: Option<AstId<ast::Macro>>, | ||
228 | pub kind: MacroDefKind, | 227 | pub kind: MacroDefKind, |
229 | 228 | ||
230 | pub local_inner: bool, | 229 | pub local_inner: bool, |
@@ -239,16 +238,27 @@ impl MacroDefId { | |||
239 | ) -> LazyMacroId { | 238 | ) -> LazyMacroId { |
240 | db.intern_macro(MacroCallLoc { def: self, krate, kind }) | 239 | db.intern_macro(MacroCallLoc { def: self, krate, kind }) |
241 | } | 240 | } |
241 | |||
242 | pub fn ast_id(&self) -> Option<AstId<ast::Macro>> { | ||
243 | let id = match &self.kind { | ||
244 | MacroDefKind::Declarative(id) => id, | ||
245 | MacroDefKind::BuiltIn(_, id) => id, | ||
246 | MacroDefKind::BuiltInDerive(_, id) => id, | ||
247 | MacroDefKind::BuiltInEager(_, id) => id, | ||
248 | MacroDefKind::ProcMacro(..) => return None, | ||
249 | }; | ||
250 | Some(*id) | ||
251 | } | ||
242 | } | 252 | } |
243 | 253 | ||
244 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 254 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
245 | pub enum MacroDefKind { | 255 | pub enum MacroDefKind { |
246 | Declarative, | 256 | Declarative(AstId<ast::Macro>), |
247 | BuiltIn(BuiltinFnLikeExpander), | 257 | BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>), |
248 | // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander | 258 | // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander |
249 | BuiltInDerive(BuiltinDeriveExpander), | 259 | BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>), |
250 | BuiltInEager(EagerExpander), | 260 | BuiltInEager(EagerExpander, AstId<ast::Macro>), |
251 | ProcMacro(ProcMacroExpander), | 261 | ProcMacro(ProcMacroExpander, AstId<ast::Fn>), |
252 | } | 262 | } |
253 | 263 | ||
254 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 264 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index bfe239793..33a0f4d7d 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -102,7 +102,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
102 | let db = self.db; | 102 | let db = self.db; |
103 | for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) { | 103 | for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) { |
104 | for (_, module) in block_def_map.modules() { | 104 | for (_, module) in block_def_map.modules() { |
105 | for (def_id, _) in module.scope.values() { | 105 | for def_id in module.scope.declarations() { |
106 | let mut validator = DeclValidator::new(self.db, self.krate, self.sink); | 106 | let mut validator = DeclValidator::new(self.db, self.krate, self.sink); |
107 | validator.validate_item(def_id); | 107 | validator.validate_item(def_id); |
108 | } | 108 | } |
@@ -902,4 +902,17 @@ extern { | |||
902 | "#, | 902 | "#, |
903 | ); | 903 | ); |
904 | } | 904 | } |
905 | |||
906 | #[test] | ||
907 | fn infinite_loop_inner_items() { | ||
908 | check_diagnostics( | ||
909 | r#" | ||
910 | fn qualify() { | ||
911 | mod foo { | ||
912 | use super::*; | ||
913 | } | ||
914 | } | ||
915 | "#, | ||
916 | ) | ||
917 | } | ||
905 | } | 918 | } |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index af4f8bb11..c1e605740 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -232,6 +232,28 @@ fn expr_macro_expanded_in_stmts() { | |||
232 | } | 232 | } |
233 | 233 | ||
234 | #[test] | 234 | #[test] |
235 | fn recursive_inner_item_macro_rules() { | ||
236 | check_infer( | ||
237 | r#" | ||
238 | macro_rules! mac { | ||
239 | () => { mac!($)}; | ||
240 | ($x:tt) => { macro_rules! blub { () => { 1 }; } }; | ||
241 | } | ||
242 | fn foo() { | ||
243 | mac!(); | ||
244 | let a = blub!(); | ||
245 | } | ||
246 | "#, | ||
247 | expect![[r#" | ||
248 | !0..1 '1': i32 | ||
249 | !0..7 'mac!($)': {unknown} | ||
250 | 107..143 '{ ...!(); }': () | ||
251 | 129..130 'a': i32 | ||
252 | "#]], | ||
253 | ); | ||
254 | } | ||
255 | |||
256 | #[test] | ||
235 | fn infer_type_value_macro_having_same_name() { | 257 | fn infer_type_value_macro_having_same_name() { |
236 | check_infer( | 258 | check_infer( |
237 | r#" | 259 | r#" |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index c086de163..364be260c 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -339,10 +339,14 @@ impl TryToNav for hir::Field { | |||
339 | impl TryToNav for hir::MacroDef { | 339 | impl TryToNav for hir::MacroDef { |
340 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 340 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
341 | let src = self.source(db)?; | 341 | let src = self.source(db)?; |
342 | log::debug!("nav target {:#?}", src.value.syntax()); | 342 | let name_owner: &dyn ast::NameOwner = match &src.value { |
343 | Either::Left(it) => it, | ||
344 | Either::Right(it) => it, | ||
345 | }; | ||
346 | log::debug!("nav target {:#?}", name_owner.syntax()); | ||
343 | let mut res = NavigationTarget::from_named( | 347 | let mut res = NavigationTarget::from_named( |
344 | db, | 348 | db, |
345 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 349 | src.as_ref().with_value(name_owner), |
346 | SymbolKind::Macro, | 350 | SymbolKind::Macro, |
347 | ); | 351 | ); |
348 | res.docs = self.docs(db); | 352 | res.docs = self.docs(db); |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 598b47e41..473d48c2f 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -1176,4 +1176,21 @@ fn foo() { A { a$0: }; } | |||
1176 | "#, | 1176 | "#, |
1177 | ) | 1177 | ) |
1178 | } | 1178 | } |
1179 | |||
1180 | #[test] | ||
1181 | fn goto_proc_macro() { | ||
1182 | check( | ||
1183 | r#" | ||
1184 | //- /main.rs crate:main deps:mac | ||
1185 | use mac::fn_macro; | ||
1186 | |||
1187 | fn_macro$0!(); | ||
1188 | |||
1189 | //- /mac.rs crate:mac | ||
1190 | #[proc_macro] | ||
1191 | fn fn_macro() {} | ||
1192 | //^^^^^^^^ | ||
1193 | "#, | ||
1194 | ) | ||
1195 | } | ||
1179 | } | 1196 | } |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 15d309d7d..a3fb17c0a 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -331,10 +331,16 @@ fn hover_for_definition( | |||
331 | ) -> Option<Markup> { | 331 | ) -> Option<Markup> { |
332 | let mod_path = definition_mod_path(db, &def); | 332 | let mod_path = definition_mod_path(db, &def); |
333 | return match def { | 333 | return match def { |
334 | Definition::Macro(it) => { | 334 | Definition::Macro(it) => match &it.source(db)?.value { |
335 | let label = macro_label(&it.source(db)?.value); | 335 | Either::Left(mac) => { |
336 | from_def_source_labeled(db, it, Some(label), mod_path) | 336 | let label = macro_label(&mac); |
337 | } | 337 | from_def_source_labeled(db, it, Some(label), mod_path) |
338 | } | ||
339 | Either::Right(_) => { | ||
340 | // FIXME | ||
341 | None | ||
342 | } | ||
343 | }, | ||
338 | Definition::Field(def) => from_hir_fmt(db, def, mod_path), | 344 | Definition::Field(def) => from_hir_fmt(db, def, mod_path), |
339 | Definition::ModuleDef(it) => match it { | 345 | Definition::ModuleDef(it) => match it { |
340 | ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), | 346 | ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path), |
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index 3fa21ba7c..7578ad50b 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs | |||
@@ -91,7 +91,7 @@ impl<'a> MacroRender<'a> { | |||
91 | } | 91 | } |
92 | 92 | ||
93 | fn detail(&self) -> Option<String> { | 93 | fn detail(&self) -> Option<String> { |
94 | let ast_node = self.macro_.source(self.ctx.db())?.value; | 94 | let ast_node = self.macro_.source(self.ctx.db())?.value.left()?; |
95 | Some(macro_label(&ast_node)) | 95 | Some(macro_label(&ast_node)) |
96 | } | 96 | } |
97 | } | 97 | } |