aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/attr.rs6
-rw-r--r--crates/hir_def/src/nameres/collector.rs50
-rw-r--r--crates/hir_expand/src/proc_macro.rs39
3 files changed, 79 insertions, 16 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index dea552a60..a841b97bf 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -171,6 +171,9 @@ pub struct AttrQuery<'a> {
171} 171}
172 172
173impl<'a> AttrQuery<'a> { 173impl<'a> AttrQuery<'a> {
174 /// For an attribute like `#[attr(value)]`, returns the `(value)` subtree.
175 ///
176 /// If the attribute does not have a token tree argument, returns `None`.
174 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { 177 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
175 self.attrs().filter_map(|attr| match attr.input.as_ref()? { 178 self.attrs().filter_map(|attr| match attr.input.as_ref()? {
176 AttrInput::TokenTree(it) => Some(it), 179 AttrInput::TokenTree(it) => Some(it),
@@ -178,6 +181,9 @@ impl<'a> AttrQuery<'a> {
178 }) 181 })
179 } 182 }
180 183
184 /// For an attribute like `#[key = "value"]`, returns `"value"`.
185 ///
186 /// Returns `None` if the attribute does not have `key = "value"` form.
181 pub fn string_value(self) -> Option<&'a SmolStr> { 187 pub fn string_value(self) -> Option<&'a SmolStr> {
182 self.attrs().find_map(|attr| match attr.input.as_ref()? { 188 self.attrs().find_map(|attr| match attr.input.as_ref()? {
183 AttrInput::Literal(it) => Some(it), 189 AttrInput::Literal(it) => Some(it),
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 4c3993ff0..42c0f0536 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -16,10 +16,10 @@ use hir_expand::{
16 proc_macro::ProcMacroExpander, 16 proc_macro::ProcMacroExpander,
17 HirFileId, MacroCallId, MacroDefId, MacroDefKind, 17 HirFileId, MacroCallId, MacroDefId, MacroDefKind,
18}; 18};
19use rustc_hash::FxHashMap; 19use rustc_hash::{FxHashMap, FxHashSet};
20use rustc_hash::FxHashSet;
21use syntax::ast; 20use syntax::ast;
22use test_utils::mark; 21use test_utils::mark;
22use tt::{Leaf, TokenTree};
23 23
24use crate::{ 24use crate::{
25 attr::Attrs, 25 attr::Attrs,
@@ -281,6 +281,25 @@ impl DefCollector<'_> {
281 } 281 }
282 } 282 }
283 283
284 fn resolve_proc_macro(&mut self, name: &Name) {
285 let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) {
286 Some((_, expander)) => MacroDefId {
287 ast_id: None,
288 krate: Some(self.def_map.krate),
289 kind: MacroDefKind::ProcMacro(*expander),
290 local_inner: false,
291 },
292 None => MacroDefId {
293 ast_id: None,
294 krate: Some(self.def_map.krate),
295 kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)),
296 local_inner: false,
297 },
298 };
299
300 self.define_proc_macro(name.clone(), macro_def);
301 }
302
284 /// Define a macro with `macro_rules`. 303 /// Define a macro with `macro_rules`.
285 /// 304 ///
286 /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, 305 /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
@@ -917,6 +936,9 @@ impl ModCollector<'_, '_> {
917 } 936 }
918 ModItem::Function(id) => { 937 ModItem::Function(id) => {
919 let func = &self.item_tree[id]; 938 let func = &self.item_tree[id];
939
940 self.collect_proc_macro_def(&func.name, attrs);
941
920 def = Some(DefData { 942 def = Some(DefData {
921 id: FunctionLoc { 943 id: FunctionLoc {
922 container: container.into(), 944 container: container.into(),
@@ -1177,6 +1199,30 @@ impl ModCollector<'_, '_> {
1177 } 1199 }
1178 } 1200 }
1179 1201
1202 /// If `attrs` registers a procedural macro, collects its definition.
1203 fn collect_proc_macro_def(&mut self, func_name: &Name, attrs: &Attrs) {
1204 // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
1205 // FIXME: distinguish the type of macro
1206 let macro_name = if attrs.by_key("proc_macro").exists()
1207 || attrs.by_key("proc_macro_attribute").exists()
1208 {
1209 func_name.clone()
1210 } else {
1211 let derive = attrs.by_key("proc_macro_derive");
1212 if let Some(arg) = derive.tt_values().next() {
1213 if let [TokenTree::Leaf(Leaf::Ident(trait_name))] = &*arg.token_trees {
1214 trait_name.as_name()
1215 } else {
1216 return;
1217 }
1218 } else {
1219 return;
1220 }
1221 };
1222
1223 self.def_collector.resolve_proc_macro(&macro_name);
1224 }
1225
1180 fn collect_macro(&mut self, mac: &MacroCall) { 1226 fn collect_macro(&mut self, mac: &MacroCall) {
1181 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1227 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
1182 1228
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs
index 80255ea32..7505cb061 100644
--- a/crates/hir_expand/src/proc_macro.rs
+++ b/crates/hir_expand/src/proc_macro.rs
@@ -7,7 +7,7 @@ use tt::buffer::{Cursor, TokenBuffer};
7#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] 7#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
8pub struct ProcMacroExpander { 8pub struct ProcMacroExpander {
9 krate: CrateId, 9 krate: CrateId,
10 proc_macro_id: ProcMacroId, 10 proc_macro_id: Option<ProcMacroId>,
11} 11}
12 12
13macro_rules! err { 13macro_rules! err {
@@ -20,8 +20,14 @@ macro_rules! err {
20} 20}
21 21
22impl ProcMacroExpander { 22impl ProcMacroExpander {
23 pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander { 23 pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> Self {
24 ProcMacroExpander { krate, proc_macro_id } 24 Self { krate, proc_macro_id: Some(proc_macro_id) }
25 }
26
27 pub fn dummy(krate: CrateId) -> Self {
28 // FIXME: Should store the name for better errors
29 // FIXME: I think this is the second layer of "dummy" expansion, we should reduce that
30 Self { krate, proc_macro_id: None }
25 } 31 }
26 32
27 pub fn expand( 33 pub fn expand(
@@ -30,17 +36,22 @@ impl ProcMacroExpander {
30 _id: LazyMacroId, 36 _id: LazyMacroId,
31 tt: &tt::Subtree, 37 tt: &tt::Subtree,
32 ) -> Result<tt::Subtree, mbe::ExpandError> { 38 ) -> Result<tt::Subtree, mbe::ExpandError> {
33 let krate_graph = db.crate_graph(); 39 match self.proc_macro_id {
34 let proc_macro = krate_graph[self.krate] 40 Some(id) => {
35 .proc_macro 41 let krate_graph = db.crate_graph();
36 .get(self.proc_macro_id.0 as usize) 42 let proc_macro = krate_graph[self.krate]
37 .clone() 43 .proc_macro
38 .ok_or_else(|| err!("No derive macro found."))?; 44 .get(id.0 as usize)
39 45 .clone()
40 let tt = remove_derive_attrs(tt) 46 .ok_or_else(|| err!("No derive macro found."))?;
41 .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; 47
42 48 let tt = remove_derive_attrs(tt)
43 proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) 49 .ok_or_else(|| err!("Fail to remove derive for custom derive"))?;
50
51 proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
52 }
53 None => Err(err!("Unresolved proc macro")),
54 }
44 } 55 }
45} 56}
46 57