]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/hir/src/attrs.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / hir / src / attrs.rs
CommitLineData
064997fb
FG
1//! Attributes & documentation for hir types.
2
3use hir_def::{
4 attr::{AttrsWithOwner, Documentation},
5 item_scope::ItemInNs,
6 path::ModPath,
7 per_ns::PerNs,
8 resolver::HasResolver,
9 AttrDefId, GenericParamId, ModuleDefId,
10};
11use hir_expand::hygiene::Hygiene;
12use hir_ty::db::HirDatabase;
13use syntax::{ast, AstNode};
14
15use crate::{
16 Adt, AssocItem, Const, ConstParam, Enum, Field, Function, GenericParam, Impl, LifetimeParam,
17 Macro, Module, ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
18};
19
20pub trait HasAttrs {
21 fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner;
22 fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
23 fn resolve_doc_path(
24 self,
25 db: &dyn HirDatabase,
26 link: &str,
27 ns: Option<Namespace>,
28 ) -> Option<ModuleDef>;
29}
30
31#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
32pub enum Namespace {
33 Types,
34 Values,
35 Macros,
36}
37
38macro_rules! impl_has_attrs {
39 ($(($def:ident, $def_id:ident),)*) => {$(
40 impl HasAttrs for $def {
41 fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
42 let def = AttrDefId::$def_id(self.into());
43 db.attrs(def)
44 }
45 fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
46 let def = AttrDefId::$def_id(self.into());
47 db.attrs(def).docs()
48 }
49 fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> {
50 let def = AttrDefId::$def_id(self.into());
51 resolve_doc_path(db, def, link, ns).map(ModuleDef::from)
52 }
53 }
54 )*};
55}
56
57impl_has_attrs![
58 (Field, FieldId),
59 (Variant, EnumVariantId),
60 (Static, StaticId),
61 (Const, ConstId),
62 (Trait, TraitId),
63 (TypeAlias, TypeAliasId),
64 (Macro, MacroId),
65 (Function, FunctionId),
66 (Adt, AdtId),
67 (Module, ModuleId),
68 (GenericParam, GenericParamId),
69 (Impl, ImplId),
70];
71
72macro_rules! impl_has_attrs_enum {
73 ($($variant:ident),* for $enum:ident) => {$(
74 impl HasAttrs for $variant {
75 fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
76 $enum::$variant(self).attrs(db)
77 }
78 fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
79 $enum::$variant(self).docs(db)
80 }
81 fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> {
82 $enum::$variant(self).resolve_doc_path(db, link, ns)
83 }
84 }
85 )*};
86}
87
88impl_has_attrs_enum![Struct, Union, Enum for Adt];
89impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam];
90
91impl HasAttrs for AssocItem {
92 fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
93 match self {
94 AssocItem::Function(it) => it.attrs(db),
95 AssocItem::Const(it) => it.attrs(db),
96 AssocItem::TypeAlias(it) => it.attrs(db),
97 }
98 }
99
100 fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
101 match self {
102 AssocItem::Function(it) => it.docs(db),
103 AssocItem::Const(it) => it.docs(db),
104 AssocItem::TypeAlias(it) => it.docs(db),
105 }
106 }
107
108 fn resolve_doc_path(
109 self,
110 db: &dyn HirDatabase,
111 link: &str,
112 ns: Option<Namespace>,
113 ) -> Option<ModuleDef> {
114 match self {
115 AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
116 AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
117 AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
118 }
119 }
120}
121
122fn resolve_doc_path(
123 db: &dyn HirDatabase,
124 def: AttrDefId,
125 link: &str,
126 ns: Option<Namespace>,
127) -> Option<ModuleDefId> {
128 let resolver = match def {
129 AttrDefId::ModuleId(it) => it.resolver(db.upcast()),
130 AttrDefId::FieldId(it) => it.parent.resolver(db.upcast()),
131 AttrDefId::AdtId(it) => it.resolver(db.upcast()),
132 AttrDefId::FunctionId(it) => it.resolver(db.upcast()),
133 AttrDefId::EnumVariantId(it) => it.parent.resolver(db.upcast()),
134 AttrDefId::StaticId(it) => it.resolver(db.upcast()),
135 AttrDefId::ConstId(it) => it.resolver(db.upcast()),
136 AttrDefId::TraitId(it) => it.resolver(db.upcast()),
137 AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
138 AttrDefId::ImplId(it) => it.resolver(db.upcast()),
139 AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()),
140 AttrDefId::MacroId(it) => it.resolver(db.upcast()),
141 AttrDefId::GenericParamId(it) => match it {
142 GenericParamId::TypeParamId(it) => it.parent(),
143 GenericParamId::ConstParamId(it) => it.parent(),
144 GenericParamId::LifetimeParamId(it) => it.parent,
145 }
146 .resolver(db.upcast()),
147 };
148
149 let modpath = {
150 // FIXME: this is not how we should get a mod path here
f25598a0 151 let ast_path = ast::SourceFile::parse(&format!("type T = {link};"))
064997fb
FG
152 .syntax_node()
153 .descendants()
154 .find_map(ast::Path::cast)?;
155 if ast_path.to_string() != link {
156 return None;
157 }
158 ModPath::from_src(db.upcast(), ast_path, &Hygiene::new_unhygienic())?
159 };
160
161 let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
162 let resolved = if resolved == PerNs::none() {
163 resolver.resolve_module_path_in_trait_assoc_items(db.upcast(), &modpath)?
164 } else {
165 resolved
166 };
167 match ns {
168 Some(Namespace::Types) => resolved.take_types(),
169 Some(Namespace::Values) => resolved.take_values(),
170 Some(Namespace::Macros) => resolved.take_macros().map(ModuleDefId::MacroId),
171 None => resolved.iter_items().next().map(|it| match it {
172 ItemInNs::Types(it) => it,
173 ItemInNs::Values(it) => it,
174 ItemInNs::Macros(it) => ModuleDefId::MacroId(it),
175 }),
176 }
177}