Treat Derive Macro specially.

This commit is contained in:
Wyatt Herkamp 2024-03-18 07:10:02 -04:00
parent 4bd2f948bb
commit 2c2bbe07fd
6 changed files with 87 additions and 40 deletions

View file

@ -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<ast::Adt>,
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<ast::Item>,

View file

@ -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;
@ -1258,9 +1259,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(
@ -1289,8 +1288,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;
@ -1338,7 +1345,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!(

View file

@ -180,7 +180,7 @@ pub(crate) fn process_cfg_attrs(
db: &dyn ExpandDatabase,
) -> Option<FxHashSet<SyntaxElement>> {
// 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();

View file

@ -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<tt::Subtree>, 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<(tt::Subtree, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
) -> 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<ast::Fn>) -> Span {
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
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),

View file

@ -228,6 +228,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<ast::Adt>,
invoc_attr_index: AttrId,
},
Attr {
ast_id: AstId<ast::Item>,
// FIXME: This shouldn't be here, we can derive this from `invoc_attr_index`
@ -515,7 +519,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)
@ -549,7 +554,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)
@ -583,6 +588,7 @@ impl MacroCallKind {
MacroCallKind::FnLike { .. } => "macro call",
MacroCallKind::Derive { .. } => "derive macro",
MacroCallKind::Attr { .. } => "attribute macro",
MacroCallKind::DeriveAttr { .. } => "derive attribute",
}
}
@ -591,6 +597,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,
}
}
@ -598,7 +605,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(),
}
}
@ -619,7 +627,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(),
};
@ -665,6 +675,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 }
@ -675,7 +694,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, .. } => {

View file

@ -972,8 +972,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.
@ -1023,6 +1022,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,
)
}
}
}
@ -3710,8 +3729,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]