diff options
Diffstat (limited to 'crates/ra_hir_def/src/data.rs')
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 382 |
1 files changed, 137 insertions, 245 deletions
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 53599e74a..282ade2a3 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -2,27 +2,19 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_expand::{ | 5 | use hir_expand::{name::Name, InFile}; |
6 | hygiene::Hygiene, | ||
7 | name::{name, AsName, Name}, | ||
8 | AstId, InFile, | ||
9 | }; | ||
10 | use ra_prof::profile; | 6 | use ra_prof::profile; |
11 | use ra_syntax::ast::{ | 7 | use ra_syntax::ast; |
12 | self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner, | ||
13 | VisibilityOwner, | ||
14 | }; | ||
15 | 8 | ||
16 | use crate::{ | 9 | use crate::{ |
17 | attr::Attrs, | 10 | attr::Attrs, |
18 | body::LowerCtx, | 11 | body::Expander, |
19 | db::DefDatabase, | 12 | db::DefDatabase, |
20 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, | 13 | item_tree::{AssocItem, ItemTreeId, ModItem}, |
21 | src::HasSource, | 14 | type_ref::{TypeBound, TypeRef}, |
22 | type_ref::{Mutability, TypeBound, TypeRef}, | ||
23 | visibility::RawVisibility, | 15 | visibility::RawVisibility, |
24 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, | 16 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, |
25 | ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 17 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
26 | }; | 18 | }; |
27 | 19 | ||
28 | #[derive(Debug, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -41,82 +33,27 @@ pub struct FunctionData { | |||
41 | impl FunctionData { | 33 | impl FunctionData { |
42 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { | 34 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { |
43 | let loc = func.lookup(db); | 35 | let loc = func.lookup(db); |
44 | let src = loc.source(db); | 36 | let item_tree = db.item_tree(loc.id.file_id); |
45 | let ctx = LowerCtx::new(db, src.file_id); | 37 | let func = &item_tree[loc.id.value]; |
46 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | 38 | |
47 | let mut params = Vec::new(); | 39 | Arc::new(FunctionData { |
48 | let mut has_self_param = false; | 40 | name: func.name.clone(), |
49 | if let Some(param_list) = src.value.param_list() { | 41 | params: func.params.to_vec(), |
50 | if let Some(self_param) = param_list.self_param() { | 42 | ret_type: func.ret_type.clone(), |
51 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | 43 | attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), |
52 | TypeRef::from_ast(&ctx, type_ref) | 44 | has_self_param: func.has_self_param, |
53 | } else { | 45 | is_unsafe: func.is_unsafe, |
54 | let self_type = TypeRef::Path(name![Self].into()); | 46 | visibility: item_tree[func.visibility].clone(), |
55 | match self_param.kind() { | 47 | }) |
56 | ast::SelfParamKind::Owned => self_type, | ||
57 | ast::SelfParamKind::Ref => { | ||
58 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
59 | } | ||
60 | ast::SelfParamKind::MutRef => { | ||
61 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
62 | } | ||
63 | } | ||
64 | }; | ||
65 | params.push(self_type); | ||
66 | has_self_param = true; | ||
67 | } | ||
68 | for param in param_list.params() { | ||
69 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); | ||
70 | params.push(type_ref); | ||
71 | } | ||
72 | } | ||
73 | let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); | ||
74 | |||
75 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { | ||
76 | TypeRef::from_ast(&ctx, type_ref) | ||
77 | } else { | ||
78 | TypeRef::unit() | ||
79 | }; | ||
80 | |||
81 | let ret_type = if src.value.async_token().is_some() { | ||
82 | let future_impl = desugar_future_path(ret_type); | ||
83 | let ty_bound = TypeBound::Path(future_impl); | ||
84 | TypeRef::ImplTrait(vec![ty_bound]) | ||
85 | } else { | ||
86 | ret_type | ||
87 | }; | ||
88 | |||
89 | let is_unsafe = src.value.unsafe_token().is_some(); | ||
90 | |||
91 | let vis_default = RawVisibility::default_for_container(loc.container); | ||
92 | let visibility = | ||
93 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); | ||
94 | |||
95 | let sig = | ||
96 | FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs }; | ||
97 | Arc::new(sig) | ||
98 | } | 48 | } |
99 | } | 49 | } |
100 | 50 | ||
101 | fn desugar_future_path(orig: TypeRef) -> Path { | ||
102 | let path = path![core::future::Future]; | ||
103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | ||
104 | let mut last = GenericArgs::empty(); | ||
105 | last.bindings.push(AssociatedTypeBinding { | ||
106 | name: name![Output], | ||
107 | type_ref: Some(orig), | ||
108 | bounds: Vec::new(), | ||
109 | }); | ||
110 | generic_args.push(Some(Arc::new(last))); | ||
111 | |||
112 | Path::from_known_path(path, generic_args) | ||
113 | } | ||
114 | |||
115 | #[derive(Debug, Clone, PartialEq, Eq)] | 51 | #[derive(Debug, Clone, PartialEq, Eq)] |
116 | pub struct TypeAliasData { | 52 | pub struct TypeAliasData { |
117 | pub name: Name, | 53 | pub name: Name, |
118 | pub type_ref: Option<TypeRef>, | 54 | pub type_ref: Option<TypeRef>, |
119 | pub visibility: RawVisibility, | 55 | pub visibility: RawVisibility, |
56 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | ||
120 | pub bounds: Vec<TypeBound>, | 57 | pub bounds: Vec<TypeBound>, |
121 | } | 58 | } |
122 | 59 | ||
@@ -126,22 +63,15 @@ impl TypeAliasData { | |||
126 | typ: TypeAliasId, | 63 | typ: TypeAliasId, |
127 | ) -> Arc<TypeAliasData> { | 64 | ) -> Arc<TypeAliasData> { |
128 | let loc = typ.lookup(db); | 65 | let loc = typ.lookup(db); |
129 | let node = loc.source(db); | 66 | let item_tree = db.item_tree(loc.id.file_id); |
130 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); | 67 | let typ = &item_tree[loc.id.value]; |
131 | let lower_ctx = LowerCtx::new(db, node.file_id); | 68 | |
132 | let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); | 69 | Arc::new(TypeAliasData { |
133 | let vis_default = RawVisibility::default_for_container(loc.container); | 70 | name: typ.name.clone(), |
134 | let visibility = RawVisibility::from_ast_with_default( | 71 | type_ref: typ.type_ref.clone(), |
135 | db, | 72 | visibility: item_tree[typ.visibility].clone(), |
136 | vis_default, | 73 | bounds: typ.bounds.to_vec(), |
137 | node.as_ref().map(|n| n.visibility()), | 74 | }) |
138 | ); | ||
139 | let bounds = if let Some(bound_list) = node.value.type_bound_list() { | ||
140 | bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect() | ||
141 | } else { | ||
142 | Vec::new() | ||
143 | }; | ||
144 | Arc::new(TypeAliasData { name, type_ref, visibility, bounds }) | ||
145 | } | 75 | } |
146 | } | 76 | } |
147 | 77 | ||
@@ -155,30 +85,24 @@ pub struct TraitData { | |||
155 | impl TraitData { | 85 | impl TraitData { |
156 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | 86 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { |
157 | let tr_loc = tr.lookup(db); | 87 | let tr_loc = tr.lookup(db); |
158 | let src = tr_loc.source(db); | 88 | let item_tree = db.item_tree(tr_loc.id.file_id); |
159 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 89 | let tr_def = &item_tree[tr_loc.id.value]; |
160 | let auto = src.value.auto_token().is_some(); | 90 | let name = tr_def.name.clone(); |
91 | let auto = tr_def.auto; | ||
161 | let module_id = tr_loc.container.module(db); | 92 | let module_id = tr_loc.container.module(db); |
162 | |||
163 | let container = AssocContainerId::TraitId(tr); | 93 | let container = AssocContainerId::TraitId(tr); |
164 | let mut items = Vec::new(); | 94 | let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); |
165 | 95 | ||
166 | if let Some(item_list) = src.value.item_list() { | 96 | let items = collect_items( |
167 | let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); | 97 | db, |
168 | items.extend(collect_items( | 98 | module_id, |
169 | db, | 99 | &mut expander, |
170 | &mut expander, | 100 | tr_def.items.iter().copied(), |
171 | item_list.assoc_items(), | 101 | tr_loc.id.file_id, |
172 | src.file_id, | 102 | container, |
173 | container, | 103 | 100, |
174 | )); | 104 | ); |
175 | items.extend(collect_items_in_macros( | 105 | |
176 | db, | ||
177 | &mut expander, | ||
178 | &src.with_value(item_list), | ||
179 | container, | ||
180 | )); | ||
181 | } | ||
182 | Arc::new(TraitData { name, items, auto }) | 106 | Arc::new(TraitData { name, items, auto }) |
183 | } | 107 | } |
184 | 108 | ||
@@ -209,33 +133,28 @@ impl ImplData { | |||
209 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { | 133 | pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { |
210 | let _p = profile("impl_data_query"); | 134 | let _p = profile("impl_data_query"); |
211 | let impl_loc = id.lookup(db); | 135 | let impl_loc = id.lookup(db); |
212 | let src = impl_loc.source(db); | ||
213 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
214 | 136 | ||
215 | let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); | 137 | let item_tree = db.item_tree(impl_loc.id.file_id); |
216 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); | 138 | let impl_def = &item_tree[impl_loc.id.value]; |
217 | let is_negative = src.value.excl_token().is_some(); | 139 | let target_trait = impl_def.target_trait.clone(); |
140 | let target_type = impl_def.target_type.clone(); | ||
141 | let is_negative = impl_def.is_negative; | ||
218 | let module_id = impl_loc.container.module(db); | 142 | let module_id = impl_loc.container.module(db); |
219 | let container = AssocContainerId::ImplId(id); | 143 | let container = AssocContainerId::ImplId(id); |
144 | let mut expander = Expander::new(db, impl_loc.id.file_id, module_id); | ||
220 | 145 | ||
221 | let mut items: Vec<AssocItemId> = Vec::new(); | 146 | let items = collect_items( |
222 | 147 | db, | |
223 | if let Some(item_list) = src.value.item_list() { | 148 | module_id, |
224 | let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); | 149 | &mut expander, |
225 | items.extend( | 150 | impl_def.items.iter().copied(), |
226 | collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) | 151 | impl_loc.id.file_id, |
227 | .into_iter() | 152 | container, |
228 | .map(|(_, item)| item), | 153 | 100, |
229 | ); | 154 | ); |
230 | items.extend( | 155 | let items = items.into_iter().map(|(_, item)| item).collect(); |
231 | collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container) | ||
232 | .into_iter() | ||
233 | .map(|(_, item)| item), | ||
234 | ); | ||
235 | } | ||
236 | 156 | ||
237 | let res = ImplData { target_trait, target_type, items, is_negative }; | 157 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) |
238 | Arc::new(res) | ||
239 | } | 158 | } |
240 | } | 159 | } |
241 | 160 | ||
@@ -250,22 +169,14 @@ pub struct ConstData { | |||
250 | impl ConstData { | 169 | impl ConstData { |
251 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { | 170 | pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { |
252 | let loc = konst.lookup(db); | 171 | let loc = konst.lookup(db); |
253 | let node = loc.source(db); | 172 | let item_tree = db.item_tree(loc.id.file_id); |
254 | let vis_default = RawVisibility::default_for_container(loc.container); | 173 | let konst = &item_tree[loc.id.value]; |
255 | Arc::new(ConstData::new(db, vis_default, node)) | ||
256 | } | ||
257 | 174 | ||
258 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( | 175 | Arc::new(ConstData { |
259 | db: &dyn DefDatabase, | 176 | name: konst.name.clone(), |
260 | vis_default: RawVisibility, | 177 | type_ref: konst.type_ref.clone(), |
261 | node: InFile<N>, | 178 | visibility: item_tree[konst.visibility].clone(), |
262 | ) -> ConstData { | 179 | }) |
263 | let ctx = LowerCtx::new(db, node.file_id); | ||
264 | let name = node.value.name().map(|n| n.as_name()); | ||
265 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); | ||
266 | let visibility = | ||
267 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | ||
268 | ConstData { name, type_ref, visibility } | ||
269 | } | 180 | } |
270 | } | 181 | } |
271 | 182 | ||
@@ -279,44 +190,25 @@ pub struct StaticData { | |||
279 | 190 | ||
280 | impl StaticData { | 191 | impl StaticData { |
281 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { | 192 | pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { |
282 | let node = konst.lookup(db).source(db); | 193 | let node = konst.lookup(db); |
283 | let ctx = LowerCtx::new(db, node.file_id); | 194 | let item_tree = db.item_tree(node.id.file_id); |
284 | 195 | let statik = &item_tree[node.id.value]; | |
285 | let name = node.value.name().map(|n| n.as_name()); | 196 | |
286 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); | 197 | Arc::new(StaticData { |
287 | let mutable = node.value.mut_token().is_some(); | 198 | name: Some(statik.name.clone()), |
288 | let visibility = RawVisibility::from_ast_with_default( | 199 | type_ref: statik.type_ref.clone(), |
289 | db, | 200 | visibility: item_tree[statik.visibility].clone(), |
290 | RawVisibility::private(), | 201 | mutable: statik.mutable, |
291 | node.map(|n| n.visibility()), | 202 | }) |
292 | ); | ||
293 | |||
294 | Arc::new(StaticData { name, type_ref, visibility, mutable }) | ||
295 | } | ||
296 | } | ||
297 | |||
298 | fn collect_items_in_macros( | ||
299 | db: &dyn DefDatabase, | ||
300 | expander: &mut Expander, | ||
301 | impl_def: &InFile<ast::ItemList>, | ||
302 | container: AssocContainerId, | ||
303 | ) -> Vec<(Name, AssocItemId)> { | ||
304 | let mut res = Vec::new(); | ||
305 | |||
306 | // We set a limit to protect against infinite recursion | ||
307 | let limit = 100; | ||
308 | |||
309 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
310 | res.extend(collect_items_in_macro(db, expander, m, container, limit)) | ||
311 | } | 203 | } |
312 | |||
313 | res | ||
314 | } | 204 | } |
315 | 205 | ||
316 | fn collect_items_in_macro( | 206 | fn collect_items( |
317 | db: &dyn DefDatabase, | 207 | db: &dyn DefDatabase, |
208 | module: ModuleId, | ||
318 | expander: &mut Expander, | 209 | expander: &mut Expander, |
319 | m: ast::MacroCall, | 210 | assoc_items: impl Iterator<Item = AssocItem>, |
211 | file_id: crate::HirFileId, | ||
320 | container: AssocContainerId, | 212 | container: AssocContainerId, |
321 | limit: usize, | 213 | limit: usize, |
322 | ) -> Vec<(Name, AssocItemId)> { | 214 | ) -> Vec<(Name, AssocItemId)> { |
@@ -324,62 +216,62 @@ fn collect_items_in_macro( | |||
324 | return Vec::new(); | 216 | return Vec::new(); |
325 | } | 217 | } |
326 | 218 | ||
327 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { | 219 | let item_tree = db.item_tree(file_id); |
328 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 220 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); |
329 | let mut res = collect_items( | 221 | |
330 | db, | 222 | let mut items = Vec::new(); |
331 | expander, | 223 | for item in assoc_items { |
332 | items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), | 224 | match item { |
333 | items.file_id, | 225 | AssocItem::Function(id) => { |
334 | container, | 226 | let item = &item_tree[id]; |
335 | ); | 227 | let attrs = item_tree.attrs(ModItem::from(id).into()); |
336 | 228 | if !attrs.is_cfg_enabled(&cfg_options) { | |
337 | // Recursive collect macros | 229 | continue; |
338 | // Note that ast::ModuleItem do not include ast::MacroCall | ||
339 | // We cannot use ModuleItemOwner::items here | ||
340 | for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
341 | res.extend(collect_items_in_macro(db, expander, it, container, limit - 1)) | ||
342 | } | ||
343 | expander.exit(db, mark); | ||
344 | res | ||
345 | } else { | ||
346 | Vec::new() | ||
347 | } | ||
348 | } | ||
349 | |||
350 | fn collect_items( | ||
351 | db: &dyn DefDatabase, | ||
352 | expander: &mut Expander, | ||
353 | assoc_items: impl Iterator<Item = AssocItem>, | ||
354 | file_id: crate::HirFileId, | ||
355 | container: AssocContainerId, | ||
356 | ) -> Vec<(Name, AssocItemId)> { | ||
357 | let items = db.ast_id_map(file_id); | ||
358 | |||
359 | assoc_items | ||
360 | .filter_map(|item_node| match item_node { | ||
361 | ast::AssocItem::FnDef(it) => { | ||
362 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | ||
363 | if !expander.is_cfg_enabled(&it) { | ||
364 | return None; | ||
365 | } | 230 | } |
366 | let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 231 | let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
367 | .intern(db); | 232 | items.push((item.name.clone(), def.into())); |
368 | Some((name, def.into())) | ||
369 | } | 233 | } |
370 | ast::AssocItem::ConstDef(it) => { | 234 | // FIXME: cfg? |
371 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 235 | AssocItem::Const(id) => { |
372 | let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 236 | let item = &item_tree[id]; |
373 | .intern(db); | 237 | let name = match item.name.clone() { |
374 | Some((name, def.into())) | 238 | Some(name) => name, |
239 | None => continue, | ||
240 | }; | ||
241 | let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); | ||
242 | items.push((name, def.into())); | ||
375 | } | 243 | } |
376 | ast::AssocItem::TypeAliasDef(it) => { | 244 | AssocItem::TypeAlias(id) => { |
377 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 245 | let item = &item_tree[id]; |
378 | let def = | 246 | let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db); |
379 | TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } | 247 | items.push((item.name.clone(), def.into())); |
380 | .intern(db); | ||
381 | Some((name, def.into())) | ||
382 | } | 248 | } |
383 | }) | 249 | AssocItem::MacroCall(call) => { |
384 | .collect() | 250 | let call = &item_tree[call]; |
251 | let ast_id_map = db.ast_id_map(file_id); | ||
252 | let root = db.parse_or_expand(file_id).unwrap(); | ||
253 | let call = ast_id_map.get(call.ast_id).to_node(&root); | ||
254 | |||
255 | if let Some((mark, mac)) = expander.enter_expand(db, None, call) { | ||
256 | let src: InFile<ast::MacroItems> = expander.to_source(mac); | ||
257 | let item_tree = db.item_tree(src.file_id); | ||
258 | let iter = | ||
259 | item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); | ||
260 | items.extend(collect_items( | ||
261 | db, | ||
262 | module, | ||
263 | expander, | ||
264 | iter, | ||
265 | src.file_id, | ||
266 | container, | ||
267 | limit - 1, | ||
268 | )); | ||
269 | |||
270 | expander.exit(db, mark); | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | items | ||
385 | } | 277 | } |