hir_def/nameres/
attr_resolution.rs1use base_db::Crate;
4use hir_expand::{
5 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, LocalModuleId, MacroId, 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(
32 &self,
33 local_def_map: &LocalDefMap,
34 db: &dyn DefDatabase,
35 original_module: LocalModuleId,
36 ast_id: AstIdWithPath<ast::Item>,
37 attr: &Attr,
38 ) -> Result<ResolvedAttr, UnresolvedMacro> {
39 if self.is_builtin_or_registered_attr(&ast_id.path) {
42 return Ok(ResolvedAttr::Other);
43 }
44
45 let resolved_res = self.resolve_path_fp_with_macro(
46 local_def_map,
47 db,
48 ResolveMode::Other,
49 original_module,
50 &ast_id.path,
51 BuiltinShadowMode::Module,
52 Some(MacroSubNs::Attr),
53 );
54 let def = match resolved_res.resolved_def.take_macros() {
55 Some(def) => {
56 if def.is_attribute(db) {
59 def
60 } else {
61 return Ok(ResolvedAttr::Other);
62 }
63 }
64 None => return Err(UnresolvedMacro { path: ast_id.path.as_ref().clone() }),
65 };
66
67 Ok(ResolvedAttr::Macro(attr_macro_as_call_id(
68 db,
69 &ast_id,
70 attr,
71 self.krate,
72 db.macro_def(def),
73 )))
74 }
75
76 pub(crate) fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
77 if path.kind != PathKind::Plain {
78 return false;
79 }
80
81 let segments = path.segments();
82
83 if let Some(name) = segments.first() {
84 let name = name.symbol();
85 let pred = |n: &_| *n == *name;
86
87 let is_tool = self.data.registered_tools.iter().any(pred);
88 if is_tool {
90 return true;
91 }
92
93 if segments.len() == 1 {
94 if find_builtin_attr_idx(name).is_some() {
95 return true;
96 }
97 if self.data.registered_attrs.iter().any(pred) {
98 return true;
99 }
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 krate: Crate,
111 def: MacroDefId,
112) -> MacroCallId {
113 let arg = match macro_attr.input.as_deref() {
114 Some(AttrInput::TokenTree(tt)) => {
115 let mut tt = tt.clone();
116 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
117 Some(tt)
118 }
119
120 _ => None,
121 };
122
123 def.make_call(
124 db,
125 krate,
126 MacroCallKind::Attr {
127 ast_id: item_attr.ast_id,
128 attr_args: arg.map(Arc::new),
129 invoc_attr_index: macro_attr.id,
130 },
131 macro_attr.ctxt,
132 )
133}
134
135pub(super) fn derive_macro_as_call_id(
136 db: &dyn DefDatabase,
137 item_attr: &AstIdWithPath<ast::Adt>,
138 derive_attr_index: AttrId,
139 derive_pos: u32,
140 call_site: SyntaxContext,
141 krate: Crate,
142 resolver: impl Fn(&ModPath) -> Option<(MacroId, MacroDefId)>,
143 derive_macro_id: MacroCallId,
144) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
145 let (macro_id, def_id) = resolver(&item_attr.path)
146 .filter(|(_, def_id)| def_id.is_derive())
147 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.as_ref().clone() })?;
148 let call_id = def_id.make_call(
149 db,
150 krate,
151 MacroCallKind::Derive {
152 ast_id: item_attr.ast_id,
153 derive_index: derive_pos,
154 derive_attr_index,
155 derive_macro_id,
156 },
157 call_site,
158 );
159 Ok((macro_id, def_id, call_id))
160}