1 //! Post-nameres attribute resolution.
3 use hir_expand::MacroCallId;
4 use syntax::{ast, SmolStr};
8 attr_macro_as_call_id, builtin_attr,
10 item_scope::BuiltinShadowMode,
11 nameres::path_resolution::ResolveMode,
12 path::{ModPath, PathKind},
13 AstIdWithPath, LocalModuleId, UnresolvedMacro,
18 pub enum ResolvedAttr {
19 /// Attribute resolved to an attribute macro.
21 /// Attribute resolved to something else that does not require expansion.
26 pub(crate) fn resolve_attr_macro(
29 original_module: LocalModuleId,
30 ast_id: AstIdWithPath<ast::Item>,
32 ) -> Result<ResolvedAttr, UnresolvedMacro> {
33 // NB: does not currently work for derive helpers as they aren't recorded in the `DefMap`
35 if self.is_builtin_or_registered_attr(&ast_id.path) {
36 return Ok(ResolvedAttr::Other);
39 let resolved_res = self.resolve_path_fp_with_macro(
44 BuiltinShadowMode::Module,
46 let def = match resolved_res.resolved_def.take_macros() {
48 if def.is_attribute() {
51 return Ok(ResolvedAttr::Other);
54 None => return Err(UnresolvedMacro { path: ast_id.path.clone() }),
57 Ok(ResolvedAttr::Macro(attr_macro_as_call_id(&ast_id, attr, db, self.krate, def)))
60 pub(crate) fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
61 if path.kind != PathKind::Plain {
65 let segments = path.segments();
67 if let Some(name) = segments.first() {
68 let name = name.to_smol_str();
69 let pred = |n: &_| *n == name;
71 let registered = self.registered_tools.iter().map(SmolStr::as_str);
72 let is_tool = builtin_attr::TOOL_MODULES.iter().copied().chain(registered).any(pred);
73 // FIXME: tool modules can be shadowed by actual modules
78 if segments.len() == 1 {
79 let registered = self.registered_attrs.iter().map(SmolStr::as_str);
80 let is_inert = builtin_attr::INERT_ATTRIBUTES