From e5a2c6596ddd11b0d57042224ac7c1d7691ec33b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 31 May 2021 13:37:11 +0200 Subject: Expand procedural attribute macros --- crates/hir_expand/src/db.rs | 11 ++++++++--- crates/hir_expand/src/input.rs | 19 +++++++++++++++++++ crates/hir_expand/src/lib.rs | 24 +++++++++++++++++++++--- crates/hir_expand/src/proc_macro.rs | 7 ++++++- 4 files changed, 54 insertions(+), 7 deletions(-) (limited to 'crates/hir_expand') 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::{ use crate::{ ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, - BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, MacroDefId, - MacroDefKind, MacroFile, ProcMacroExpander, + BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, + MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -377,7 +377,12 @@ fn expand_proc_macro( _ => unreachable!(), }; - expander.expand(db, loc.krate, ¯o_arg.0) + let attr_arg = match &loc.kind { + MacroCallKind::Attr { attr_args, .. } => Some(attr_args), + _ => None, + }; + + expander.expand(db, loc.krate, ¯o_arg.0, attr_arg) } 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( remove_derives_up_to(item, derive_attr_index as usize).syntax().clone() } + MacroCallKind::Attr { invoc_attr_index, .. } => { + let item = match ast::Item::cast(node.clone()) { + Some(item) => item, + None => return node, + }; + + remove_attr_invoc(item, invoc_attr_index as usize).syntax().clone() + } } } @@ -46,6 +54,17 @@ fn remove_derives_up_to(item: ast::Item, attr_index: usize) -> ast::Item { item } +/// Removes the attribute invoking an attribute macro from `item`. +fn remove_attr_invoc(item: ast::Item, attr_index: usize) -> ast::Item { + let item = item.clone_for_update(); + let attr = item + .attrs() + .nth(attr_index) + .unwrap_or_else(|| panic!("cannot find attribute #{}", attr_index)); + attr.syntax().detach(); + item +} + #[cfg(test)] mod tests { 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 { /// out-of-line modules, which may have attributes spread across 2 files! derive_attr_index: u32, }, + Attr { + ast_id: AstId, + attr_name: String, + attr_args: tt::Subtree, + /// Syntactical index of the invoking `#[attribute]`. + /// + /// Outer attributes are counted first, then inner attributes. This does not support + /// out-of-line modules, which may have attributes spread across 2 files! + invoc_attr_index: u32, + }, } +// FIXME: attribute indices do not account for `cfg_attr`, which means that we'll strip the whole +// `cfg_attr` instead of just one of the attributes it expands to + impl MacroCallKind { /// Returns the file containing the macro invocation. fn file_id(&self) -> HirFileId { match self { MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id, - MacroCallKind::Derive { ast_id, .. } => ast_id.file_id, + MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => { + ast_id.file_id + } } } @@ -274,7 +289,7 @@ impl MacroCallKind { MacroCallKind::FnLike { ast_id, .. } => { ast_id.with_value(ast_id.to_node(db).syntax().clone()) } - MacroCallKind::Derive { ast_id, .. } => { + MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => { ast_id.with_value(ast_id.to_node(db).syntax().clone()) } } @@ -285,7 +300,9 @@ impl MacroCallKind { MacroCallKind::FnLike { ast_id, .. } => { Some(ast_id.to_node(db).token_tree()?.syntax().clone()) } - MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), + MacroCallKind::Derive { ast_id, .. } | MacroCallKind::Attr { ast_id, .. } => { + Some(ast_id.to_node(db).syntax().clone()) + } } } @@ -293,6 +310,7 @@ impl MacroCallKind { match self { MacroCallKind::FnLike { fragment, .. } => *fragment, MacroCallKind::Derive { .. } => FragmentKind::Items, + MacroCallKind::Attr { .. } => FragmentKind::Items, // is this always correct? } } } 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 { Self { krate, proc_macro_id: None } } + pub fn is_dummy(&self) -> bool { + self.proc_macro_id.is_none() + } + pub fn expand( self, db: &dyn AstDatabase, calling_crate: CrateId, tt: &tt::Subtree, + attr_arg: Option<&tt::Subtree>, ) -> Result { match self.proc_macro_id { Some(id) => { @@ -46,7 +51,7 @@ impl ProcMacroExpander { // Proc macros have access to the environment variables of the invoking crate. let env = &krate_graph[calling_crate].env; - proc_macro.expander.expand(&tt, None, &env).map_err(mbe::ExpandError::from) + proc_macro.expander.expand(&tt, attr_arg, &env).map_err(mbe::ExpandError::from) } None => Err(mbe::ExpandError::UnresolvedProcMacro), } -- cgit v1.2.3