|
1 | 1 | //! Contains basic data about various HIR declarations.
|
2 | 2 |
|
3 |
| -use std::sync::Arc; |
| 3 | +use std::{mem, sync::Arc}; |
4 | 4 |
|
5 |
| -use hir_expand::{name::Name, AstId, ExpandResult, InFile, MacroCallId}; |
| 5 | +use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId}; |
6 | 6 | use syntax::ast;
|
7 | 7 |
|
8 | 8 | use crate::{
|
9 | 9 | attr::Attrs,
|
10 | 10 | body::{Expander, Mark},
|
11 | 11 | db::DefDatabase,
|
12 | 12 | intern::Interned,
|
13 |
| - item_tree::{self, AssocItem, FnFlags, ItemTreeId, ModItem, Param}, |
14 |
| - nameres::attr_resolution::ResolvedAttr, |
| 13 | + item_tree::{self, AssocItem, FnFlags, ItemTreeId, ModItem, Param, TreeId}, |
| 14 | + nameres::{attr_resolution::ResolvedAttr, DefMap}, |
15 | 15 | type_ref::{TraitRef, TypeBound, TypeRef},
|
16 | 16 | visibility::RawVisibility,
|
17 | 17 | AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
|
@@ -201,25 +201,28 @@ impl TraitData {
|
201 | 201 | let is_auto = tr_def.is_auto;
|
202 | 202 | let is_unsafe = tr_def.is_unsafe;
|
203 | 203 | let module_id = tr_loc.container;
|
204 |
| - let container = ItemContainerId::TraitId(tr); |
205 | 204 | let visibility = item_tree[tr_def.visibility].clone();
|
206 |
| - let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); |
207 | 205 | let skip_array_during_method_dispatch = item_tree
|
208 | 206 | .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
|
209 | 207 | .by_key("rustc_skip_array_during_method_dispatch")
|
210 | 208 | .exists();
|
211 | 209 |
|
212 |
| - let (items, attribute_calls) = |
213 |
| - do_collect(db, module_id, &mut expander, &tr_def.items, tr_loc.id.tree_id(), container); |
| 210 | + let mut collector = AssocItemCollector::new( |
| 211 | + db, |
| 212 | + module_id, |
| 213 | + tr_loc.id.file_id(), |
| 214 | + ItemContainerId::TraitId(tr), |
| 215 | + ); |
| 216 | + collector.collect(tr_loc.id.tree_id(), &tr_def.items); |
214 | 217 |
|
215 | 218 | Arc::new(TraitData {
|
216 | 219 | name,
|
217 |
| - items, |
| 220 | + attribute_calls: collector.take_attr_calls(), |
| 221 | + items: collector.items, |
218 | 222 | is_auto,
|
219 | 223 | is_unsafe,
|
220 | 224 | visibility,
|
221 | 225 | skip_array_during_method_dispatch,
|
222 |
| - attribute_calls, |
223 | 226 | })
|
224 | 227 | }
|
225 | 228 |
|
@@ -270,18 +273,17 @@ impl ImplData {
|
270 | 273 | let self_ty = impl_def.self_ty.clone();
|
271 | 274 | let is_negative = impl_def.is_negative;
|
272 | 275 | let module_id = impl_loc.container;
|
273 |
| - let container = ItemContainerId::ImplId(id); |
274 |
| - let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id); |
275 | 276 |
|
276 |
| - let (items, attribute_calls) = do_collect( |
| 277 | + let mut collector = AssocItemCollector::new( |
277 | 278 | db,
|
278 | 279 | module_id,
|
279 |
| - &mut expander, |
280 |
| - &impl_def.items, |
281 |
| - impl_loc.id.tree_id(), |
282 |
| - container, |
| 280 | + impl_loc.id.file_id(), |
| 281 | + ItemContainerId::ImplId(id), |
283 | 282 | );
|
284 |
| - let items = items.into_iter().map(|(_, item)| item).collect(); |
| 283 | + collector.collect(impl_loc.id.tree_id(), &impl_def.items); |
| 284 | + |
| 285 | + let attribute_calls = collector.take_attr_calls(); |
| 286 | + let items = collector.items.into_iter().map(|(_, item)| item).collect(); |
285 | 287 |
|
286 | 288 | Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls })
|
287 | 289 | }
|
@@ -338,120 +340,128 @@ impl StaticData {
|
338 | 340 | }
|
339 | 341 | }
|
340 | 342 |
|
341 |
| -fn do_collect( |
342 |
| - db: &dyn DefDatabase, |
| 343 | +struct AssocItemCollector<'a> { |
| 344 | + db: &'a dyn DefDatabase, |
343 | 345 | module_id: ModuleId,
|
344 |
| - expander: &mut Expander, |
345 |
| - assoc_items: &[AssocItem], |
346 |
| - tree_id: item_tree::TreeId, |
| 346 | + def_map: Arc<DefMap>, |
347 | 347 | container: ItemContainerId,
|
348 |
| -) -> (Vec<(Name, AssocItemId)>, Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>) { |
349 |
| - let mut items = Vec::new(); |
350 |
| - let mut attribute_calls = Vec::new(); |
351 |
| - |
352 |
| - collect_items( |
353 |
| - db, |
354 |
| - &mut items, |
355 |
| - &mut attribute_calls, |
356 |
| - module_id, |
357 |
| - expander, |
358 |
| - assoc_items.iter().copied(), |
359 |
| - tree_id, |
360 |
| - container, |
361 |
| - ); |
362 |
| - |
363 |
| - let attribute_calls = |
364 |
| - if attribute_calls.is_empty() { None } else { Some(Box::new(attribute_calls)) }; |
365 |
| - (items, attribute_calls) |
| 348 | + expander: Expander, |
| 349 | + |
| 350 | + items: Vec<(Name, AssocItemId)>, |
| 351 | + attr_calls: Vec<(AstId<ast::Item>, MacroCallId)>, |
366 | 352 | }
|
367 | 353 |
|
368 |
| -fn collect_items( |
369 |
| - db: &dyn DefDatabase, |
370 |
| - items: &mut Vec<(Name, AssocItemId)>, |
371 |
| - attr_calls: &mut Vec<(AstId<ast::Item>, MacroCallId)>, |
372 |
| - module: ModuleId, |
373 |
| - expander: &mut Expander, |
374 |
| - assoc_items: impl Iterator<Item = AssocItem>, |
375 |
| - tree_id: item_tree::TreeId, |
376 |
| - container: ItemContainerId, |
377 |
| -) { |
378 |
| - let item_tree = tree_id.item_tree(db); |
379 |
| - let crate_graph = db.crate_graph(); |
380 |
| - let cfg_options = &crate_graph[module.krate].cfg_options; |
381 |
| - let def_map = module.def_map(db); |
382 |
| - |
383 |
| - 'items: for item in assoc_items { |
384 |
| - let attrs = item_tree.attrs(db, module.krate, ModItem::from(item).into()); |
385 |
| - if !attrs.is_cfg_enabled(cfg_options) { |
386 |
| - continue; |
| 354 | +impl<'a> AssocItemCollector<'a> { |
| 355 | + fn new( |
| 356 | + db: &'a dyn DefDatabase, |
| 357 | + module_id: ModuleId, |
| 358 | + file_id: HirFileId, |
| 359 | + container: ItemContainerId, |
| 360 | + ) -> Self { |
| 361 | + Self { |
| 362 | + db, |
| 363 | + module_id, |
| 364 | + def_map: module_id.def_map(db), |
| 365 | + container, |
| 366 | + expander: Expander::new(db, file_id, module_id), |
| 367 | + |
| 368 | + items: Vec::new(), |
| 369 | + attr_calls: Vec::new(), |
387 | 370 | }
|
| 371 | + } |
388 | 372 |
|
389 |
| - for attr in &*attrs { |
390 |
| - let ast_id = AstId::new(expander.current_file_id(), item.ast_id(&item_tree).upcast()); |
391 |
| - let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id }; |
392 |
| - |
393 |
| - if let Ok(ResolvedAttr::Macro(call_id)) = |
394 |
| - def_map.resolve_attr_macro(db, module.local_id, ast_id_with_path, attr) |
395 |
| - { |
396 |
| - attr_calls.push((ast_id, call_id)); |
397 |
| - let res = expander.enter_expand_id(db, call_id); |
398 |
| - collect_macro_items(db, items, attr_calls, module, expander, container, res); |
399 |
| - continue 'items; |
400 |
| - } |
| 373 | + fn take_attr_calls(&mut self) -> Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>> { |
| 374 | + let attribute_calls = mem::take(&mut self.attr_calls); |
| 375 | + if attribute_calls.is_empty() { |
| 376 | + None |
| 377 | + } else { |
| 378 | + Some(Box::new(attribute_calls)) |
401 | 379 | }
|
| 380 | + } |
402 | 381 |
|
403 |
| - match item { |
404 |
| - AssocItem::Function(id) => { |
405 |
| - let item = &item_tree[id]; |
406 |
| - let def = FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(db); |
407 |
| - items.push((item.name.clone(), def.into())); |
408 |
| - } |
409 |
| - AssocItem::Const(id) => { |
410 |
| - let item = &item_tree[id]; |
411 |
| - let name = match item.name.clone() { |
412 |
| - Some(name) => name, |
413 |
| - None => continue, |
414 |
| - }; |
415 |
| - let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(db); |
416 |
| - items.push((name, def.into())); |
| 382 | + fn collect(&mut self, tree_id: TreeId, assoc_items: &[AssocItem]) { |
| 383 | + let item_tree = tree_id.item_tree(self.db); |
| 384 | + |
| 385 | + 'items: for &item in assoc_items { |
| 386 | + let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into()); |
| 387 | + if !attrs.is_cfg_enabled(self.expander.cfg_options()) { |
| 388 | + continue; |
417 | 389 | }
|
418 |
| - AssocItem::TypeAlias(id) => { |
419 |
| - let item = &item_tree[id]; |
420 |
| - let def = TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(db); |
421 |
| - items.push((item.name.clone(), def.into())); |
| 390 | + |
| 391 | + for attr in &*attrs { |
| 392 | + let ast_id = |
| 393 | + AstId::new(self.expander.current_file_id(), item.ast_id(&item_tree).upcast()); |
| 394 | + let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id }; |
| 395 | + |
| 396 | + if let Ok(ResolvedAttr::Macro(call_id)) = self.def_map.resolve_attr_macro( |
| 397 | + self.db, |
| 398 | + self.module_id.local_id, |
| 399 | + ast_id_with_path, |
| 400 | + attr, |
| 401 | + ) { |
| 402 | + self.attr_calls.push((ast_id, call_id)); |
| 403 | + let res = self.expander.enter_expand_id(self.db, call_id); |
| 404 | + self.collect_macro_items(res); |
| 405 | + continue 'items; |
| 406 | + } |
422 | 407 | }
|
423 |
| - AssocItem::MacroCall(call) => { |
424 |
| - let call = &item_tree[call]; |
425 |
| - let ast_id_map = db.ast_id_map(tree_id.file_id()); |
426 |
| - let root = db.parse_or_expand(tree_id.file_id()).unwrap(); |
427 |
| - let call = ast_id_map.get(call.ast_id).to_node(&root); |
428 |
| - let _cx = stdx::panic_context::enter(format!("collect_items MacroCall: {}", call)); |
429 |
| - let res = expander.enter_expand(db, call); |
430 |
| - |
431 |
| - if let Ok(res) = res { |
432 |
| - collect_macro_items(db, items, attr_calls, module, expander, container, res); |
| 408 | + |
| 409 | + match item { |
| 410 | + AssocItem::Function(id) => { |
| 411 | + let item = &item_tree[id]; |
| 412 | + let def = |
| 413 | + FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } |
| 414 | + .intern(self.db); |
| 415 | + self.items.push((item.name.clone(), def.into())); |
| 416 | + } |
| 417 | + AssocItem::Const(id) => { |
| 418 | + let item = &item_tree[id]; |
| 419 | + let name = match item.name.clone() { |
| 420 | + Some(name) => name, |
| 421 | + None => continue, |
| 422 | + }; |
| 423 | + let def = |
| 424 | + ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } |
| 425 | + .intern(self.db); |
| 426 | + self.items.push((name, def.into())); |
| 427 | + } |
| 428 | + AssocItem::TypeAlias(id) => { |
| 429 | + let item = &item_tree[id]; |
| 430 | + let def = TypeAliasLoc { |
| 431 | + container: self.container, |
| 432 | + id: ItemTreeId::new(tree_id, id), |
| 433 | + } |
| 434 | + .intern(self.db); |
| 435 | + self.items.push((item.name.clone(), def.into())); |
| 436 | + } |
| 437 | + AssocItem::MacroCall(call) => { |
| 438 | + let call = &item_tree[call]; |
| 439 | + let ast_id_map = self.db.ast_id_map(self.expander.current_file_id()); |
| 440 | + let root = self.db.parse_or_expand(self.expander.current_file_id()).unwrap(); |
| 441 | + let call = ast_id_map.get(call.ast_id).to_node(&root); |
| 442 | + let _cx = |
| 443 | + stdx::panic_context::enter(format!("collect_items MacroCall: {}", call)); |
| 444 | + let res = self.expander.enter_expand(self.db, call); |
| 445 | + |
| 446 | + if let Ok(res) = res { |
| 447 | + self.collect_macro_items(res); |
| 448 | + } |
433 | 449 | }
|
434 | 450 | }
|
435 | 451 | }
|
436 | 452 | }
|
437 |
| -} |
438 | 453 |
|
439 |
| -fn collect_macro_items( |
440 |
| - db: &dyn DefDatabase, |
441 |
| - items: &mut Vec<(Name, AssocItemId)>, |
442 |
| - attr_calls: &mut Vec<(AstId<ast::Item>, MacroCallId)>, |
443 |
| - module: ModuleId, |
444 |
| - expander: &mut Expander, |
445 |
| - container: ItemContainerId, |
446 |
| - res: ExpandResult<Option<(Mark, ast::MacroItems)>>, |
447 |
| -) { |
448 |
| - if let Some((mark, mac)) = res.value { |
449 |
| - let src: InFile<ast::MacroItems> = expander.to_source(mac); |
450 |
| - let tree_id = item_tree::TreeId::new(src.file_id, None); |
451 |
| - let item_tree = tree_id.item_tree(db); |
452 |
| - let iter = item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); |
453 |
| - collect_items(db, items, attr_calls, module, expander, iter, tree_id, container); |
454 |
| - |
455 |
| - expander.exit(db, mark); |
| 454 | + fn collect_macro_items(&mut self, res: ExpandResult<Option<(Mark, ast::MacroItems)>>) { |
| 455 | + if let Some((mark, mac)) = res.value { |
| 456 | + let src: InFile<ast::MacroItems> = self.expander.to_source(mac); |
| 457 | + let tree_id = item_tree::TreeId::new(src.file_id, None); |
| 458 | + let item_tree = tree_id.item_tree(self.db); |
| 459 | + let iter: Vec<_> = |
| 460 | + item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item).collect(); |
| 461 | + |
| 462 | + self.collect(tree_id, &iter); |
| 463 | + |
| 464 | + self.expander.exit(self.db, mark); |
| 465 | + } |
456 | 466 | }
|
457 | 467 | }
|
0 commit comments