]>
Commit | Line | Data |
---|---|---|
064997fb FG |
1 | //! Attributes & documentation for hir types. |
2 | ||
3 | use 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 | }; | |
11 | use hir_expand::hygiene::Hygiene; | |
12 | use hir_ty::db::HirDatabase; | |
13 | use syntax::{ast, AstNode}; | |
14 | ||
15 | use 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 | ||
20 | pub 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)] | |
32 | pub enum Namespace { | |
33 | Types, | |
34 | Values, | |
35 | Macros, | |
36 | } | |
37 | ||
38 | macro_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 | ||
57 | impl_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 | ||
72 | macro_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 | ||
88 | impl_has_attrs_enum![Struct, Union, Enum for Adt]; | |
89 | impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam]; | |
90 | ||
91 | impl 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 | ||
122 | fn 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 | } |