diff options
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 56 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/mod_resolution.rs | 87 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 403 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/mod_resolution.rs | 2 |
4 files changed, 29 insertions, 519 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index b5fe16bfa..ee0a4c99f 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,5 +1,10 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir_def::{ | ||
4 | attr::Attr, | ||
5 | nameres::{mod_resolution::ModDir, raw}, | ||
6 | }; | ||
7 | use hir_expand::name; | ||
3 | use ra_cfg::CfgOptions; | 8 | use ra_cfg::CfgOptions; |
4 | use ra_db::FileId; | 9 | use ra_db::FileId; |
5 | use ra_syntax::{ast, SmolStr}; | 10 | use ra_syntax::{ast, SmolStr}; |
@@ -7,13 +12,11 @@ use rustc_hash::FxHashMap; | |||
7 | use test_utils::tested_by; | 12 | use test_utils::tested_by; |
8 | 13 | ||
9 | use crate::{ | 14 | use crate::{ |
10 | attr::Attr, | ||
11 | db::DefDatabase, | 15 | db::DefDatabase, |
12 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, | 16 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, |
13 | name::MACRO_RULES, | ||
14 | nameres::{ | 17 | nameres::{ |
15 | diagnostics::DefDiagnostic, mod_resolution::ModDir, raw, Crate, CrateDefMap, CrateModuleId, | 18 | diagnostics::DefDiagnostic, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, |
16 | ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, | 19 | PerNs, ReachedFixedPoint, Resolution, ResolveMode, |
17 | }, | 20 | }, |
18 | Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, | 21 | Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, |
19 | Struct, Trait, TypeAlias, Union, | 22 | Struct, Trait, TypeAlias, Union, |
@@ -212,7 +215,7 @@ where | |||
212 | 215 | ||
213 | if let Some(ModuleDef::Module(m)) = res.take_types() { | 216 | if let Some(ModuleDef::Module(m)) = res.take_types() { |
214 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | 217 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); |
215 | self.import_all_macros_exported(current_module_id, m.krate); | 218 | self.import_all_macros_exported(current_module_id, m.krate()); |
216 | } | 219 | } |
217 | } | 220 | } |
218 | 221 | ||
@@ -289,11 +292,11 @@ where | |||
289 | if import.is_prelude { | 292 | if import.is_prelude { |
290 | tested_by!(std_prelude); | 293 | tested_by!(std_prelude); |
291 | self.def_map.prelude = Some(m); | 294 | self.def_map.prelude = Some(m); |
292 | } else if m.krate != self.def_map.krate { | 295 | } else if m.krate() != self.def_map.krate { |
293 | tested_by!(glob_across_crates); | 296 | tested_by!(glob_across_crates); |
294 | // glob import from other crate => we can just import everything once | 297 | // glob import from other crate => we can just import everything once |
295 | let item_map = self.db.crate_def_map(m.krate); | 298 | let item_map = self.db.crate_def_map(m.krate()); |
296 | let scope = &item_map[m.module_id].scope; | 299 | let scope = &item_map[m.id.module_id].scope; |
297 | 300 | ||
298 | // Module scoped macros is included | 301 | // Module scoped macros is included |
299 | let items = scope | 302 | let items = scope |
@@ -307,7 +310,7 @@ where | |||
307 | // glob import from same crate => we do an initial | 310 | // glob import from same crate => we do an initial |
308 | // import, and then need to propagate any further | 311 | // import, and then need to propagate any further |
309 | // additions | 312 | // additions |
310 | let scope = &self.def_map[m.module_id].scope; | 313 | let scope = &self.def_map[m.id.module_id].scope; |
311 | 314 | ||
312 | // Module scoped macros is included | 315 | // Module scoped macros is included |
313 | let items = scope | 316 | let items = scope |
@@ -319,7 +322,7 @@ where | |||
319 | self.update(module_id, Some(import_id), &items); | 322 | self.update(module_id, Some(import_id), &items); |
320 | // record the glob import in case we add further items | 323 | // record the glob import in case we add further items |
321 | self.glob_imports | 324 | self.glob_imports |
322 | .entry(m.module_id) | 325 | .entry(m.id.module_id) |
323 | .or_default() | 326 | .or_default() |
324 | .push((module_id, import_id)); | 327 | .push((module_id, import_id)); |
325 | } | 328 | } |
@@ -448,7 +451,7 @@ where | |||
448 | ); | 451 | ); |
449 | 452 | ||
450 | if let Some(def) = resolved_res.resolved_def.get_macros() { | 453 | if let Some(def) = resolved_res.resolved_def.get_macros() { |
451 | let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); | 454 | let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id }); |
452 | resolved.push((*module_id, call_id, def.id)); | 455 | resolved.push((*module_id, call_id, def.id)); |
453 | res = ReachedFixedPoint::No; | 456 | res = ReachedFixedPoint::No; |
454 | return false; | 457 | return false; |
@@ -523,9 +526,10 @@ where | |||
523 | 526 | ||
524 | // Prelude module is always considered to be `#[macro_use]`. | 527 | // Prelude module is always considered to be `#[macro_use]`. |
525 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 528 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
526 | if prelude_module.krate != self.def_collector.def_map.krate { | 529 | if prelude_module.krate() != self.def_collector.def_map.krate { |
527 | tested_by!(prelude_is_macro_use); | 530 | tested_by!(prelude_is_macro_use); |
528 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); | 531 | self.def_collector |
532 | .import_all_macros_exported(self.module_id, prelude_module.krate()); | ||
529 | } | 533 | } |
530 | } | 534 | } |
531 | 535 | ||
@@ -567,7 +571,7 @@ where | |||
567 | // inline module, just recurse | 571 | // inline module, just recurse |
568 | raw::ModuleData::Definition { name, items, ast_id } => { | 572 | raw::ModuleData::Definition { name, items, ast_id } => { |
569 | let module_id = | 573 | let module_id = |
570 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); | 574 | self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None); |
571 | 575 | ||
572 | ModCollector { | 576 | ModCollector { |
573 | def_collector: &mut *self.def_collector, | 577 | def_collector: &mut *self.def_collector, |
@@ -583,7 +587,7 @@ where | |||
583 | } | 587 | } |
584 | // out of line module, resolve, parse and recurse | 588 | // out of line module, resolve, parse and recurse |
585 | raw::ModuleData::Declaration { name, ast_id } => { | 589 | raw::ModuleData::Declaration { name, ast_id } => { |
586 | let ast_id = ast_id.with_file_id(self.file_id); | 590 | let ast_id = AstId::new(self.file_id, *ast_id); |
587 | match self.mod_dir.resolve_declaration( | 591 | match self.mod_dir.resolve_declaration( |
588 | self.def_collector.db, | 592 | self.def_collector.db, |
589 | self.file_id, | 593 | self.file_id, |
@@ -631,9 +635,7 @@ where | |||
631 | modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); | 635 | modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); |
632 | modules[self.module_id].children.insert(name.clone(), res); | 636 | modules[self.module_id].children.insert(name.clone(), res); |
633 | let resolution = Resolution { | 637 | let resolution = Resolution { |
634 | def: PerNs::types( | 638 | def: PerNs::types(Module::new(self.def_collector.def_map.krate, res).into()), |
635 | Module { krate: self.def_collector.def_map.krate, module_id: res }.into(), | ||
636 | ), | ||
637 | import: None, | 639 | import: None, |
638 | }; | 640 | }; |
639 | self.def_collector.update(self.module_id, None, &[(name, resolution)]); | 641 | self.def_collector.update(self.module_id, None, &[(name, resolution)]); |
@@ -641,8 +643,8 @@ where | |||
641 | } | 643 | } |
642 | 644 | ||
643 | fn define_def(&mut self, def: &raw::DefData) { | 645 | fn define_def(&mut self, def: &raw::DefData) { |
644 | let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }; | 646 | let module = Module::new(self.def_collector.def_map.krate, self.module_id); |
645 | let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); | 647 | let ctx = LocationCtx::new(self.def_collector.db, module.id, self.file_id); |
646 | 648 | ||
647 | macro_rules! def { | 649 | macro_rules! def { |
648 | ($kind:ident, $ast_id:ident) => { | 650 | ($kind:ident, $ast_id:ident) => { |
@@ -671,28 +673,26 @@ where | |||
671 | } | 673 | } |
672 | 674 | ||
673 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 675 | fn collect_macro(&mut self, mac: &raw::MacroData) { |
676 | let ast_id = AstId::new(self.file_id, mac.ast_id); | ||
677 | |||
674 | // Case 1: macro rules, define a macro in crate-global mutable scope | 678 | // Case 1: macro rules, define a macro in crate-global mutable scope |
675 | if is_macro_rules(&mac.path) { | 679 | if is_macro_rules(&mac.path) { |
676 | if let Some(name) = &mac.name { | 680 | if let Some(name) = &mac.name { |
677 | let macro_id = MacroDefId { | 681 | let macro_id = |
678 | ast_id: mac.ast_id.with_file_id(self.file_id), | 682 | MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id }; |
679 | krate: self.def_collector.def_map.krate, | ||
680 | }; | ||
681 | let macro_ = MacroDef { id: macro_id }; | 683 | let macro_ = MacroDef { id: macro_id }; |
682 | self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); | 684 | self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); |
683 | } | 685 | } |
684 | return; | 686 | return; |
685 | } | 687 | } |
686 | 688 | ||
687 | let ast_id = mac.ast_id.with_file_id(self.file_id); | ||
688 | |||
689 | // Case 2: try to resolve in legacy scope and expand macro_rules, triggering | 689 | // Case 2: try to resolve in legacy scope and expand macro_rules, triggering |
690 | // recursive item collection. | 690 | // recursive item collection. |
691 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { | 691 | if let Some(macro_def) = mac.path.as_ident().and_then(|name| { |
692 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | 692 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) |
693 | }) { | 693 | }) { |
694 | let def = macro_def.id; | 694 | let def = macro_def.id; |
695 | let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); | 695 | let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id }); |
696 | 696 | ||
697 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); | 697 | self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); |
698 | return; | 698 | return; |
@@ -728,7 +728,7 @@ where | |||
728 | } | 728 | } |
729 | 729 | ||
730 | fn is_macro_rules(path: &Path) -> bool { | 730 | fn is_macro_rules(path: &Path) -> bool { |
731 | path.as_ident() == Some(&MACRO_RULES) | 731 | path.as_ident() == Some(&name::MACRO_RULES) |
732 | } | 732 | } |
733 | 733 | ||
734 | #[cfg(test)] | 734 | #[cfg(test)] |
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs deleted file mode 100644 index e8b808514..000000000 --- a/crates/ra_hir/src/nameres/mod_resolution.rs +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | //! This module resolves `mod foo;` declaration to file. | ||
2 | use ra_db::FileId; | ||
3 | use ra_syntax::SmolStr; | ||
4 | use relative_path::RelativePathBuf; | ||
5 | |||
6 | use crate::{db::DefDatabase, HirFileId, Name}; | ||
7 | |||
8 | #[derive(Clone, Debug)] | ||
9 | pub(super) struct ModDir { | ||
10 | /// `.` for `mod.rs`, `lib.rs` | ||
11 | /// `./foo` for `foo.rs` | ||
12 | /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` | ||
13 | path: RelativePathBuf, | ||
14 | /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/` | ||
15 | root_non_dir_owner: bool, | ||
16 | } | ||
17 | |||
18 | impl ModDir { | ||
19 | pub(super) fn root() -> ModDir { | ||
20 | ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } | ||
21 | } | ||
22 | |||
23 | pub(super) fn descend_into_definition( | ||
24 | &self, | ||
25 | name: &Name, | ||
26 | attr_path: Option<&SmolStr>, | ||
27 | ) -> ModDir { | ||
28 | let mut path = self.path.clone(); | ||
29 | match attr_to_path(attr_path) { | ||
30 | None => path.push(&name.to_string()), | ||
31 | Some(attr_path) => { | ||
32 | if self.root_non_dir_owner { | ||
33 | // Workaround for relative path API: turn `lib.rs` into ``. | ||
34 | if !path.pop() { | ||
35 | path = RelativePathBuf::default(); | ||
36 | } | ||
37 | } | ||
38 | path.push(attr_path); | ||
39 | } | ||
40 | } | ||
41 | ModDir { path, root_non_dir_owner: false } | ||
42 | } | ||
43 | |||
44 | pub(super) fn resolve_declaration( | ||
45 | &self, | ||
46 | db: &impl DefDatabase, | ||
47 | file_id: HirFileId, | ||
48 | name: &Name, | ||
49 | attr_path: Option<&SmolStr>, | ||
50 | ) -> Result<(FileId, ModDir), RelativePathBuf> { | ||
51 | let empty_path = RelativePathBuf::default(); | ||
52 | let file_id = file_id.original_file(db); | ||
53 | |||
54 | let mut candidate_files = Vec::new(); | ||
55 | match attr_to_path(attr_path) { | ||
56 | Some(attr_path) => { | ||
57 | let base = if self.root_non_dir_owner { | ||
58 | self.path.parent().unwrap_or(&empty_path) | ||
59 | } else { | ||
60 | &self.path | ||
61 | }; | ||
62 | candidate_files.push(base.join(attr_path)) | ||
63 | } | ||
64 | None => { | ||
65 | candidate_files.push(self.path.join(&format!("{}.rs", name))); | ||
66 | candidate_files.push(self.path.join(&format!("{}/mod.rs", name))); | ||
67 | } | ||
68 | }; | ||
69 | |||
70 | for candidate in candidate_files.iter() { | ||
71 | if let Some(file_id) = db.resolve_relative_path(file_id, candidate) { | ||
72 | let mut root_non_dir_owner = false; | ||
73 | let mut mod_path = RelativePathBuf::new(); | ||
74 | if !(candidate.ends_with("mod.rs") || attr_path.is_some()) { | ||
75 | root_non_dir_owner = true; | ||
76 | mod_path.push(&name.to_string()); | ||
77 | } | ||
78 | return Ok((file_id, ModDir { path: mod_path, root_non_dir_owner })); | ||
79 | } | ||
80 | } | ||
81 | Err(candidate_files.remove(0)) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | fn attr_to_path(attr: Option<&SmolStr>) -> Option<RelativePathBuf> { | ||
86 | attr.and_then(|it| RelativePathBuf::from_path(&it.replace("\\", "/")).ok()) | ||
87 | } | ||
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs deleted file mode 100644 index 57f2929c3..000000000 --- a/crates/ra_hir/src/nameres/raw.rs +++ /dev/null | |||
@@ -1,403 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::{ops::Index, sync::Arc}; | ||
4 | |||
5 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | ||
6 | use ra_syntax::{ | ||
7 | ast::{self, AttrsOwner, NameOwner}, | ||
8 | AstNode, AstPtr, SourceFile, | ||
9 | }; | ||
10 | use test_utils::tested_by; | ||
11 | |||
12 | use crate::{ | ||
13 | attr::Attr, | ||
14 | db::{AstDatabase, DefDatabase}, | ||
15 | AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source, | ||
16 | }; | ||
17 | |||
18 | /// `RawItems` is a set of top-level items in a file (except for impls). | ||
19 | /// | ||
20 | /// It is the input to name resolution algorithm. `RawItems` are not invalidated | ||
21 | /// on most edits. | ||
22 | #[derive(Debug, Default, PartialEq, Eq)] | ||
23 | pub struct RawItems { | ||
24 | modules: Arena<Module, ModuleData>, | ||
25 | imports: Arena<ImportId, ImportData>, | ||
26 | defs: Arena<Def, DefData>, | ||
27 | macros: Arena<Macro, MacroData>, | ||
28 | /// items for top-level module | ||
29 | items: Vec<RawItem>, | ||
30 | } | ||
31 | |||
32 | #[derive(Debug, Default, PartialEq, Eq)] | ||
33 | pub struct ImportSourceMap { | ||
34 | map: ArenaMap<ImportId, ImportSourcePtr>, | ||
35 | } | ||
36 | |||
37 | type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; | ||
38 | type ImportSource = Either<ast::UseTree, ast::ExternCrateItem>; | ||
39 | |||
40 | impl ImportSourcePtr { | ||
41 | fn to_node(self, file: &SourceFile) -> ImportSource { | ||
42 | self.map(|ptr| ptr.to_node(file.syntax()), |ptr| ptr.to_node(file.syntax())) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | impl ImportSourceMap { | ||
47 | fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) { | ||
48 | self.map.insert(import, ptr) | ||
49 | } | ||
50 | |||
51 | pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource { | ||
52 | let file = match source { | ||
53 | ModuleSource::SourceFile(file) => file.clone(), | ||
54 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | ||
55 | }; | ||
56 | |||
57 | self.map[import].to_node(&file) | ||
58 | } | ||
59 | } | ||
60 | |||
61 | impl RawItems { | ||
62 | pub(crate) fn raw_items_query( | ||
63 | db: &(impl DefDatabase + AstDatabase), | ||
64 | file_id: HirFileId, | ||
65 | ) -> Arc<RawItems> { | ||
66 | db.raw_items_with_source_map(file_id).0 | ||
67 | } | ||
68 | |||
69 | pub(crate) fn raw_items_with_source_map_query( | ||
70 | db: &(impl DefDatabase + AstDatabase), | ||
71 | file_id: HirFileId, | ||
72 | ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { | ||
73 | let mut collector = RawItemsCollector { | ||
74 | raw_items: RawItems::default(), | ||
75 | source_ast_id_map: db.ast_id_map(file_id), | ||
76 | source_map: ImportSourceMap::default(), | ||
77 | file_id, | ||
78 | db, | ||
79 | }; | ||
80 | if let Some(node) = db.parse_or_expand(file_id) { | ||
81 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { | ||
82 | collector.process_module(None, source_file); | ||
83 | } else if let Some(item_list) = ast::MacroItems::cast(node) { | ||
84 | collector.process_module(None, item_list); | ||
85 | } | ||
86 | } | ||
87 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) | ||
88 | } | ||
89 | |||
90 | pub(super) fn items(&self) -> &[RawItem] { | ||
91 | &self.items | ||
92 | } | ||
93 | } | ||
94 | |||
95 | impl Index<Module> for RawItems { | ||
96 | type Output = ModuleData; | ||
97 | fn index(&self, idx: Module) -> &ModuleData { | ||
98 | &self.modules[idx] | ||
99 | } | ||
100 | } | ||
101 | |||
102 | impl Index<ImportId> for RawItems { | ||
103 | type Output = ImportData; | ||
104 | fn index(&self, idx: ImportId) -> &ImportData { | ||
105 | &self.imports[idx] | ||
106 | } | ||
107 | } | ||
108 | |||
109 | impl Index<Def> for RawItems { | ||
110 | type Output = DefData; | ||
111 | fn index(&self, idx: Def) -> &DefData { | ||
112 | &self.defs[idx] | ||
113 | } | ||
114 | } | ||
115 | |||
116 | impl Index<Macro> for RawItems { | ||
117 | type Output = MacroData; | ||
118 | fn index(&self, idx: Macro) -> &MacroData { | ||
119 | &self.macros[idx] | ||
120 | } | ||
121 | } | ||
122 | |||
123 | // Avoid heap allocation on items without attributes. | ||
124 | type Attrs = Option<Arc<[Attr]>>; | ||
125 | |||
126 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
127 | pub(super) struct RawItem { | ||
128 | attrs: Attrs, | ||
129 | pub(super) kind: RawItemKind, | ||
130 | } | ||
131 | |||
132 | impl RawItem { | ||
133 | pub(super) fn attrs(&self) -> &[Attr] { | ||
134 | self.attrs.as_ref().map_or(&[], |it| &*it) | ||
135 | } | ||
136 | } | ||
137 | |||
138 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
139 | pub(super) enum RawItemKind { | ||
140 | Module(Module), | ||
141 | Import(ImportId), | ||
142 | Def(Def), | ||
143 | Macro(Macro), | ||
144 | } | ||
145 | |||
146 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
147 | pub(super) struct Module(RawId); | ||
148 | impl_arena_id!(Module); | ||
149 | |||
150 | #[derive(Debug, PartialEq, Eq)] | ||
151 | pub(super) enum ModuleData { | ||
152 | Declaration { name: Name, ast_id: FileAstId<ast::Module> }, | ||
153 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, | ||
154 | } | ||
155 | |||
156 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
157 | pub struct ImportId(RawId); | ||
158 | impl_arena_id!(ImportId); | ||
159 | |||
160 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
161 | pub struct ImportData { | ||
162 | pub(super) path: Path, | ||
163 | pub(super) alias: Option<Name>, | ||
164 | pub(super) is_glob: bool, | ||
165 | pub(super) is_prelude: bool, | ||
166 | pub(super) is_extern_crate: bool, | ||
167 | pub(super) is_macro_use: bool, | ||
168 | } | ||
169 | |||
170 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
171 | pub(super) struct Def(RawId); | ||
172 | impl_arena_id!(Def); | ||
173 | |||
174 | #[derive(Debug, PartialEq, Eq)] | ||
175 | pub(super) struct DefData { | ||
176 | pub(super) name: Name, | ||
177 | pub(super) kind: DefKind, | ||
178 | } | ||
179 | |||
180 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
181 | pub(super) enum DefKind { | ||
182 | Function(FileAstId<ast::FnDef>), | ||
183 | Struct(FileAstId<ast::StructDef>), | ||
184 | Union(FileAstId<ast::StructDef>), | ||
185 | Enum(FileAstId<ast::EnumDef>), | ||
186 | Const(FileAstId<ast::ConstDef>), | ||
187 | Static(FileAstId<ast::StaticDef>), | ||
188 | Trait(FileAstId<ast::TraitDef>), | ||
189 | TypeAlias(FileAstId<ast::TypeAliasDef>), | ||
190 | } | ||
191 | |||
192 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
193 | pub(super) struct Macro(RawId); | ||
194 | impl_arena_id!(Macro); | ||
195 | |||
196 | #[derive(Debug, PartialEq, Eq)] | ||
197 | pub(super) struct MacroData { | ||
198 | pub(super) ast_id: FileAstId<ast::MacroCall>, | ||
199 | pub(super) path: Path, | ||
200 | pub(super) name: Option<Name>, | ||
201 | pub(super) export: bool, | ||
202 | } | ||
203 | |||
204 | struct RawItemsCollector<DB> { | ||
205 | raw_items: RawItems, | ||
206 | source_ast_id_map: Arc<AstIdMap>, | ||
207 | source_map: ImportSourceMap, | ||
208 | file_id: HirFileId, | ||
209 | db: DB, | ||
210 | } | ||
211 | |||
212 | impl<DB: AstDatabase> RawItemsCollector<&DB> { | ||
213 | fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) { | ||
214 | for item_or_macro in body.items_with_macros() { | ||
215 | match item_or_macro { | ||
216 | ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m), | ||
217 | ast::ItemOrMacro::Item(item) => self.add_item(current_module, item), | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { | ||
223 | let attrs = self.parse_attrs(&item); | ||
224 | let (kind, name) = match item { | ||
225 | ast::ModuleItem::Module(module) => { | ||
226 | self.add_module(current_module, module); | ||
227 | return; | ||
228 | } | ||
229 | ast::ModuleItem::UseItem(use_item) => { | ||
230 | self.add_use_item(current_module, use_item); | ||
231 | return; | ||
232 | } | ||
233 | ast::ModuleItem::ExternCrateItem(extern_crate) => { | ||
234 | self.add_extern_crate_item(current_module, extern_crate); | ||
235 | return; | ||
236 | } | ||
237 | ast::ModuleItem::ImplBlock(_) => { | ||
238 | // impls don't participate in name resolution | ||
239 | return; | ||
240 | } | ||
241 | ast::ModuleItem::StructDef(it) => { | ||
242 | let id = self.source_ast_id_map.ast_id(&it); | ||
243 | let name = it.name(); | ||
244 | if it.is_union() { | ||
245 | (DefKind::Union(id), name) | ||
246 | } else { | ||
247 | (DefKind::Struct(id), name) | ||
248 | } | ||
249 | } | ||
250 | ast::ModuleItem::EnumDef(it) => { | ||
251 | (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
252 | } | ||
253 | ast::ModuleItem::FnDef(it) => { | ||
254 | (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
255 | } | ||
256 | ast::ModuleItem::TraitDef(it) => { | ||
257 | (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
258 | } | ||
259 | ast::ModuleItem::TypeAliasDef(it) => { | ||
260 | (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
261 | } | ||
262 | ast::ModuleItem::ConstDef(it) => { | ||
263 | (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
264 | } | ||
265 | ast::ModuleItem::StaticDef(it) => { | ||
266 | (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name()) | ||
267 | } | ||
268 | }; | ||
269 | if let Some(name) = name { | ||
270 | let name = name.as_name(); | ||
271 | let def = self.raw_items.defs.alloc(DefData { name, kind }); | ||
272 | self.push_item(current_module, attrs, RawItemKind::Def(def)); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | fn add_module(&mut self, current_module: Option<Module>, module: ast::Module) { | ||
277 | let name = match module.name() { | ||
278 | Some(it) => it.as_name(), | ||
279 | None => return, | ||
280 | }; | ||
281 | let attrs = self.parse_attrs(&module); | ||
282 | |||
283 | let ast_id = self.source_ast_id_map.ast_id(&module); | ||
284 | if module.has_semi() { | ||
285 | let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id }); | ||
286 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | ||
287 | return; | ||
288 | } | ||
289 | |||
290 | if let Some(item_list) = module.item_list() { | ||
291 | let item = self.raw_items.modules.alloc(ModuleData::Definition { | ||
292 | name, | ||
293 | ast_id, | ||
294 | items: Vec::new(), | ||
295 | }); | ||
296 | self.process_module(Some(item), item_list); | ||
297 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | ||
298 | return; | ||
299 | } | ||
300 | tested_by!(name_res_works_for_broken_modules); | ||
301 | } | ||
302 | |||
303 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { | ||
304 | // FIXME: cfg_attr | ||
305 | let is_prelude = use_item.has_atom_attr("prelude_import"); | ||
306 | let attrs = self.parse_attrs(&use_item); | ||
307 | |||
308 | Path::expand_use_item( | ||
309 | Source { ast: use_item, file_id: self.file_id }, | ||
310 | self.db, | ||
311 | |path, use_tree, is_glob, alias| { | ||
312 | let import_data = ImportData { | ||
313 | path, | ||
314 | alias, | ||
315 | is_glob, | ||
316 | is_prelude, | ||
317 | is_extern_crate: false, | ||
318 | is_macro_use: false, | ||
319 | }; | ||
320 | self.push_import( | ||
321 | current_module, | ||
322 | attrs.clone(), | ||
323 | import_data, | ||
324 | Either::A(AstPtr::new(use_tree)), | ||
325 | ); | ||
326 | }, | ||
327 | ) | ||
328 | } | ||
329 | |||
330 | fn add_extern_crate_item( | ||
331 | &mut self, | ||
332 | current_module: Option<Module>, | ||
333 | extern_crate: ast::ExternCrateItem, | ||
334 | ) { | ||
335 | if let Some(name_ref) = extern_crate.name_ref() { | ||
336 | let path = Path::from_name_ref(&name_ref); | ||
337 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | ||
338 | let attrs = self.parse_attrs(&extern_crate); | ||
339 | // FIXME: cfg_attr | ||
340 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
341 | let import_data = ImportData { | ||
342 | path, | ||
343 | alias, | ||
344 | is_glob: false, | ||
345 | is_prelude: false, | ||
346 | is_extern_crate: true, | ||
347 | is_macro_use, | ||
348 | }; | ||
349 | self.push_import( | ||
350 | current_module, | ||
351 | attrs, | ||
352 | import_data, | ||
353 | Either::B(AstPtr::new(&extern_crate)), | ||
354 | ); | ||
355 | } | ||
356 | } | ||
357 | |||
358 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { | ||
359 | let attrs = self.parse_attrs(&m); | ||
360 | let path = match m | ||
361 | .path() | ||
362 | .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db)) | ||
363 | { | ||
364 | Some(it) => it, | ||
365 | _ => return, | ||
366 | }; | ||
367 | |||
368 | let name = m.name().map(|it| it.as_name()); | ||
369 | let ast_id = self.source_ast_id_map.ast_id(&m); | ||
370 | // FIXME: cfg_attr | ||
371 | let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); | ||
372 | |||
373 | let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); | ||
374 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | ||
375 | } | ||
376 | |||
377 | fn push_import( | ||
378 | &mut self, | ||
379 | current_module: Option<Module>, | ||
380 | attrs: Attrs, | ||
381 | data: ImportData, | ||
382 | source: ImportSourcePtr, | ||
383 | ) { | ||
384 | let import = self.raw_items.imports.alloc(data); | ||
385 | self.source_map.insert(import, source); | ||
386 | self.push_item(current_module, attrs, RawItemKind::Import(import)) | ||
387 | } | ||
388 | |||
389 | fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) { | ||
390 | match current_module { | ||
391 | Some(module) => match &mut self.raw_items.modules[module] { | ||
392 | ModuleData::Definition { items, .. } => items, | ||
393 | ModuleData::Declaration { .. } => unreachable!(), | ||
394 | }, | ||
395 | None => &mut self.raw_items.items, | ||
396 | } | ||
397 | .push(RawItem { attrs, kind }) | ||
398 | } | ||
399 | |||
400 | fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { | ||
401 | Attr::from_attrs_owner(self.file_id, item, self.db) | ||
402 | } | ||
403 | } | ||
diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs index f569aacdc..abfe8b1c3 100644 --- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs | |||
@@ -2,7 +2,7 @@ use super::*; | |||
2 | 2 | ||
3 | #[test] | 3 | #[test] |
4 | fn name_res_works_for_broken_modules() { | 4 | fn name_res_works_for_broken_modules() { |
5 | covers!(name_res_works_for_broken_modules); | 5 | // covers!(name_res_works_for_broken_modules); |
6 | let map = def_map( | 6 | let map = def_map( |
7 | " | 7 | " |
8 | //- /lib.rs | 8 | //- /lib.rs |