diff options
author | Jonas Schievink <[email protected]> | 2021-05-31 12:37:11 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2021-06-03 17:09:21 +0100 |
commit | e5a2c6596ddd11b0d57042224ac7c1d7691ec33b (patch) | |
tree | f0476ad40103b5d3dea60f81fca32c63fe9618d7 /crates/hir_expand | |
parent | 7f9c4a59d9a84cd8c734286937439b5cd215be27 (diff) |
Expand procedural attribute macros
Diffstat (limited to 'crates/hir_expand')
-rw-r--r-- | crates/hir_expand/src/db.rs | 11 | ||||
-rw-r--r-- | crates/hir_expand/src/input.rs | 19 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 24 | ||||
-rw-r--r-- | crates/hir_expand/src/proc_macro.rs | 7 |
4 files changed, 54 insertions, 7 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index e8f4af309..3ebe194e4 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -13,8 +13,8 @@ use syntax::{ | |||
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, | 15 | ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, |
16 | BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId, | 16 | BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, |
17 | MacroDefKind, MacroFile, ProcMacroExpander, | 17 | MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | /// Total limit on the number of tokens produced by any macro invocation. | 20 | /// Total limit on the number of tokens produced by any macro invocation. |
@@ -377,7 +377,12 @@ fn expand_proc_macro( | |||
377 | _ => unreachable!(), | 377 | _ => unreachable!(), |
378 | }; | 378 | }; |
379 | 379 | ||
380 | expander.expand(db, loc.krate, ¯o_arg.0) | 380 | let attr_arg = match &loc.kind { |
381 | MacroCallKind::Attr { attr_args, .. } => Some(attr_args), | ||
382 | _ => None, | ||
383 | }; | ||
384 | |||
385 | expander.expand(db, loc.krate, ¯o_arg.0, attr_arg) | ||
381 | } | 386 | } |
382 | 387 | ||
383 | fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { | 388 | fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { |
diff --git a/crates/hir_expand/src/input.rs b/crates/hir_expand/src/input.rs index fe4790e7b..40116a479 100644 --- a/crates/hir_expand/src/input.rs +++ b/crates/hir_expand/src/input.rs | |||
@@ -28,6 +28,14 @@ pub(crate) fn process_macro_input( | |||
28 | 28 | ||
29 | remove_derives_up_to(item, derive_attr_index as usize).syntax().clone() | 29 | remove_derives_up_to(item, derive_attr_index as usize).syntax().clone() |
30 | } | 30 | } |
31 | MacroCallKind::Attr { invoc_attr_index, .. } => { | ||
32 | let item = match ast::Item::cast(node.clone()) { | ||
33 | Some(item) => item, | ||
34 | None => return node, | ||
35 | }; | ||
36 | |||
37 | remove_attr_invoc(item, invoc_attr_index as usize).syntax().clone() | ||
38 | } | ||
31 | } | 39 | } |
32 | } | 40 | } |
33 | 41 | ||
@@ -46,6 +54,17 @@ fn remove_derives_up_to(item: ast::Item, attr_index: usize) -> ast::Item { | |||
46 | item | 54 | item |
47 | } | 55 | } |
48 | 56 | ||
57 | /// Removes the attribute invoking an attribute macro from `item`. | ||
58 | fn remove_attr_invoc(item: ast::Item, attr_index: usize) -> ast::Item { | ||
59 | let item = item.clone_for_update(); | ||
60 | let attr = item | ||
61 | .attrs() | ||
62 | .nth(attr_index) | ||
63 | .unwrap_or_else(|| panic!("cannot find attribute #{}", attr_index)); | ||
64 | attr.syntax().detach(); | ||
65 | item | ||
66 | } | ||
67 | |||
49 | #[cfg(test)] | 68 | #[cfg(test)] |
50 | mod tests { | 69 | mod tests { |
51 | use base_db::fixture::WithFixture; | 70 | use base_db::fixture::WithFixture; |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 90d8ae240..618f26b95 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -258,14 +258,29 @@ pub enum MacroCallKind { | |||
258 | /// out-of-line modules, which may have attributes spread across 2 files! | 258 | /// out-of-line modules, which may have attributes spread across 2 files! |
259 | derive_attr_index: u32, | 259 | derive_attr_index: u32, |
260 | }, | 260 | }, |
261 | Attr { | ||
262 | ast_id: AstId<ast::Item>, | ||
263 | attr_name: String, | ||
264 | attr_args: tt::Subtree, | ||
265 | /// Syntactical index of the invoking `#[attribute]`. | ||
266 | /// | ||
267 | /// Outer attributes are counted first, then inner attributes. This does not support | ||
268 | /// out-of-line modules, which may have attributes spread across 2 files! | ||
269 | invoc_attr_index: u32, | ||
270 | }, | ||
261 | } | 271 | } |
262 | 272 | ||
273 | // FIXME: attribute indices do not account for `cfg_attr`, which means that we'll strip the whole | ||
274 | // `cfg_attr` instead of just one of the attributes it expands to | ||
275 | |||
263 | impl MacroCallKind { | 276 | impl MacroCallKind { |
264 | /// Returns the file containing the macro invocation. | 277 | /// Returns the file containing the macro invocation. |
265 | fn file_id(&self) -> HirFileId { | 278 | fn file_id(&self) -> HirFileId { |
266 | match self { | 279 | match self { |
267 | MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id, | 280 | MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id, |
268 | MacroCallKind::Derive { ast_id, .. } => ast_id.file_id, | 281 | MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => { |
282 | ast_id.file_id | ||
283 | } | ||
269 | } | 284 | } |
270 | } | 285 | } |
271 | 286 | ||
@@ -274,7 +289,7 @@ impl MacroCallKind { | |||
274 | MacroCallKind::FnLike { ast_id, .. } => { | 289 | MacroCallKind::FnLike { ast_id, .. } => { |
275 | ast_id.with_value(ast_id.to_node(db).syntax().clone()) | 290 | ast_id.with_value(ast_id.to_node(db).syntax().clone()) |
276 | } | 291 | } |
277 | MacroCallKind::Derive { ast_id, .. } => { | 292 | MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => { |
278 | ast_id.with_value(ast_id.to_node(db).syntax().clone()) | 293 | ast_id.with_value(ast_id.to_node(db).syntax().clone()) |
279 | } | 294 | } |
280 | } | 295 | } |
@@ -285,7 +300,9 @@ impl MacroCallKind { | |||
285 | MacroCallKind::FnLike { ast_id, .. } => { | 300 | MacroCallKind::FnLike { ast_id, .. } => { |
286 | Some(ast_id.to_node(db).token_tree()?.syntax().clone()) | 301 | Some(ast_id.to_node(db).token_tree()?.syntax().clone()) |
287 | } | 302 | } |
288 | MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), | 303 | MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => { |
304 | Some(ast_id.to_node(db).syntax().clone()) | ||
305 | } | ||
289 | } | 306 | } |
290 | } | 307 | } |
291 | 308 | ||
@@ -293,6 +310,7 @@ impl MacroCallKind { | |||
293 | match self { | 310 | match self { |
294 | MacroCallKind::FnLike { fragment, .. } => *fragment, | 311 | MacroCallKind::FnLike { fragment, .. } => *fragment, |
295 | MacroCallKind::Derive { .. } => FragmentKind::Items, | 312 | MacroCallKind::Derive { .. } => FragmentKind::Items, |
313 | MacroCallKind::Attr { .. } => FragmentKind::Items, // is this always correct? | ||
296 | } | 314 | } |
297 | } | 315 | } |
298 | } | 316 | } |
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index d5643393a..dbe1b446e 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -28,11 +28,16 @@ impl ProcMacroExpander { | |||
28 | Self { krate, proc_macro_id: None } | 28 | Self { krate, proc_macro_id: None } |
29 | } | 29 | } |
30 | 30 | ||
31 | pub fn is_dummy(&self) -> bool { | ||
32 | self.proc_macro_id.is_none() | ||
33 | } | ||
34 | |||
31 | pub fn expand( | 35 | pub fn expand( |
32 | self, | 36 | self, |
33 | db: &dyn AstDatabase, | 37 | db: &dyn AstDatabase, |
34 | calling_crate: CrateId, | 38 | calling_crate: CrateId, |
35 | tt: &tt::Subtree, | 39 | tt: &tt::Subtree, |
40 | attr_arg: Option<&tt::Subtree>, | ||
36 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 41 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
37 | match self.proc_macro_id { | 42 | match self.proc_macro_id { |
38 | Some(id) => { | 43 | Some(id) => { |
@@ -46,7 +51,7 @@ impl ProcMacroExpander { | |||
46 | // Proc macros have access to the environment variables of the invoking crate. | 51 | // Proc macros have access to the environment variables of the invoking crate. |
47 | let env = &krate_graph[calling_crate].env; | 52 | let env = &krate_graph[calling_crate].env; |
48 | 53 | ||
49 | proc_macro.expander.expand(&tt, None, &env).map_err(mbe::ExpandError::from) | 54 | proc_macro.expander.expand(&tt, attr_arg, &env).map_err(mbe::ExpandError::from) |
50 | } | 55 | } |
51 | None => Err(mbe::ExpandError::UnresolvedProcMacro), | 56 | None => Err(mbe::ExpandError::UnresolvedProcMacro), |
52 | } | 57 | } |