]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/nameres/attr_resolution.rs
Replaced fold with for loop
[rust.git] / crates / hir_def / src / nameres / attr_resolution.rs
1 //! Post-nameres attribute resolution.
2
3 use hir_expand::MacroCallId;
4 use syntax::{ast, SmolStr};
5
6 use crate::{
7     attr::Attr,
8     attr_macro_as_call_id, builtin_attr,
9     db::DefDatabase,
10     item_scope::BuiltinShadowMode,
11     nameres::path_resolution::ResolveMode,
12     path::{ModPath, PathKind},
13     AstIdWithPath, LocalModuleId, UnresolvedMacro,
14 };
15
16 use super::DefMap;
17
18 pub enum ResolvedAttr {
19     /// Attribute resolved to an attribute macro.
20     Macro(MacroCallId),
21     /// Attribute resolved to something else that does not require expansion.
22     Other,
23 }
24
25 impl DefMap {
26     pub(crate) fn resolve_attr_macro(
27         &self,
28         db: &dyn DefDatabase,
29         original_module: LocalModuleId,
30         ast_id: AstIdWithPath<ast::Item>,
31         attr: &Attr,
32     ) -> Result<ResolvedAttr, UnresolvedMacro> {
33         // NB: does not currently work for derive helpers as they aren't recorded in the `DefMap`
34
35         if self.is_builtin_or_registered_attr(&ast_id.path) {
36             return Ok(ResolvedAttr::Other);
37         }
38
39         let resolved_res = self.resolve_path_fp_with_macro(
40             db,
41             ResolveMode::Other,
42             original_module,
43             &ast_id.path,
44             BuiltinShadowMode::Module,
45         );
46         let def = match resolved_res.resolved_def.take_macros() {
47             Some(def) => {
48                 if def.is_attribute() {
49                     def
50                 } else {
51                     return Ok(ResolvedAttr::Other);
52                 }
53             }
54             None => return Err(UnresolvedMacro { path: ast_id.path.clone() }),
55         };
56
57         Ok(ResolvedAttr::Macro(attr_macro_as_call_id(&ast_id, attr, db, self.krate, def)))
58     }
59
60     pub(crate) fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
61         if path.kind != PathKind::Plain {
62             return false;
63         }
64
65         let segments = path.segments();
66
67         if let Some(name) = segments.first() {
68             let name = name.to_smol_str();
69             let pred = |n: &_| *n == name;
70
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
74             if is_tool {
75                 return true;
76             }
77
78             if segments.len() == 1 {
79                 let registered = self.registered_attrs.iter().map(SmolStr::as_str);
80                 let is_inert = builtin_attr::INERT_ATTRIBUTES
81                     .iter()
82                     .map(|it| it.name)
83                     .chain(registered)
84                     .any(pred);
85                 return is_inert;
86             }
87         }
88         false
89     }
90 }