diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs index eb7f4c05ae21..e2d83c8e3bfe 100644 --- a/crates/hir-def/src/nameres/attr_resolution.rs +++ b/crates/hir-def/src/nameres/attr_resolution.rs @@ -3,7 +3,7 @@ use base_db::CrateId; use hir_expand::{ attrs::{Attr, AttrId, AttrInput}, - MacroCallId, MacroCallKind, MacroDefId, + AstId, MacroCallId, MacroCallKind, MacroDefId, }; use span::SyntaxContextId; use syntax::{ast, SmolStr}; @@ -98,7 +98,20 @@ impl DefMap { false } } - +pub(super) fn derive_attr_macro_as_call_id( + db: &dyn DefDatabase, + item_attr: &AstId, + macro_attr: &Attr, + krate: CrateId, + def: MacroDefId, +) -> MacroCallId { + def.make_call( + db.upcast(), + krate, + MacroCallKind::DeriveAttr { ast_id: *item_attr, invoc_attr_index: macro_attr.id }, + macro_attr.ctxt, + ) +} pub(super) fn attr_macro_as_call_id( db: &dyn DefDatabase, item_attr: &AstIdWithPath, diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index ab7a49e6ee3d..ca4d1ba84699 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -14,6 +14,7 @@ use crate::item_tree::Mod; use crate::item_tree::ModKind; use crate::macro_call_as_call_id_with_eager; +use crate::nameres::attr_resolution::derive_attr_macro_as_call_id; use crate::nameres::mod_resolution::ModDir; use crate::item_tree::ItemTree; @@ -1261,9 +1262,7 @@ impl DefCollector<'_> { Some(def) if def.is_attribute() => def, _ => return Resolved::No, }; - // We will treat derive macros as an attribute as a reference for the input to derives - let call_id = - attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def); + if let MacroDefId { kind: MacroDefKind::BuiltInAttr( @@ -1292,8 +1291,16 @@ impl DefCollector<'_> { return recollect_without(self); } }; - let ast_id = ast_id.with_value(ast_adt_id); + let ast_id = ast_id.with_value(ast_adt_id); + // the call_id for the actual derive macro. This is used so all the derive proc macros can share a token tree + let call_id = derive_attr_macro_as_call_id( + self.db, + &ast_id, + attr, + self.def_map.krate, + def, + ); match attr.parse_path_comma_token_tree(self.db.upcast()) { Some(derive_macros) => { let mut len = 0; @@ -1341,7 +1348,8 @@ impl DefCollector<'_> { return recollect_without(self); } - + let call_id = + attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def); // Skip #[test]/#[bench] expansion, which would merely result in more memory usage // due to duplicating functions into macro expansions if matches!( diff --git a/crates/hir-expand/src/cfg_process.rs b/crates/hir-expand/src/cfg_process.rs index c74c13a6fd3c..060b132c1e0b 100644 --- a/crates/hir-expand/src/cfg_process.rs +++ b/crates/hir-expand/src/cfg_process.rs @@ -180,7 +180,7 @@ pub(crate) fn process_cfg_attrs( db: &dyn ExpandDatabase, ) -> Option> { // FIXME: #[cfg_eval] is not implemented. But it is not stable yet - if !matches!(loc.kind, MacroCallKind::Derive { .. }) { + if !matches!(loc.kind, MacroCallKind::Derive { .. } | MacroCallKind::DeriveAttr { .. }) { return None; } let mut remove = FxHashSet::default(); diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 004c4473011f..277c268086bc 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -7,7 +7,6 @@ use mbe::syntax_node_to_token_tree; use rustc_hash::FxHashSet; use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId}; use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T}; -use tracing::debug; use triomphe::Arc; use crate::{ @@ -158,7 +157,8 @@ pub fn expand_speculative( SyntaxFixupUndoInfo::NONE, ), MacroCallKind::Derive { derive_attr_index: index, .. } - | MacroCallKind::Attr { invoc_attr_index: index, .. } => { + | MacroCallKind::Attr { invoc_attr_index: index, .. } + | MacroCallKind::DeriveAttr { invoc_attr_index: index, .. } => { let censor = if let MacroCallKind::Derive { .. } = loc.kind { censor_derive_input(index, &ast::Adt::cast(speculative_args.clone())?) } else { @@ -347,31 +347,18 @@ type MacroArgResult = (Arc, SyntaxFixupUndoInfo, Span); /// Other wise return the [macro_arg] for the macro_call_id. /// /// This is not connected to the database so it does not cached the result. However, the inner [macro_arg] query is -/// -/// FIXME: Pick a better name -fn smart_macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { - let loc = db.lookup_intern_macro_call(id); +fn macro_arg_considering_derives(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { + let macro_call_kind = db.lookup_intern_macro_call(id).kind; // FIXME: We called lookup_intern_macro_call twice. - match loc.kind { + match macro_call_kind { // Get the macro arg for the derive macro - MacroCallKind::Derive { derive_macro_id, .. } => { - debug!( - ?loc, - "{id:?} is a derive macro. Using the derive macro, id: {derive_macro_id:?}, attribute as the macro arg." - ); - db.macro_arg(derive_macro_id) - } + MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(derive_macro_id), // Normal macro arg _ => db.macro_arg(id), } } -fn macro_arg( - db: &dyn ExpandDatabase, - id: MacroCallId, - // FIXME: consider the following by putting fixup info into eager call info args - // ) -> ValueResult, Arc>> { -) -> MacroArgResult { +fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { let loc = db.lookup_intern_macro_call(id); if let MacroCallLoc { @@ -441,7 +428,9 @@ fn macro_arg( } return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span); } - MacroCallKind::Derive { ast_id, derive_attr_index, .. } => { + // MacroCallKind::Derive should not be here. As we are getting the argument for the derive macro + MacroCallKind::Derive { ast_id, derive_attr_index, .. } + | MacroCallKind::DeriveAttr { ast_id, invoc_attr_index: derive_attr_index } => { let node = ast_id.to_ptr(db).to_node(&root); let censor_derive_input = censor_derive_input(derive_attr_index, &node); let item_node = node.into(); @@ -553,7 +542,7 @@ fn macro_expand( let (ExpandResult { value: tt, err }, span) = match loc.def.kind { MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc), _ => { - let (macro_arg, undo_info, span) = smart_macro_arg(db, macro_call_id); + let (macro_arg, undo_info, span) = macro_arg_considering_derives(db, macro_call_id); let arg = &*macro_arg; let res = @@ -630,7 +619,7 @@ fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId) -> Span { fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult> { let loc = db.lookup_intern_macro_call(id); - let (macro_arg, undo_info, span) = smart_macro_arg(db, id); + let (macro_arg, undo_info, span) = macro_arg_considering_derives(db, id); let (expander, ast) = match loc.def.kind { MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast), diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 5d00d2f24e5c..696c0f5dc2f7 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -229,6 +229,10 @@ pub enum MacroCallKind { /// We will resolve the same token tree for all derive macros in the same derive attribute. derive_macro_id: MacroCallId, }, + DeriveAttr { + ast_id: AstId, + invoc_attr_index: AttrId, + }, Attr { ast_id: AstId, // FIXME: This shouldn't be here, we can derive this from `invoc_attr_index` @@ -516,7 +520,8 @@ impl MacroCallLoc { MacroCallKind::FnLike { ast_id, .. } => { ast_id.with_value(ast_id.to_node(db).syntax().clone()) } - MacroCallKind::Derive { ast_id, derive_attr_index, .. } => { + MacroCallKind::Derive { ast_id, derive_attr_index, .. } + | MacroCallKind::DeriveAttr { ast_id, invoc_attr_index: derive_attr_index } => { // FIXME: handle `cfg_attr` ast_id.with_value(ast_id.to_node(db)).map(|it| { collect_attrs(&it) @@ -550,7 +555,7 @@ impl MacroCallLoc { fn expand_to(&self) -> ExpandTo { match self.kind { MacroCallKind::FnLike { expand_to, .. } => expand_to, - MacroCallKind::Derive { .. } => ExpandTo::Items, + MacroCallKind::Derive { .. } | MacroCallKind::DeriveAttr { .. } => ExpandTo::Items, MacroCallKind::Attr { .. } if self.def.is_attribute_derive() => ExpandTo::Items, MacroCallKind::Attr { .. } => { // FIXME(stmt_expr_attributes) @@ -584,6 +589,7 @@ impl MacroCallKind { MacroCallKind::FnLike { .. } => "macro call", MacroCallKind::Derive { .. } => "derive macro", MacroCallKind::Attr { .. } => "attribute macro", + MacroCallKind::DeriveAttr { .. } => "derive attribute", } } @@ -592,6 +598,7 @@ impl MacroCallKind { match *self { MacroCallKind::FnLike { ast_id: InFile { file_id, .. }, .. } | MacroCallKind::Derive { ast_id: InFile { file_id, .. }, .. } + | MacroCallKind::DeriveAttr { ast_id: InFile { file_id, .. }, .. } | MacroCallKind::Attr { ast_id: InFile { file_id, .. }, .. } => file_id, } } @@ -599,7 +606,8 @@ impl MacroCallKind { pub fn erased_ast_id(&self) -> ErasedFileAstId { match *self { MacroCallKind::FnLike { ast_id: InFile { value, .. }, .. } => value.erase(), - MacroCallKind::Derive { ast_id: InFile { value, .. }, .. } => value.erase(), + MacroCallKind::Derive { ast_id: InFile { value, .. }, .. } + | MacroCallKind::DeriveAttr { ast_id: InFile { value, .. }, .. } => value.erase(), MacroCallKind::Attr { ast_id: InFile { value, .. }, .. } => value.erase(), } } @@ -620,7 +628,9 @@ impl MacroCallKind { let range = match kind { MacroCallKind::FnLike { ast_id, .. } => ast_id.to_ptr(db).text_range(), - MacroCallKind::Derive { ast_id, .. } => ast_id.to_ptr(db).text_range(), + MacroCallKind::Derive { ast_id, .. } | MacroCallKind::DeriveAttr { ast_id, .. } => { + ast_id.to_ptr(db).text_range() + } MacroCallKind::Attr { ast_id, .. } => ast_id.to_ptr(db).text_range(), }; @@ -666,6 +676,15 @@ impl MacroCallKind { .syntax() .text_range() } + MacroCallKind::DeriveAttr { ast_id, invoc_attr_index } => { + collect_attrs(&ast_id.to_node(db)) + .nth(invoc_attr_index.ast_index()) + .expect("missing attribute") + .1 + .expect_left("attribute macro is a doc comment?") + .syntax() + .text_range() + } }; FileRange { range, file_id } @@ -676,7 +695,7 @@ impl MacroCallKind { MacroCallKind::FnLike { ast_id, .. } => { ast_id.to_in_file_node(db).map(|it| Some(it.token_tree()?.syntax().clone())) } - MacroCallKind::Derive { ast_id, .. } => { + MacroCallKind::Derive { ast_id, .. } | MacroCallKind::DeriveAttr { ast_id, .. } => { ast_id.to_in_file_node(db).syntax().cloned().map(Some) } MacroCallKind::Attr { ast_id, .. } => { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index e43109f591f5..1612992677d3 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -971,8 +971,7 @@ fn precise_macro_call_location( MacroKind::ProcMacro, ) } - // TODO: derive_macro_id - MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, derive_macro_id } => { + MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => { let node = ast_id.to_node(db.upcast()); // Compute the precise location of the macro name's token in the derive // list. @@ -1022,6 +1021,26 @@ fn precise_macro_call_location( MacroKind::Attr, ) } + MacroCallKind::DeriveAttr { ast_id, invoc_attr_index } => { + let node = ast_id.to_node(db.upcast()); + let attr = collect_attrs(&node) + .nth(invoc_attr_index.ast_index()) + .and_then(|x| Either::left(x.1)) + .unwrap_or_else(|| { + panic!("cannot find attribute #{}", invoc_attr_index.ast_index()) + }); + + ( + ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), + Some(attr.syntax().text_range()), + attr.path() + .and_then(|path| path.segment()) + .and_then(|seg| seg.name_ref()) + .as_ref() + .map(ToString::to_string), + MacroKind::Attr, + ) + } } } @@ -3684,8 +3703,7 @@ impl Impl { let macro_file = src.file_id.macro_file()?; let loc = macro_file.macro_call_id.lookup(db.upcast()); let (derive_attr, derive_index) = match loc.kind { - // TODO: derive_macro_id - MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, derive_macro_id } => { + MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => { let module_id = self.id.lookup(db.upcast()).container; ( db.crate_def_map(module_id.krate())[module_id.local_id]