let token = successors(Some(InFile::new(sa.file_id, token)), |token| {
self.db.unwind_if_cancelled();
- let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
- let tt = macro_call.token_tree()?;
- if !tt.syntax().text_range().contains_range(token.value.text_range()) {
- return None;
- }
- let file_id = sa.expand(self.db, token.with_value(¯o_call))?;
- let token = self
- .expansion_info_cache
- .borrow_mut()
- .entry(file_id)
- .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
- .as_ref()?
- .map_token_down(token.as_ref())?;
-
- if let Some(parent) = token.value.parent() {
- self.cache(find_root(&parent), token.file_id);
+
+ for node in token.value.ancestors() {
+ match_ast! {
+ match node {
+ ast::MacroCall(macro_call) => {
+ let tt = macro_call.token_tree()?;
+ if !tt.syntax().text_range().contains_range(token.value.text_range()) {
+ return None;
+ }
+ let file_id = sa.expand(self.db, token.with_value(¯o_call))?;
+ let token = self
+ .expansion_info_cache
+ .borrow_mut()
+ .entry(file_id)
+ .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
+ .as_ref()?
+ .map_token_down(token.as_ref())?;
+
+ if let Some(parent) = token.value.parent() {
+ self.cache(find_root(&parent), token.file_id);
+ }
+
+ return Some(token);
+ },
+ ast::Item(item) => {
+ match self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item))) {
+ Some(call_id) => {
+ let file_id = call_id.as_file();
+ let token = self
+ .expansion_info_cache
+ .borrow_mut()
+ .entry(file_id)
+ .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
+ .as_ref()?
+ .map_token_down(token.as_ref())?;
+
+ if let Some(parent) = token.value.parent() {
+ self.cache(find_root(&parent), token.file_id);
+ }
+
+ return Some(token);
+ }
+ None => {}
+ }
+ },
+ _ => {}
+ }
+ }
}
- Some(token)
+ None
})
.last()
.unwrap();
ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
UnionId, VariantId,
};
-use hir_expand::{name::AsName, AstId, MacroDefKind};
+use hir_expand::{name::AsName, AstId, MacroCallId, MacroDefKind};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
use stdx::impl_from;
Some((container, label_id))
}
+ pub(super) fn item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId> {
+ let map = self.dyn_map(src.as_ref())?;
+ map[keys::ATTR_MACRO].get(&src).copied()
+ }
+
fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
&mut self,
src: InFile<Ast>,
key: Key<Ast, ID>,
) -> Option<ID> {
- let container = self.find_container(src.as_ref().map(|it| it.syntax()))?;
+ self.dyn_map(src.as_ref())?[key].get(&src).copied()
+ }
+
+ fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> {
+ let container = self.find_container(src.map(|it| it.syntax()))?;
let db = self.db;
let dyn_map =
&*self.cache.entry(container).or_insert_with(|| container.child_by_source(db));
- dyn_map[key].get(&src).copied()
+ Some(dyn_map)
}
pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
res[keys::CONST].insert(src, konst);
});
self.impls().for_each(|imp| add_impl(db, res, imp));
+ self.attr_macro_invocs().for_each(|(ast_id, call_id)| {
+ let item = ast_id.with_value(ast_id.to_node(db.upcast()));
+ res[keys::ATTR_MACRO].insert(item, call_id);
+ });
fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
match item {
use std::collections::hash_map::Entry;
use base_db::CrateId;
-use hir_expand::name::Name;
-use hir_expand::MacroDefKind;
+use hir_expand::{name::Name, AstId, MacroCallId, MacroDefKind};
use once_cell::sync::Lazy;
use rustc_hash::{FxHashMap, FxHashSet};
use stdx::format_to;
+use syntax::ast;
use crate::{
db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId,
// FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
// be all resolved to the last one defined if shadowing happens.
legacy_macros: FxHashMap<Name, MacroDefId>,
+ attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
}
pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
self.legacy_macros.insert(name, mac);
}
+ pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) {
+ self.attr_macros.insert(item, call);
+ }
+
+ pub(crate) fn attr_macro_invocs(
+ &self,
+ ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
+ self.attr_macros.iter().map(|(k, v)| (*k, *v))
+ }
+
pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
self.unnamed_trait_imports.get(&tr).copied()
}
unnamed_consts,
unnamed_trait_imports,
legacy_macros,
+ attr_macros,
} = self;
types.shrink_to_fit();
values.shrink_to_fit();
unnamed_consts.shrink_to_fit();
unnamed_trait_imports.shrink_to_fit();
legacy_macros.shrink_to_fit();
+ attr_macros.shrink_to_fit();
}
}
use std::marker::PhantomData;
-use hir_expand::{InFile, MacroDefId};
+use hir_expand::{InFile, MacroCallId, MacroDefId};
use rustc_hash::FxHashMap;
use syntax::{ast, AstNode, AstPtr};
pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();
+pub const ATTR_MACRO: Key<ast::Item, MacroCallId> = Key::new();
/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
/// equal if they point to exactly the same object.
return false;
}
}
+
+ self.def_map.modules[directive.module_id]
+ .scope
+ .add_attr_macro_invoc(ast_id.ast_id, call_id);
+
resolved.push((directive.module_id, call_id, directive.depth));
res = ReachedFixedPoint::No;
return false;