2022-01-06 05:30:16 -06:00
|
|
|
//! Post-nameres attribute resolution.
|
|
|
|
|
|
|
|
use hir_expand::MacroCallId;
|
|
|
|
use syntax::{ast, SmolStr};
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
attr::Attr,
|
|
|
|
attr_macro_as_call_id, builtin_attr,
|
|
|
|
db::DefDatabase,
|
|
|
|
item_scope::BuiltinShadowMode,
|
|
|
|
nameres::path_resolution::ResolveMode,
|
|
|
|
path::{ModPath, PathKind},
|
|
|
|
AstIdWithPath, LocalModuleId, UnresolvedMacro,
|
|
|
|
};
|
|
|
|
|
|
|
|
use super::DefMap;
|
|
|
|
|
|
|
|
pub enum ResolvedAttr {
|
|
|
|
/// Attribute resolved to an attribute macro.
|
|
|
|
Macro(MacroCallId),
|
|
|
|
/// Attribute resolved to something else that does not require expansion.
|
|
|
|
Other,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DefMap {
|
|
|
|
pub(crate) fn resolve_attr_macro(
|
|
|
|
&self,
|
|
|
|
db: &dyn DefDatabase,
|
|
|
|
original_module: LocalModuleId,
|
|
|
|
ast_id: AstIdWithPath<ast::Item>,
|
|
|
|
attr: &Attr,
|
|
|
|
) -> Result<ResolvedAttr, UnresolvedMacro> {
|
|
|
|
// NB: does not currently work for derive helpers as they aren't recorded in the `DefMap`
|
|
|
|
|
|
|
|
if self.is_builtin_or_registered_attr(&ast_id.path) {
|
|
|
|
return Ok(ResolvedAttr::Other);
|
|
|
|
}
|
|
|
|
|
|
|
|
let resolved_res = self.resolve_path_fp_with_macro(
|
|
|
|
db,
|
|
|
|
ResolveMode::Other,
|
|
|
|
original_module,
|
|
|
|
&ast_id.path,
|
|
|
|
BuiltinShadowMode::Module,
|
|
|
|
);
|
|
|
|
let def = match resolved_res.resolved_def.take_macros() {
|
|
|
|
Some(def) => {
|
|
|
|
if def.is_attribute() {
|
|
|
|
def
|
|
|
|
} else {
|
|
|
|
return Ok(ResolvedAttr::Other);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => return Err(UnresolvedMacro { path: ast_id.path.clone() }),
|
|
|
|
};
|
|
|
|
|
2022-02-20 19:42:58 -06:00
|
|
|
Ok(ResolvedAttr::Macro(attr_macro_as_call_id(db, &ast_id, attr, self.krate, def, false)))
|
2022-01-06 05:30:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
|
|
|
|
if path.kind != PathKind::Plain {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let segments = path.segments();
|
|
|
|
|
|
|
|
if let Some(name) = segments.first() {
|
|
|
|
let name = name.to_smol_str();
|
|
|
|
let pred = |n: &_| *n == name;
|
|
|
|
|
|
|
|
let registered = self.registered_tools.iter().map(SmolStr::as_str);
|
|
|
|
let is_tool = builtin_attr::TOOL_MODULES.iter().copied().chain(registered).any(pred);
|
|
|
|
// FIXME: tool modules can be shadowed by actual modules
|
|
|
|
if is_tool {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if segments.len() == 1 {
|
|
|
|
let registered = self.registered_attrs.iter().map(SmolStr::as_str);
|
|
|
|
let is_inert = builtin_attr::INERT_ATTRIBUTES
|
|
|
|
.iter()
|
|
|
|
.map(|it| it.name)
|
|
|
|
.chain(registered)
|
|
|
|
.any(pred);
|
|
|
|
return is_inert;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|