diff options
author | Jonas Schievink <[email protected]> | 2020-09-18 15:43:50 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-09-18 15:43:50 +0100 |
commit | 5486b70bc0fa1b6260178fa7e547a534d91c3e04 (patch) | |
tree | ac4a36773afb0e7f33e9e6abdecd07c0216557f5 /crates | |
parent | dfa3a3f017c39f745f06d96de11359b97c76fc47 (diff) |
Use hir_def to resolve proc macros
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_def/src/attr.rs | 6 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 50 | ||||
-rw-r--r-- | crates/hir_expand/src/proc_macro.rs | 39 |
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 | ||
173 | impl<'a> AttrQuery<'a> { | 173 | impl<'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 | }; |
19 | use rustc_hash::FxHashMap; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | use rustc_hash::FxHashSet; | ||
21 | use syntax::ast; | 20 | use syntax::ast; |
22 | use test_utils::mark; | 21 | use test_utils::mark; |
22 | use tt::{Leaf, TokenTree}; | ||
23 | 23 | ||
24 | use crate::{ | 24 | use 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(¯o_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)] |
8 | pub struct ProcMacroExpander { | 8 | pub struct ProcMacroExpander { |
9 | krate: CrateId, | 9 | krate: CrateId, |
10 | proc_macro_id: ProcMacroId, | 10 | proc_macro_id: Option<ProcMacroId>, |
11 | } | 11 | } |
12 | 12 | ||
13 | macro_rules! err { | 13 | macro_rules! err { |
@@ -20,8 +20,14 @@ macro_rules! err { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | impl ProcMacroExpander { | 22 | impl 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 | ||