diff options
Diffstat (limited to 'crates/ra_hir_def/src/nameres/collector.rs')
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 105 |
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 | ||
39 | const GLOB_RECURSION_LIMIT: usize = 100; | ||
40 | const EXPANSION_DEPTH_LIMIT: usize = 128; | ||
41 | const FIXED_POINT_LIMIT: usize = 8192; | ||
42 | |||
39 | pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 43 | pub(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)] |
167 | struct DeriveDirective { | 171 | struct 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 | ||
172 | struct DefData<'a> { | 176 | struct 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 { |