aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres/collector.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/nameres/collector.rs')
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs105
1 files changed, 74 insertions, 31 deletions
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index a35ac1024..28b7a20c5 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -36,6 +36,10 @@ use crate::{
36 TraitLoc, TypeAliasLoc, UnionLoc, 36 TraitLoc, TypeAliasLoc, UnionLoc,
37}; 37};
38 38
39const GLOB_RECURSION_LIMIT: usize = 100;
40const EXPANSION_DEPTH_LIMIT: usize = 128;
41const FIXED_POINT_LIMIT: usize = 8192;
42
39pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 43pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
40 let crate_graph = db.crate_graph(); 44 let crate_graph = db.crate_graph();
41 45
@@ -166,7 +170,7 @@ struct MacroDirective {
166#[derive(Clone, Debug, Eq, PartialEq)] 170#[derive(Clone, Debug, Eq, PartialEq)]
167struct DeriveDirective { 171struct DeriveDirective {
168 module_id: LocalModuleId, 172 module_id: LocalModuleId,
169 ast_id: AstIdWithPath<ast::ModuleItem>, 173 ast_id: AstIdWithPath<ast::Item>,
170} 174}
171 175
172struct DefData<'a> { 176struct DefData<'a> {
@@ -217,7 +221,7 @@ impl DefCollector<'_> {
217 ReachedFixedPoint::Yes => break, 221 ReachedFixedPoint::Yes => break,
218 ReachedFixedPoint::No => i += 1, 222 ReachedFixedPoint::No => i += 1,
219 } 223 }
220 if i == 10000 { 224 if i == FIXED_POINT_LIMIT {
221 log::error!("name resolution is stuck"); 225 log::error!("name resolution is stuck");
222 break; 226 break;
223 } 227 }
@@ -306,7 +310,7 @@ impl DefCollector<'_> {
306 if export { 310 if export {
307 self.update( 311 self.update(
308 self.def_map.root, 312 self.def_map.root,
309 &[(name, PerNs::macros(macro_, Visibility::Public))], 313 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
310 Visibility::Public, 314 Visibility::Public,
311 ImportType::Named, 315 ImportType::Named,
312 ); 316 );
@@ -332,7 +336,7 @@ impl DefCollector<'_> {
332 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { 336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
333 self.update( 337 self.update(
334 self.def_map.root, 338 self.def_map.root,
335 &[(name, PerNs::macros(macro_, Visibility::Public))], 339 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
336 Visibility::Public, 340 Visibility::Public,
337 ImportType::Named, 341 ImportType::Named,
338 ); 342 );
@@ -530,7 +534,7 @@ impl DefCollector<'_> {
530 let name = variant_data.name.clone(); 534 let name = variant_data.name.clone();
531 let variant = EnumVariantId { parent: e, local_id }; 535 let variant = EnumVariantId { parent: e, local_id };
532 let res = PerNs::both(variant.into(), variant.into(), vis); 536 let res = PerNs::both(variant.into(), variant.into(), vis);
533 (name, res) 537 (Some(name), res)
534 }) 538 })
535 .collect::<Vec<_>>(); 539 .collect::<Vec<_>>();
536 self.update(module_id, &resolutions, vis, ImportType::Glob); 540 self.update(module_id, &resolutions, vis, ImportType::Glob);
@@ -546,15 +550,15 @@ impl DefCollector<'_> {
546 match import.path.segments.last() { 550 match import.path.segments.last() {
547 Some(last_segment) => { 551 Some(last_segment) => {
548 let name = match &import.alias { 552 let name = match &import.alias {
549 Some(ImportAlias::Alias(name)) => name.clone(), 553 Some(ImportAlias::Alias(name)) => Some(name.clone()),
550 Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736 554 Some(ImportAlias::Underscore) => None,
551 None => last_segment.clone(), 555 None => Some(last_segment.clone()),
552 }; 556 };
553 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
554 558
555 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
556 if import.is_extern_crate && module_id == self.def_map.root { 560 if import.is_extern_crate && module_id == self.def_map.root {
557 if let Some(def) = def.take_types() { 561 if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
558 self.def_map.extern_prelude.insert(name.clone(), def); 562 self.def_map.extern_prelude.insert(name.clone(), def);
559 } 563 }
560 } 564 }
@@ -569,36 +573,73 @@ impl DefCollector<'_> {
569 fn update( 573 fn update(
570 &mut self, 574 &mut self,
571 module_id: LocalModuleId, 575 module_id: LocalModuleId,
572 resolutions: &[(Name, PerNs)], 576 resolutions: &[(Option<Name>, PerNs)],
573 vis: Visibility, 577 vis: Visibility,
574 import_type: ImportType, 578 import_type: ImportType,
575 ) { 579 ) {
580 self.db.check_canceled();
576 self.update_recursive(module_id, resolutions, vis, import_type, 0) 581 self.update_recursive(module_id, resolutions, vis, import_type, 0)
577 } 582 }
578 583
579 fn update_recursive( 584 fn update_recursive(
580 &mut self, 585 &mut self,
581 module_id: LocalModuleId, 586 module_id: LocalModuleId,
582 resolutions: &[(Name, PerNs)], 587 resolutions: &[(Option<Name>, PerNs)],
583 // All resolutions are imported with this visibility; the visibilies in 588 // All resolutions are imported with this visibility; the visibilies in
584 // the `PerNs` values are ignored and overwritten 589 // the `PerNs` values are ignored and overwritten
585 vis: Visibility, 590 vis: Visibility,
586 import_type: ImportType, 591 import_type: ImportType,
587 depth: usize, 592 depth: usize,
588 ) { 593 ) {
589 if depth > 100 { 594 if depth > GLOB_RECURSION_LIMIT {
590 // prevent stack overflows (but this shouldn't be possible) 595 // prevent stack overflows (but this shouldn't be possible)
591 panic!("infinite recursion in glob imports!"); 596 panic!("infinite recursion in glob imports!");
592 } 597 }
593 let scope = &mut self.def_map.modules[module_id].scope;
594 let mut changed = false; 598 let mut changed = false;
599
595 for (name, res) in resolutions { 600 for (name, res) in resolutions {
596 changed |= scope.push_res_with_import( 601 match name {
597 &mut self.from_glob_import, 602 Some(name) => {
598 (module_id, name.clone()), 603 let scope = &mut self.def_map.modules[module_id].scope;
599 res.with_visibility(vis), 604 changed |= scope.push_res_with_import(
600 import_type, 605 &mut self.from_glob_import,
601 ); 606 (module_id, name.clone()),
607 res.with_visibility(vis),
608 import_type,
609 );
610 }
611 None => {
612 let tr = match res.take_types() {
613 Some(ModuleDefId::TraitId(tr)) => tr,
614 Some(other) => {
615 log::debug!("non-trait `_` import of {:?}", other);
616 continue;
617 }
618 None => continue,
619 };
620 let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
621 let should_update = match old_vis {
622 None => true,
623 Some(old_vis) => {
624 let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
625 panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
626 });
627
628 if max_vis == old_vis {
629 false
630 } else {
631 mark::hit!(upgrade_underscore_visibility);
632 true
633 }
634 }
635 };
636
637 if should_update {
638 changed = true;
639 self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
640 }
641 }
642 }
602 } 643 }
603 644
604 if !changed { 645 if !changed {
@@ -609,14 +650,15 @@ impl DefCollector<'_> {
609 .get(&module_id) 650 .get(&module_id)
610 .into_iter() 651 .into_iter()
611 .flat_map(|v| v.iter()) 652 .flat_map(|v| v.iter())
653 .filter(|(glob_importing_module, _)| {
654 // we know all resolutions have the same visibility (`vis`), so we
655 // just need to check that once
656 vis.is_visible_from_def_map(&self.def_map, *glob_importing_module)
657 })
612 .cloned() 658 .cloned()
613 .collect::<Vec<_>>(); 659 .collect::<Vec<_>>();
660
614 for (glob_importing_module, glob_import_vis) in glob_imports { 661 for (glob_importing_module, glob_import_vis) in glob_imports {
615 // we know all resolutions have the same visibility (`vis`), so we
616 // just need to check that once
617 if !vis.is_visible_from_def_map(&self.def_map, glob_importing_module) {
618 continue;
619 }
620 self.update_recursive( 662 self.update_recursive(
621 glob_importing_module, 663 glob_importing_module,
622 resolutions, 664 resolutions,
@@ -677,10 +719,6 @@ impl DefCollector<'_> {
677 self.unexpanded_attribute_macros = attribute_macros; 719 self.unexpanded_attribute_macros = attribute_macros;
678 720
679 for (module_id, macro_call_id, depth) in resolved { 721 for (module_id, macro_call_id, depth) in resolved {
680 if depth > 1024 {
681 log::debug!("Max macro expansion depth reached");
682 continue;
683 }
684 self.collect_macro_expansion(module_id, macro_call_id, depth); 722 self.collect_macro_expansion(module_id, macro_call_id, depth);
685 } 723 }
686 724
@@ -717,6 +755,11 @@ impl DefCollector<'_> {
717 macro_call_id: MacroCallId, 755 macro_call_id: MacroCallId,
718 depth: usize, 756 depth: usize,
719 ) { 757 ) {
758 if depth > EXPANSION_DEPTH_LIMIT {
759 mark::hit!(macro_expansion_overflow);
760 log::warn!("macro expansion is too deep");
761 return;
762 }
720 let file_id: HirFileId = macro_call_id.as_file(); 763 let file_id: HirFileId = macro_call_id.as_file();
721 let item_tree = self.db.item_tree(file_id); 764 let item_tree = self.db.item_tree(file_id);
722 let mod_dir = self.mod_dirs[&module_id].clone(); 765 let mod_dir = self.mod_dirs[&module_id].clone();
@@ -943,7 +986,7 @@ impl ModCollector<'_, '_> {
943 .unwrap_or(Visibility::Public); 986 .unwrap_or(Visibility::Public);
944 self.def_collector.update( 987 self.def_collector.update(
945 self.module_id, 988 self.module_id,
946 &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], 989 &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
947 vis, 990 vis,
948 ImportType::Named, 991 ImportType::Named,
949 ) 992 )
@@ -1050,14 +1093,14 @@ impl ModCollector<'_, '_> {
1050 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 1093 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
1051 self.def_collector.update( 1094 self.def_collector.update(
1052 self.module_id, 1095 self.module_id,
1053 &[(name, PerNs::from_def(def, vis, false))], 1096 &[(Some(name), PerNs::from_def(def, vis, false))],
1054 vis, 1097 vis,
1055 ImportType::Named, 1098 ImportType::Named,
1056 ); 1099 );
1057 res 1100 res
1058 } 1101 }
1059 1102
1060 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::ModuleItem>) { 1103 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
1061 for derive_subtree in attrs.by_key("derive").tt_values() { 1104 for derive_subtree in attrs.by_key("derive").tt_values() {
1062 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree 1105 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
1063 for tt in &derive_subtree.token_trees { 1106 for tt in &derive_subtree.token_trees {