diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-08-13 15:31:49 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-08-13 15:31:49 +0100 |
commit | e9926948ca267932ccc1341388bfd1b3fa88a001 (patch) | |
tree | cc4b797cb39a40b59e9e3d37178e8a1907f12358 /crates/hir_def/src/data.rs | |
parent | 902f74c2697cc2a50de9067845814a2a852fccfd (diff) | |
parent | 50f8c1ebf23f634b68529603a917e3feeda457fa (diff) |
Merge #5747
5747: Rename crate r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/hir_def/src/data.rs')
-rw-r--r-- | crates/hir_def/src/data.rs | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs new file mode 100644 index 000000000..9a8eb4ede --- /dev/null +++ b/crates/hir_def/src/data.rs | |||
@@ -0,0 +1,278 @@ | |||
1 | //! Contains basic data about various HIR declarations. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_expand::{name::Name, InFile}; | ||
6 | use syntax::ast; | ||
7 | |||
8 | use crate::{ | ||
9 | attr::Attrs, | ||
10 | body::Expander, | ||
11 | db::DefDatabase, | ||
12 | item_tree::{AssocItem, ItemTreeId, ModItem}, | ||
13 | type_ref::{TypeBound, TypeRef}, | ||
14 | visibility::RawVisibility, | ||
15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, | ||
16 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | ||
17 | }; | ||
18 | |||
19 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
20 | pub struct FunctionData { | ||
21 | pub name: Name, | ||
22 | pub params: Vec<TypeRef>, | ||
23 | pub ret_type: TypeRef, | ||
24 | pub attrs: Attrs, | ||
25 | /// True if the first param is `self`. This is relevant to decide whether this | ||
26 | /// can be called as a method. | ||
27 | pub has_self_param: bool, | ||
28 | pub is_unsafe: bool, | ||
29 | pub is_varargs: bool, | ||
30 | pub visibility: RawVisibility, | ||
31 | } | ||
32 | |||
33 | impl FunctionData { | ||
34 | pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> { | ||
35 | let loc = func.lookup(db); | ||
36 | let item_tree = db.item_tree(loc.id.file_id); | ||
37 | let func = &item_tree[loc.id.value]; | ||
38 | |||
39 | Arc::new(FunctionData { | ||
40 | name: func.name.clone(), | ||
41 | params: func.params.to_vec(), | ||
42 | ret_type: func.ret_type.clone(), | ||
43 | attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), | ||
44 | has_self_param: func.has_self_param, | ||
45 | is_unsafe: func.is_unsafe, | ||
46 | is_varargs: func.is_varargs, | ||
47 | visibility: item_tree[func.visibility].clone(), | ||
48 | }) | ||
49 | } | ||
50 | } | ||
51 | |||
52 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
53 | pub struct TypeAliasData { | ||
54 | pub name: Name, | ||
55 | pub type_ref: Option<TypeRef>, | ||
56 | pub visibility: RawVisibility, | ||
57 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | ||
58 | pub bounds: Vec<TypeBound>, | ||
59 | } | ||
60 | |||
61 | impl TypeAliasData { | ||
62 | pub(crate) fn type_alias_data_query( | ||
63 | db: &dyn DefDatabase, | ||
64 | typ: TypeAliasId, | ||
65 | ) -> Arc<TypeAliasData> { | ||
66 | let loc = typ.lookup(db); | ||
67 | let item_tree = db.item_tree(loc.id.file_id); | ||
68 | let typ = &item_tree[loc.id.value]; | ||
69 | |||
70 | Arc::new(TypeAliasData { | ||
71 | name: typ.name.clone(), | ||
72 | type_ref: typ.type_ref.clone(), | ||
73 | visibility: item_tree[typ.visibility].clone(), | ||
74 | bounds: typ.bounds.to_vec(), | ||
75 | }) | ||
76 | } | ||
77 | } | ||
78 | |||
79 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
80 | pub struct TraitData { | ||
81 | pub name: Name, | ||
82 | pub items: Vec<(Name, AssocItemId)>, | ||
83 | pub auto: bool, | ||
84 | } | ||
85 | |||
86 | impl TraitData { | ||
87 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | ||
88 | let tr_loc = tr.lookup(db); | ||
89 | let item_tree = db.item_tree(tr_loc.id.file_id); | ||
90 | let tr_def = &item_tree[tr_loc.id.value]; | ||
91 | let name = tr_def.name.clone(); | ||
92 | let auto = tr_def.auto; | ||
93 | let module_id = tr_loc.container.module(db); | ||
94 | let container = AssocContainerId::TraitId(tr); | ||
95 | let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); | ||
96 | |||
97 | let items = collect_items( | ||
98 | db, | ||
99 | module_id, | ||
100 | &mut expander, | ||
101 | tr_def.items.iter().copied(), | ||
102 | tr_loc.id.file_id, | ||
103 | container, | ||
104 | 100, | ||
105 | ); | ||
106 | |||
107 | Arc::new(TraitData { name, items, auto }) | ||
108 | } | ||
109 | |||
110 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { | ||
111 | self.items.iter().filter_map(|(_name, item)| match item { | ||
112 | AssocItemId::TypeAliasId(t) => Some(*t), | ||
113 | _ => None, | ||
114 | }) | ||
115 | } | ||
116 | |||
117 | pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> { | ||
118 | self.items.iter().find_map(|(item_name, item)| match item { | ||
119 | AssocItemId::TypeAliasId(t) if item_name == name => Some(*t), | ||
120 | _ => None, | ||
121 | }) | ||
122 | } | ||
123 | } | ||
124 | |||
125 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
126 | pub struct ImplData { | ||
127 | pub target_trait: Option<TypeRef>, | ||
128 | pub target_type: TypeRef, | ||
129 | pub items: Vec<AssocItemId>, | ||
130 | pub is_negative: bool, | ||
131 | } | ||
132 | |||
133 | impl ImplData { | ||
134 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { | ||
135 | let _p = profile::span("impl_data_query"); | ||
136 | let impl_loc = id.lookup(db); | ||
137 | |||
138 | let item_tree = db.item_tree(impl_loc.id.file_id); | ||
139 | let impl_def = &item_tree[impl_loc.id.value]; | ||
140 | let target_trait = impl_def.target_trait.clone(); | ||
141 | let target_type = impl_def.target_type.clone(); | ||
142 | let is_negative = impl_def.is_negative; | ||
143 | let module_id = impl_loc.container.module(db); | ||
144 | let container = AssocContainerId::ImplId(id); | ||
145 | let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); | ||
146 | |||
147 | let items = collect_items( | ||
148 | db, | ||
149 | module_id, | ||
150 | &mut expander, | ||
151 | impl_def.items.iter().copied(), | ||
152 | impl_loc.id.file_id, | ||
153 | container, | ||
154 | 100, | ||
155 | ); | ||
156 | let items = items.into_iter().map(|(_, item)| item).collect(); | ||
157 | |||
158 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) | ||
159 | } | ||
160 | } | ||
161 | |||
162 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
163 | pub struct ConstData { | ||
164 | /// const _: () = (); | ||
165 | pub name: Option<Name>, | ||
166 | pub type_ref: TypeRef, | ||
167 | pub visibility: RawVisibility, | ||
168 | } | ||
169 | |||
170 | impl ConstData { | ||
171 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { | ||
172 | let loc = konst.lookup(db); | ||
173 | let item_tree = db.item_tree(loc.id.file_id); | ||
174 | let konst = &item_tree[loc.id.value]; | ||
175 | |||
176 | Arc::new(ConstData { | ||
177 | name: konst.name.clone(), | ||
178 | type_ref: konst.type_ref.clone(), | ||
179 | visibility: item_tree[konst.visibility].clone(), | ||
180 | }) | ||
181 | } | ||
182 | } | ||
183 | |||
184 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
185 | pub struct StaticData { | ||
186 | pub name: Option<Name>, | ||
187 | pub type_ref: TypeRef, | ||
188 | pub visibility: RawVisibility, | ||
189 | pub mutable: bool, | ||
190 | } | ||
191 | |||
192 | impl StaticData { | ||
193 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { | ||
194 | let node = konst.lookup(db); | ||
195 | let item_tree = db.item_tree(node.id.file_id); | ||
196 | let statik = &item_tree[node.id.value]; | ||
197 | |||
198 | Arc::new(StaticData { | ||
199 | name: Some(statik.name.clone()), | ||
200 | type_ref: statik.type_ref.clone(), | ||
201 | visibility: item_tree[statik.visibility].clone(), | ||
202 | mutable: statik.mutable, | ||
203 | }) | ||
204 | } | ||
205 | } | ||
206 | |||
207 | fn collect_items( | ||
208 | db: &dyn DefDatabase, | ||
209 | module: ModuleId, | ||
210 | expander: &mut Expander, | ||
211 | assoc_items: impl Iterator<Item = AssocItem>, | ||
212 | file_id: crate::HirFileId, | ||
213 | container: AssocContainerId, | ||
214 | limit: usize, | ||
215 | ) -> Vec<(Name, AssocItemId)> { | ||
216 | if limit == 0 { | ||
217 | return Vec::new(); | ||
218 | } | ||
219 | |||
220 | let item_tree = db.item_tree(file_id); | ||
221 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); | ||
222 | |||
223 | let mut items = Vec::new(); | ||
224 | for item in assoc_items { | ||
225 | match item { | ||
226 | AssocItem::Function(id) => { | ||
227 | let item = &item_tree[id]; | ||
228 | let attrs = item_tree.attrs(ModItem::from(id).into()); | ||
229 | if !attrs.is_cfg_enabled(&cfg_options) { | ||
230 | continue; | ||
231 | } | ||
232 | let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
233 | items.push((item.name.clone(), def.into())); | ||
234 | } | ||
235 | // FIXME: cfg? | ||
236 | AssocItem::Const(id) => { | ||
237 | let item = &item_tree[id]; | ||
238 | let name = match item.name.clone() { | ||
239 | Some(name) => name, | ||
240 | None => continue, | ||
241 | }; | ||
242 | let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
243 | items.push((name, def.into())); | ||
244 | } | ||
245 | AssocItem::TypeAlias(id) => { | ||
246 | let item = &item_tree[id]; | ||
247 | let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
248 | items.push((item.name.clone(), def.into())); | ||
249 | } | ||
250 | AssocItem::MacroCall(call) => { | ||
251 | let call = &item_tree[call]; | ||
252 | let ast_id_map = db.ast_id_map(file_id); | ||
253 | let root = db.parse_or_expand(file_id).unwrap(); | ||
254 | let call = ast_id_map.get(call.ast_id).to_node(&root); | ||
255 | |||
256 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | ||
257 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | ||
258 | let item_tree = db.item_tree(src.file_id); | ||
259 | let iter = | ||
260 | item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); | ||
261 | items.extend(collect_items( | ||
262 | db, | ||
263 | module, | ||
264 | expander, | ||
265 | iter, | ||
266 | src.file_id, | ||
267 | container, | ||
268 | limit - 1, | ||
269 | )); | ||
270 | |||
271 | expander.exit(db, mark); | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | items | ||
278 | } | ||