hir_def/nameres/
attr_resolution.rs1use base_db::Crate;
4use hir_expand::{
5 AttrMacroAttrIds, MacroCallId, MacroCallKind, MacroDefId,
6 attrs::{Attr, AttrId, AttrInput},
7 inert_attr_macro::find_builtin_attr_idx,
8 mod_path::{ModPath, PathKind},
9};
10use span::SyntaxContext;
11use syntax::ast;
12use triomphe::Arc;
13
14use crate::{
15 AstIdWithPath, MacroId, ModuleId, UnresolvedMacro,
16 db::DefDatabase,
17 item_scope::BuiltinShadowMode,
18 nameres::{LocalDefMap, path_resolution::ResolveMode},
19};
20
21use super::{DefMap, MacroSubNs};
22
23pub enum ResolvedAttr {
24 Macro(MacroCallId),
26 Other,
28}
29
30impl DefMap {
31 pub(crate) fn resolve_attr_macro(
33 &self,
34 local_def_map: &LocalDefMap,
35 db: &dyn DefDatabase,
36 original_module: ModuleId,
37 ast_id: AstIdWithPath<ast::Item>,
38 attr: &Attr,
39 attr_id: AttrId,
40 ) -> Result<ResolvedAttr, UnresolvedMacro> {
41 if self.is_builtin_or_registered_attr(&ast_id.path) {
44 return Ok(ResolvedAttr::Other);
45 }
46
47 let resolved_res = self.resolve_path_fp_with_macro(
48 local_def_map,
49 db,
50 ResolveMode::Other,
51 original_module,
52 &ast_id.path,
53 BuiltinShadowMode::Module,
54 Some(MacroSubNs::Attr),
55 );
56 let def = match resolved_res.resolved_def.take_macros() {
57 Some(def) => {
58 if def.is_attribute(db) {
61 def
62 } else {
63 return Ok(ResolvedAttr::Other);
64 }
65 }
66 None => return Err(UnresolvedMacro { path: ast_id.path.as_ref().clone() }),
67 };
68
69 Ok(ResolvedAttr::Macro(attr_macro_as_call_id(
70 db,
71 &ast_id,
72 attr,
73 AttrMacroAttrIds::from_one(attr_id),
76 self.krate,
77 db.macro_def(def),
78 )))
79 }
80
81 pub(crate) fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
82 if path.kind != PathKind::Plain {
83 return false;
84 }
85
86 let segments = path.segments();
87
88 if let Some(name) = segments.first() {
89 let name = name.symbol();
90 let pred = |n: &_| *n == *name;
91
92 let is_tool = self.data.registered_tools.iter().any(pred);
93 if is_tool {
95 return true;
96 }
97
98 if segments.len() == 1 && find_builtin_attr_idx(name).is_some() {
99 return true;
100 }
101 }
102 false
103 }
104}
105
106pub(super) fn attr_macro_as_call_id(
107 db: &dyn DefDatabase,
108 item_attr: &AstIdWithPath<ast::Item>,
109 macro_attr: &Attr,
110 censored_attr_ids: AttrMacroAttrIds,
111 krate: Crate,
112 def: MacroDefId,
113) -> MacroCallId {
114 let arg = match macro_attr.input.as_deref() {
115 Some(AttrInput::TokenTree(tt)) => {
116 let mut tt = tt.clone();
117 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
118 Some(tt)
119 }
120
121 _ => None,
122 };
123
124 def.make_call(
125 db,
126 krate,
127 MacroCallKind::Attr {
128 ast_id: item_attr.ast_id,
129 attr_args: arg.map(Arc::new),
130 censored_attr_ids,
131 },
132 macro_attr.ctxt,
133 )
134}
135
136pub(super) fn derive_macro_as_call_id(
137 db: &dyn DefDatabase,
138 item_attr: &AstIdWithPath<ast::Adt>,
139 derive_attr_index: AttrId,
140 derive_pos: u32,
141 call_site: SyntaxContext,
142 krate: Crate,
143 resolver: impl Fn(&ModPath) -> Option<(MacroId, MacroDefId)>,
144 derive_macro_id: MacroCallId,
145) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
146 let (macro_id, def_id) = resolver(&item_attr.path)
147 .filter(|(_, def_id)| def_id.is_derive())
148 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.as_ref().clone() })?;
149 let call_id = def_id.make_call(
150 db,
151 krate,
152 MacroCallKind::Derive {
153 ast_id: item_attr.ast_id,
154 derive_index: derive_pos,
155 derive_attr_index,
156 derive_macro_id,
157 },
158 call_site,
159 );
160 Ok((macro_id, def_id, call_id))
161}