aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-03-13 13:38:02 +0000
committerAleksey Kladov <[email protected]>2019-03-17 09:49:07 +0000
commit2195d1db6d70d64383bec82819fab02891d09744 (patch)
tree40174ca7cbb3625ea62ebc10dbd9b592c83a8081
parent182c05a96c25321ac3ff262cea098e0c4d7ed6f8 (diff)
Replace module_tree with CrateDefMap
-rw-r--r--crates/ra_hir/src/code_model_api.rs2
-rw-r--r--crates/ra_hir/src/code_model_impl/krate.rs4
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs97
-rw-r--r--crates/ra_hir/src/db.rs21
-rw-r--r--crates/ra_hir/src/ids.rs6
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/module_tree.rs340
-rw-r--r--crates/ra_hir/src/nameres.rs23
-rw-r--r--crates/ra_hir/src/nameres/crate_def_map.rs118
-rw-r--r--crates/ra_hir/src/nameres/crate_def_map/collector.rs166
-rw-r--r--crates/ra_hir/src/nameres/crate_def_map/raw.rs51
-rw-r--r--crates/ra_hir/src/nameres/crate_def_map/tests.rs2
-rw-r--r--crates/ra_hir/src/nameres/tests.rs3
-rw-r--r--crates/ra_hir/src/source_binder.rs4
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs4
-rw-r--r--crates/ra_ide_api/src/runnables.rs2
16 files changed, 333 insertions, 511 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 87a7195e6..ef69ef96a 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -9,12 +9,12 @@ use crate::{
9 HirDatabase, PersistentHirDatabase, 9 HirDatabase, PersistentHirDatabase,
10 type_ref::TypeRef, 10 type_ref::TypeRef,
11 nameres::{ModuleScope, Namespace, lower::ImportId}, 11 nameres::{ModuleScope, Namespace, lower::ImportId},
12 nameres::crate_def_map::ModuleId,
12 expr::{Body, BodySourceMap}, 13 expr::{Body, BodySourceMap},
13 ty::InferenceResult, 14 ty::InferenceResult,
14 adt::{EnumVariantId, StructFieldId, VariantDef}, 15 adt::{EnumVariantId, StructFieldId, VariantDef},
15 generics::GenericParams, 16 generics::GenericParams,
16 docs::{Documentation, Docs, docs_from_ast}, 17 docs::{Documentation, Docs, docs_from_ast},
17 module_tree::ModuleId,
18 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, 18 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId},
19 impl_block::ImplBlock, 19 impl_block::ImplBlock,
20 resolve::Resolver, 20 resolve::Resolver,
diff --git a/crates/ra_hir/src/code_model_impl/krate.rs b/crates/ra_hir/src/code_model_impl/krate.rs
index 161ae6e18..cc87c6f14 100644
--- a/crates/ra_hir/src/code_model_impl/krate.rs
+++ b/crates/ra_hir/src/code_model_impl/krate.rs
@@ -18,9 +18,7 @@ impl Crate {
18 .collect() 18 .collect()
19 } 19 }
20 pub(crate) fn root_module_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 20 pub(crate) fn root_module_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
21 let module_tree = db.module_tree(*self); 21 let module_id = db.crate_def_map(*self).root();
22 let module_id = module_tree.modules().next()?;
23
24 let module = Module { krate: *self, module_id }; 22 let module = Module { krate: *self, module_id };
25 Some(module) 23 Some(module)
26 } 24 }
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 437f96942..5d8f738b5 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -1,33 +1,62 @@
1use ra_syntax::{ast, SyntaxNode, TreeArc}; 1use ra_db::FileId;
2use ra_syntax::{ast, SyntaxNode, TreeArc, AstNode};
2 3
3use crate::{ 4use crate::{
4 Module, ModuleSource, Problem, 5 Module, ModuleSource, Problem, Name,
5 Name, 6 nameres::crate_def_map::ModuleId,
6 module_tree::ModuleId,
7 nameres::lower::ImportId, 7 nameres::lower::ImportId,
8 HirDatabase, PersistentHirDatabase, 8 HirDatabase, PersistentHirDatabase,
9 HirFileId 9 HirFileId, SourceItemId,
10}; 10};
11 11
12impl ModuleSource {
13 pub(crate) fn new(
14 db: &impl PersistentHirDatabase,
15 file_id: Option<FileId>,
16 decl_id: Option<SourceItemId>,
17 ) -> ModuleSource {
18 match (file_id, decl_id) {
19 (Some(file_id), _) => {
20 let source_file = db.parse(file_id);
21 ModuleSource::SourceFile(source_file)
22 }
23 (None, Some(item_id)) => {
24 let module = db.file_item(item_id);
25 let module = ast::Module::cast(&*module).unwrap();
26 assert!(module.item_list().is_some(), "expected inline module");
27 ModuleSource::Module(module.to_owned())
28 }
29 (None, None) => panic!(),
30 }
31 }
32}
33
12impl Module { 34impl Module {
13 fn with_module_id(&self, module_id: ModuleId) -> Module { 35 fn with_module_id(&self, module_id: ModuleId) -> Module {
14 Module { module_id, krate: self.krate } 36 Module { module_id, krate: self.krate }
15 } 37 }
16 38
17 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> { 39 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option<Name> {
18 let module_tree = db.module_tree(self.krate); 40 let def_map = db.crate_def_map(self.krate);
19 let link = self.module_id.parent_link(&module_tree)?; 41 let parent = def_map[self.module_id].parent?;
20 Some(link.name(&module_tree).clone()) 42 def_map[parent].children.iter().find_map(|(name, module_id)| {
43 if *module_id == self.module_id {
44 Some(name.clone())
45 } else {
46 None
47 }
48 })
21 } 49 }
22 50
23 pub(crate) fn definition_source_impl( 51 pub(crate) fn definition_source_impl(
24 &self, 52 &self,
25 db: &impl PersistentHirDatabase, 53 db: &impl PersistentHirDatabase,
26 ) -> (HirFileId, ModuleSource) { 54 ) -> (HirFileId, ModuleSource) {
27 let module_tree = db.module_tree(self.krate); 55 let def_map = db.crate_def_map(self.krate);
28 let file_id = self.module_id.file_id(&module_tree); 56 let decl_id = def_map[self.module_id].declaration;
29 let decl_id = self.module_id.decl_id(&module_tree); 57 let file_id = def_map[self.module_id].definition;
30 let module_source = ModuleSource::new(db, file_id, decl_id); 58 let module_source = ModuleSource::new(db, file_id, decl_id);
59 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id);
31 (file_id, module_source) 60 (file_id, module_source)
32 } 61 }
33 62
@@ -35,11 +64,11 @@ impl Module {
35 &self, 64 &self,
36 db: &impl HirDatabase, 65 db: &impl HirDatabase,
37 ) -> Option<(HirFileId, TreeArc<ast::Module>)> { 66 ) -> Option<(HirFileId, TreeArc<ast::Module>)> {
38 let module_tree = db.module_tree(self.krate); 67 let def_map = db.crate_def_map(self.krate);
39 let link = self.module_id.parent_link(&module_tree)?; 68 let decl = def_map[self.module_id].declaration?;
40 let file_id = link.owner(&module_tree).file_id(&module_tree); 69 let syntax_node = db.file_item(decl);
41 let src = link.source(&module_tree, db); 70 let ast = ast::Module::cast(&syntax_node).unwrap().to_owned();
42 Some((file_id, src)) 71 Some((decl.file_id, ast))
43 } 72 }
44 73
45 pub(crate) fn import_source_impl( 74 pub(crate) fn import_source_impl(
@@ -53,16 +82,15 @@ impl Module {
53 } 82 }
54 83
55 pub(crate) fn crate_root_impl(&self, db: &impl PersistentHirDatabase) -> Module { 84 pub(crate) fn crate_root_impl(&self, db: &impl PersistentHirDatabase) -> Module {
56 let module_tree = db.module_tree(self.krate); 85 let def_map = db.crate_def_map(self.krate);
57 let module_id = self.module_id.crate_root(&module_tree); 86 self.with_module_id(def_map.root())
58 self.with_module_id(module_id)
59 } 87 }
60 88
61 /// Finds a child module with the specified name. 89 /// Finds a child module with the specified name.
62 pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> { 90 pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option<Module> {
63 let module_tree = db.module_tree(self.krate); 91 let def_map = db.crate_def_map(self.krate);
64 let child_id = self.module_id.child(&module_tree, name)?; 92 let child_id = def_map[self.module_id].children.get(name)?;
65 Some(self.with_module_id(child_id)) 93 Some(self.with_module_id(*child_id))
66 } 94 }
67 95
68 /// Iterates over all child modules. 96 /// Iterates over all child modules.
@@ -70,18 +98,18 @@ impl Module {
70 &self, 98 &self,
71 db: &impl PersistentHirDatabase, 99 db: &impl PersistentHirDatabase,
72 ) -> impl Iterator<Item = Module> { 100 ) -> impl Iterator<Item = Module> {
73 let module_tree = db.module_tree(self.krate); 101 let def_map = db.crate_def_map(self.krate);
74 let children = self 102 let children = def_map[self.module_id]
75 .module_id 103 .children
76 .children(&module_tree) 104 .iter()
77 .map(|(_, module_id)| self.with_module_id(module_id)) 105 .map(|(_, module_id)| self.with_module_id(*module_id))
78 .collect::<Vec<_>>(); 106 .collect::<Vec<_>>();
79 children.into_iter() 107 children.into_iter()
80 } 108 }
81 109
82 pub(crate) fn parent_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 110 pub(crate) fn parent_impl(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
83 let module_tree = db.module_tree(self.krate); 111 let def_map = db.crate_def_map(self.krate);
84 let parent_id = self.module_id.parent(&module_tree)?; 112 let parent_id = def_map[self.module_id].parent?;
85 Some(self.with_module_id(parent_id)) 113 Some(self.with_module_id(parent_id))
86 } 114 }
87 115
@@ -89,7 +117,14 @@ impl Module {
89 &self, 117 &self,
90 db: &impl HirDatabase, 118 db: &impl HirDatabase,
91 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> { 119 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
92 let module_tree = db.module_tree(self.krate); 120 let def_map = db.crate_def_map(self.krate);
93 self.module_id.problems(&module_tree, db) 121 let (my_file_id, _) = self.definition_source(db);
122 // FIXME: not entirely corret filterint by module
123 def_map
124 .problems()
125 .iter()
126 .filter(|(source_item_id, _problem)| my_file_id == source_item_id.file_id)
127 .map(|(source_item_id, problem)| (db.file_item(*source_item_id), problem.clone()))
128 .collect()
94 } 129 }
95} 130}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 5ad9547f1..423922a57 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SourceDatabase, salsa}; 4use ra_db::{SourceDatabase, salsa, FileId};
5 5
6use crate::{ 6use crate::{
7 MacroCallId, HirFileId, 7 MacroCallId, HirFileId,
@@ -10,14 +10,11 @@ use crate::{
10 Struct, Enum, StructField, 10 Struct, Enum, StructField,
11 Const, ConstSignature, Static, 11 Const, ConstSignature, Static,
12 macros::MacroExpansion, 12 macros::MacroExpansion,
13 module_tree::ModuleTree, 13 nameres::{Namespace, ItemMap, lower::{LoweredModule, ImportSourceMap}, crate_def_map::{RawItems, CrateDefMap}},
14 nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
15 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, 14 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig},
16 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData},
17 impl_block::{ModuleImplBlocks, ImplSourceMap}, 16 impl_block::{ModuleImplBlocks, ImplSourceMap},
18 generics::{GenericParams, GenericDef}, 17 generics::{GenericParams, GenericDef},
19 ids::SourceFileItemId,
20 nameres::Namespace,
21 type_ref::TypeRef, 18 type_ref::TypeRef,
22}; 19};
23 20
@@ -41,13 +38,6 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
41 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] 38 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)]
42 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; 39 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;
43 40
44 #[salsa::invoke(crate::module_tree::Submodule::submodules_query)]
45 fn submodules(
46 &self,
47 file_id: HirFileId,
48 delc_id: Option<SourceFileItemId>,
49 ) -> Arc<Vec<crate::module_tree::Submodule>>;
50
51 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_with_source_map_query)] 41 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_with_source_map_query)]
52 fn lower_module_with_source_map( 42 fn lower_module_with_source_map(
53 &self, 43 &self,
@@ -57,11 +47,14 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
57 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] 47 #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)]
58 fn lower_module(&self, module: Module) -> Arc<LoweredModule>; 48 fn lower_module(&self, module: Module) -> Arc<LoweredModule>;
59 49
50 #[salsa::invoke(RawItems::raw_items_query)]
51 fn raw_items(&self, file_id: FileId) -> Arc<RawItems>;
52
60 #[salsa::invoke(crate::nameres::ItemMap::item_map_query)] 53 #[salsa::invoke(crate::nameres::ItemMap::item_map_query)]
61 fn item_map(&self, krate: Crate) -> Arc<ItemMap>; 54 fn item_map(&self, krate: Crate) -> Arc<ItemMap>;
62 55
63 #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)] 56 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
64 fn module_tree(&self, krate: Crate) -> Arc<ModuleTree>; 57 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
65 58
66 #[salsa::invoke(crate::impl_block::impls_in_module)] 59 #[salsa::invoke(crate::impl_block::impls_in_module)]
67 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; 60 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>;
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index e805ddcba..6ce00a372 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -296,6 +296,12 @@ impl AstItemDef<ast::TypeAliasDef> for TypeId {
296pub struct SourceFileItemId(RawId); 296pub struct SourceFileItemId(RawId);
297impl_arena_id!(SourceFileItemId); 297impl_arena_id!(SourceFileItemId);
298 298
299impl SourceFileItemId {
300 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
301 SourceItemId { file_id, item_id: self }
302 }
303}
304
299#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 305#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
300pub struct SourceItemId { 306pub struct SourceItemId {
301 pub(crate) file_id: HirFileId, 307 pub(crate) file_id: HirFileId,
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 4508a873e..61db4f6cc 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -26,7 +26,6 @@ pub mod source_binder;
26mod ids; 26mod ids;
27mod macros; 27mod macros;
28mod name; 28mod name;
29mod module_tree;
30mod nameres; 29mod nameres;
31mod adt; 30mod adt;
32mod type_alias; 31mod type_alias;
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index 4d0f40e85..e69de29bb 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -1,340 +0,0 @@
1use std::sync::Arc;
2
3use arrayvec::ArrayVec;
4use relative_path::RelativePathBuf;
5use ra_db::{FileId, SourceRoot};
6use ra_syntax::{
7 SyntaxNode, TreeArc,
8 algo::generate,
9 ast::{self, AstNode, NameOwner},
10};
11use ra_arena::{Arena, RawId, impl_arena_id};
12use test_utils::tested_by;
13
14use crate::{
15 Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource,
16 PersistentHirDatabase,
17 Crate,
18 ids::SourceFileItemId,
19};
20
21impl ModuleSource {
22 pub(crate) fn new(
23 db: &impl PersistentHirDatabase,
24 file_id: HirFileId,
25 decl_id: Option<SourceFileItemId>,
26 ) -> ModuleSource {
27 match decl_id {
28 Some(item_id) => {
29 let module = db.file_item(SourceItemId { file_id, item_id });
30 let module = ast::Module::cast(&*module).unwrap();
31 assert!(module.item_list().is_some(), "expected inline module");
32 ModuleSource::Module(module.to_owned())
33 }
34 None => {
35 let source_file = db.hir_parse(file_id);
36 ModuleSource::SourceFile(source_file)
37 }
38 }
39 }
40}
41
42#[derive(Clone, Hash, PartialEq, Eq, Debug)]
43pub struct Submodule {
44 name: Name,
45 is_declaration: bool,
46 decl_id: SourceFileItemId,
47}
48
49impl Submodule {
50 pub(crate) fn submodules_query(
51 db: &impl PersistentHirDatabase,
52 file_id: HirFileId,
53 decl_id: Option<SourceFileItemId>,
54 ) -> Arc<Vec<Submodule>> {
55 db.check_canceled();
56 let file_items = db.file_items(file_id);
57 let module_source = ModuleSource::new(db, file_id, decl_id);
58 let submodules = match module_source {
59 ModuleSource::SourceFile(source_file) => {
60 collect_submodules(file_id, &file_items, &*source_file)
61 }
62 ModuleSource::Module(module) => {
63 collect_submodules(file_id, &file_items, module.item_list().unwrap())
64 }
65 };
66
67 return Arc::new(submodules);
68
69 fn collect_submodules(
70 file_id: HirFileId,
71 file_items: &SourceFileItems,
72 root: &impl ast::ModuleItemOwner,
73 ) -> Vec<Submodule> {
74 root.items()
75 .filter_map(|item| match item.kind() {
76 ast::ModuleItemKind::Module(m) => Some(m),
77 _ => None,
78 })
79 .filter_map(|module| {
80 let name = module.name()?.as_name();
81 if !module.has_semi() && module.item_list().is_none() {
82 tested_by!(name_res_works_for_broken_modules);
83 return None;
84 }
85 let sub = Submodule {
86 name,
87 is_declaration: module.has_semi(),
88 decl_id: file_items.id_of(file_id, module.syntax()),
89 };
90 Some(sub)
91 })
92 .collect()
93 }
94 }
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
98pub struct ModuleId(RawId);
99impl_arena_id!(ModuleId);
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
102pub struct LinkId(RawId);
103impl_arena_id!(LinkId);
104
105/// Physically, rust source is organized as a set of files, but logically it is
106/// organized as a tree of modules. Usually, a single file corresponds to a
107/// single module, but it is not neccessarily always the case.
108///
109/// `ModuleTree` encapsulates the logic of transitioning from the fuzzy world of files
110/// (which can have multiple parents) to the precise world of modules (which
111/// always have one parent).
112#[derive(Default, Debug, PartialEq, Eq)]
113pub struct ModuleTree {
114 mods: Arena<ModuleId, ModuleData>,
115 links: Arena<LinkId, LinkData>,
116}
117
118#[derive(Debug, PartialEq, Eq)]
119pub struct ModuleData {
120 file_id: HirFileId,
121 /// Points to `ast::Module`, `None` for the whole file.
122 decl_id: Option<SourceFileItemId>,
123 parent: Option<LinkId>,
124 children: Vec<LinkId>,
125}
126
127#[derive(Hash, Debug, PartialEq, Eq)]
128struct LinkData {
129 source: SourceItemId,
130 owner: ModuleId,
131 name: Name,
132 points_to: Vec<ModuleId>,
133 problem: Option<Problem>,
134}
135
136impl ModuleTree {
137 pub(crate) fn module_tree_query(
138 db: &impl PersistentHirDatabase,
139 krate: Crate,
140 ) -> Arc<ModuleTree> {
141 db.check_canceled();
142 let mut res = ModuleTree::default();
143 res.init_crate(db, krate);
144 Arc::new(res)
145 }
146
147 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
148 self.mods.iter().map(|(id, _)| id)
149 }
150
151 pub(crate) fn find_module_by_source(
152 &self,
153 file_id: HirFileId,
154 decl_id: Option<SourceFileItemId>,
155 ) -> Option<ModuleId> {
156 let (res, _) =
157 self.mods.iter().find(|(_, m)| (m.file_id, m.decl_id) == (file_id, decl_id))?;
158 Some(res)
159 }
160
161 fn init_crate(&mut self, db: &impl PersistentHirDatabase, krate: Crate) {
162 let crate_graph = db.crate_graph();
163 let file_id = crate_graph.crate_root(krate.crate_id);
164 let source_root_id = db.file_source_root(file_id);
165
166 let source_root = db.source_root(source_root_id);
167 self.init_subtree(db, &source_root, None, file_id.into(), None);
168 }
169
170 fn init_subtree(
171 &mut self,
172 db: &impl PersistentHirDatabase,
173 source_root: &SourceRoot,
174 parent: Option<LinkId>,
175 file_id: HirFileId,
176 decl_id: Option<SourceFileItemId>,
177 ) -> ModuleId {
178 let is_root = parent.is_none();
179 let id = self.alloc_mod(ModuleData { file_id, decl_id, parent, children: Vec::new() });
180 for sub in db.submodules(file_id, decl_id).iter() {
181 let link = self.alloc_link(LinkData {
182 source: SourceItemId { file_id, item_id: sub.decl_id },
183 name: sub.name.clone(),
184 owner: id,
185 points_to: Vec::new(),
186 problem: None,
187 });
188
189 let (points_to, problem) = if sub.is_declaration {
190 let (points_to, problem) = resolve_submodule(db, file_id, &sub.name, is_root);
191 let points_to = points_to
192 .into_iter()
193 .map(|file_id| {
194 self.init_subtree(db, source_root, Some(link), file_id.into(), None)
195 })
196 .collect::<Vec<_>>();
197 (points_to, problem)
198 } else {
199 let points_to =
200 self.init_subtree(db, source_root, Some(link), file_id, Some(sub.decl_id));
201 (vec![points_to], None)
202 };
203
204 self.links[link].points_to = points_to;
205 self.links[link].problem = problem;
206 }
207 id
208 }
209
210 fn alloc_mod(&mut self, data: ModuleData) -> ModuleId {
211 self.mods.alloc(data)
212 }
213
214 fn alloc_link(&mut self, data: LinkData) -> LinkId {
215 let owner = data.owner;
216 let id = self.links.alloc(data);
217 self.mods[owner].children.push(id);
218 id
219 }
220}
221
222impl ModuleId {
223 pub(crate) fn file_id(self, tree: &ModuleTree) -> HirFileId {
224 tree.mods[self].file_id
225 }
226 pub(crate) fn decl_id(self, tree: &ModuleTree) -> Option<SourceFileItemId> {
227 tree.mods[self].decl_id
228 }
229 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
230 tree.mods[self].parent
231 }
232 pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
233 let link = self.parent_link(tree)?;
234 Some(tree.links[link].owner)
235 }
236 pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
237 generate(Some(self), move |it| it.parent(tree)).last().unwrap()
238 }
239 pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
240 let link = tree.mods[self]
241 .children
242 .iter()
243 .map(|&it| &tree.links[it])
244 .find(|it| it.name == *name)?;
245 Some(*link.points_to.first()?)
246 }
247 pub(crate) fn children<'a>(
248 self,
249 tree: &'a ModuleTree,
250 ) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
251 tree.mods[self].children.iter().filter_map(move |&it| {
252 let link = &tree.links[it];
253 let module = *link.points_to.first()?;
254 Some((link.name.clone(), module))
255 })
256 }
257 pub(crate) fn problems(
258 self,
259 tree: &ModuleTree,
260 db: &impl HirDatabase,
261 ) -> Vec<(TreeArc<SyntaxNode>, Problem)> {
262 tree.mods[self]
263 .children
264 .iter()
265 .filter_map(|&link| {
266 let p = tree.links[link].problem.clone()?;
267 let s = link.source(tree, db);
268 let s = s.name().unwrap().syntax().to_owned();
269 Some((s, p))
270 })
271 .collect()
272 }
273}
274
275impl LinkId {
276 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
277 tree.links[self].owner
278 }
279 pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
280 &tree.links[self].name
281 }
282 pub(crate) fn source(
283 self,
284 tree: &ModuleTree,
285 db: &impl PersistentHirDatabase,
286 ) -> TreeArc<ast::Module> {
287 let syntax_node = db.file_item(tree.links[self].source);
288 ast::Module::cast(&syntax_node).unwrap().to_owned()
289 }
290}
291
292pub(crate) fn resolve_module_declaration(
293 db: &impl PersistentHirDatabase,
294 file_id: HirFileId,
295 name: &Name,
296 is_root: bool,
297) -> Option<FileId> {
298 resolve_submodule(db, file_id, name, is_root).0.first().map(|it| *it)
299}
300
301fn resolve_submodule(
302 db: &impl PersistentHirDatabase,
303 file_id: HirFileId,
304 name: &Name,
305 is_root: bool,
306) -> (Vec<FileId>, Option<Problem>) {
307 // FIXME: handle submodules of inline modules properly
308 let file_id = file_id.original_file(db);
309 let source_root_id = db.file_source_root(file_id);
310 let path = db.file_relative_path(file_id);
311 let root = RelativePathBuf::default();
312 let dir_path = path.parent().unwrap_or(&root);
313 let mod_name = path.file_stem().unwrap_or("unknown");
314 let is_dir_owner = is_root || mod_name == "mod";
315
316 let file_mod = dir_path.join(format!("{}.rs", name));
317 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
318 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
319 let mut candidates = ArrayVec::<[_; 2]>::new();
320 if is_dir_owner {
321 candidates.push(file_mod.clone());
322 candidates.push(dir_mod);
323 } else {
324 candidates.push(file_dir_mod.clone());
325 };
326 let sr = db.source_root(source_root_id);
327 let points_to = candidates
328 .into_iter()
329 .filter_map(|path| sr.files.get(&path))
330 .map(|&it| it)
331 .collect::<Vec<_>>();
332 let problem = if points_to.is_empty() {
333 Some(Problem::UnresolvedModule {
334 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
335 })
336 } else {
337 None
338 };
339 (points_to, problem)
340}
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 6f98ac071..baffbce6f 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -15,7 +15,7 @@
15//! so that the results of name resolution can be preserved unless the module 15//! so that the results of name resolution can be preserved unless the module
16//! structure itself is modified. 16//! structure itself is modified.
17pub(crate) mod lower; 17pub(crate) mod lower;
18mod crate_def_map; 18pub(crate) mod crate_def_map;
19 19
20use std::{time, sync::Arc}; 20use std::{time, sync::Arc};
21 21
@@ -29,8 +29,10 @@ use crate::{
29 Module, ModuleDef, 29 Module, ModuleDef,
30 Path, PathKind, PersistentHirDatabase, 30 Path, PathKind, PersistentHirDatabase,
31 Crate, Name, 31 Crate, Name,
32 module_tree::{ModuleId, ModuleTree}, 32 nameres::{
33 nameres::lower::{ImportId, LoweredModule, ImportData}, 33 crate_def_map::{CrateDefMap, ModuleId},
34 lower::{ImportId, LoweredModule, ImportData}
35 },
34}; 36};
35 37
36/// `ItemMap` is the result of module name resolution. It contains, for each 38/// `ItemMap` is the result of module name resolution. It contains, for each
@@ -160,7 +162,7 @@ struct Resolver<'a, DB> {
160 db: &'a DB, 162 db: &'a DB,
161 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>, 163 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
162 krate: Crate, 164 krate: Crate,
163 module_tree: Arc<ModuleTree>, 165 def_map: Arc<CrateDefMap>,
164 processed_imports: FxHashSet<(ModuleId, ImportId)>, 166 processed_imports: FxHashSet<(ModuleId, ImportId)>,
165 /// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import) 167 /// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import)
166 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>, 168 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>,
@@ -176,12 +178,11 @@ where
176 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>, 178 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
177 krate: Crate, 179 krate: Crate,
178 ) -> Resolver<'a, DB> { 180 ) -> Resolver<'a, DB> {
179 let module_tree = db.module_tree(krate);
180 Resolver { 181 Resolver {
181 db, 182 db,
182 input, 183 input,
183 krate, 184 krate,
184 module_tree, 185 def_map: db.crate_def_map(krate),
185 processed_imports: FxHashSet::default(), 186 processed_imports: FxHashSet::default(),
186 glob_imports: FxHashMap::default(), 187 glob_imports: FxHashMap::default(),
187 result: ItemMap { 188 result: ItemMap {
@@ -254,9 +255,9 @@ where
254 } 255 }
255 256
256 // Populate modules 257 // Populate modules
257 for (name, module_id) in module_id.children(&self.module_tree) { 258 for (name, module_id) in self.def_map[module_id].children.iter() {
258 let module = Module { module_id, krate: self.krate }; 259 let module = Module { module_id: *module_id, krate: self.krate };
259 self.add_module_item(&mut module_items, name, PerNs::types(module.into())); 260 self.add_module_item(&mut module_items, name.clone(), PerNs::types(module.into()));
260 } 261 }
261 262
262 self.result.per_module.insert(module_id, module_items); 263 self.result.per_module.insert(module_id, module_items);
@@ -479,8 +480,8 @@ enum ReachedFixedPoint {
479impl ItemMap { 480impl ItemMap {
480 pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> { 481 pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> {
481 let start = time::Instant::now(); 482 let start = time::Instant::now();
482 let module_tree = db.module_tree(krate); 483 let def_map = db.crate_def_map(krate);
483 let input = module_tree 484 let input = def_map
484 .modules() 485 .modules()
485 .map(|module_id| (module_id, db.lower_module(Module { krate, module_id }))) 486 .map(|module_id| (module_id, db.lower_module(Module { krate, module_id })))
486 .collect::<FxHashMap<_, _>>(); 487 .collect::<FxHashMap<_, _>>();
diff --git a/crates/ra_hir/src/nameres/crate_def_map.rs b/crates/ra_hir/src/nameres/crate_def_map.rs
index 483878c78..d7ccb6584 100644
--- a/crates/ra_hir/src/nameres/crate_def_map.rs
+++ b/crates/ra_hir/src/nameres/crate_def_map.rs
@@ -48,25 +48,40 @@ mod tests;
48 48
49use rustc_hash::FxHashMap; 49use rustc_hash::FxHashMap;
50use test_utils::tested_by; 50use test_utils::tested_by;
51use ra_arena::Arena; 51use ra_arena::{Arena, RawId, impl_arena_id};
52use ra_db::FileId;
53
54use std::sync::Arc;
52 55
53use crate::{ 56use crate::{
54 Name, Module, Path, PathKind, ModuleDef, Crate, 57 Name, Module, Path, PathKind, ModuleDef, Crate, Problem, HirFileId,
55 PersistentHirDatabase, 58 PersistentHirDatabase,
56 module_tree::ModuleId,
57 nameres::{ModuleScope, ResolveMode, ResolvePathResult, PerNs, Edition, ReachedFixedPoint}, 59 nameres::{ModuleScope, ResolveMode, ResolvePathResult, PerNs, Edition, ReachedFixedPoint},
60 ids::{SourceItemId, SourceFileItemId},
58}; 61};
59 62
60#[derive(Default, Debug)] 63pub(crate) use self::raw::RawItems;
61struct ModuleData { 64
62 parent: Option<ModuleId>, 65#[derive(Default, Debug, PartialEq, Eq)]
63 children: FxHashMap<Name, ModuleId>, 66pub(crate) struct ModuleData {
64 scope: ModuleScope, 67 pub(crate) parent: Option<ModuleId>,
68 pub(crate) children: FxHashMap<Name, ModuleId>,
69 pub(crate) scope: ModuleScope,
70 /// None for root
71 pub(crate) declaration: Option<SourceItemId>,
72 /// None for inline modules.
73 ///
74 /// Note that non-inline modules, by definition, live inside non-macro file.
75 pub(crate) definition: Option<FileId>,
65} 76}
66 77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
79pub(crate) struct ModuleId(RawId);
80impl_arena_id!(ModuleId);
81
67/// Contans all top-level defs from a macro-expanded crate 82/// Contans all top-level defs from a macro-expanded crate
68#[derive(Debug)] 83#[derive(Debug, PartialEq, Eq)]
69pub(crate) struct CrateDefMap { 84pub struct CrateDefMap {
70 krate: Crate, 85 krate: Crate,
71 edition: Edition, 86 edition: Edition,
72 /// The prelude module for this crate. This either comes from an import 87 /// The prelude module for this crate. This either comes from an import
@@ -77,19 +92,85 @@ pub(crate) struct CrateDefMap {
77 root: ModuleId, 92 root: ModuleId,
78 modules: Arena<ModuleId, ModuleData>, 93 modules: Arena<ModuleId, ModuleData>,
79 public_macros: FxHashMap<Name, mbe::MacroRules>, 94 public_macros: FxHashMap<Name, mbe::MacroRules>,
95 problems: CrateDefMapProblems,
96}
97
98#[derive(Default, Debug, PartialEq, Eq)]
99pub(crate) struct CrateDefMapProblems {
100 problems: Vec<(SourceItemId, Problem)>,
101}
102
103impl CrateDefMapProblems {
104 fn add(&mut self, source_item_id: SourceItemId, problem: Problem) {
105 self.problems.push((source_item_id, problem))
106 }
107
108 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a {
109 self.problems.iter().map(|(s, p)| (s, p))
110 }
80} 111}
81 112
82impl std::ops::Index<ModuleId> for CrateDefMap { 113impl std::ops::Index<ModuleId> for CrateDefMap {
83 type Output = ModuleScope; 114 type Output = ModuleData;
84 fn index(&self, id: ModuleId) -> &ModuleScope { 115 fn index(&self, id: ModuleId) -> &ModuleData {
85 &self.modules[id].scope 116 &self.modules[id]
86 } 117 }
87} 118}
88 119
89impl CrateDefMap { 120impl CrateDefMap {
121 pub(crate) fn crate_def_map_query(
122 db: &impl PersistentHirDatabase,
123 krate: Crate,
124 ) -> Arc<CrateDefMap> {
125 let def_map = {
126 let edition = krate.edition(db);
127 let mut modules: Arena<ModuleId, ModuleData> = Arena::default();
128 let root = modules.alloc(ModuleData::default());
129 CrateDefMap {
130 krate,
131 edition,
132 extern_prelude: FxHashMap::default(),
133 prelude: None,
134 root,
135 modules,
136 public_macros: FxHashMap::default(),
137 problems: CrateDefMapProblems::default(),
138 }
139 };
140 let def_map = collector::collect_defs(db, def_map);
141 Arc::new(def_map)
142 }
143
144 pub(crate) fn root(&self) -> ModuleId {
145 self.root
146 }
147
148 pub(crate) fn problems(&self) -> &CrateDefMapProblems {
149 &self.problems
150 }
151
152 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
153 self.modules.iter().map(|(id, _data)| id)
154 }
155
156 pub(crate) fn find_module_by_source(
157 &self,
158 file_id: HirFileId,
159 decl_id: Option<SourceFileItemId>,
160 ) -> Option<ModuleId> {
161 let decl_id = decl_id.map(|it| it.with_file_id(file_id));
162 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
163 if decl_id.is_some() {
164 module_data.declaration == decl_id
165 } else {
166 module_data.definition.map(|it| it.into()) == Some(file_id)
167 }
168 })?;
169 Some(module_id)
170 }
171
90 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 172 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
91 // the result. 173 // the result.
92 #[allow(unused)]
93 fn resolve_path_fp( 174 fn resolve_path_fp(
94 &self, 175 &self,
95 db: &impl PersistentHirDatabase, 176 db: &impl PersistentHirDatabase,
@@ -182,7 +263,7 @@ impl CrateDefMap {
182 ); 263 );
183 } 264 }
184 265
185 match self[module.module_id].items.get(&segment.name) { 266 match self[module.module_id].scope.items.get(&segment.name) {
186 Some(res) if !res.def.is_none() => res.def, 267 Some(res) if !res.def.is_none() => res.def,
187 _ => { 268 _ => {
188 log::debug!("path segment {:?} not found", segment.name); 269 log::debug!("path segment {:?} not found", segment.name);
@@ -225,7 +306,8 @@ impl CrateDefMap {
225 } 306 }
226 307
227 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 308 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
228 let from_crate_root = self[self.root].items.get(name).map_or(PerNs::none(), |it| it.def); 309 let from_crate_root =
310 self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
229 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 311 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
230 312
231 from_crate_root.or(from_extern_prelude) 313 from_crate_root.or(from_extern_prelude)
@@ -241,7 +323,7 @@ impl CrateDefMap {
241 // - current module / scope 323 // - current module / scope
242 // - extern prelude 324 // - extern prelude
243 // - std prelude 325 // - std prelude
244 let from_scope = self[module].items.get(name).map_or(PerNs::none(), |it| it.def); 326 let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
245 let from_extern_prelude = 327 let from_extern_prelude =
246 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 328 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
247 let from_prelude = self.resolve_in_prelude(db, name); 329 let from_prelude = self.resolve_in_prelude(db, name);
@@ -256,7 +338,7 @@ impl CrateDefMap {
256 fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> { 338 fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> {
257 if let Some(prelude) = self.prelude { 339 if let Some(prelude) = self.prelude {
258 let resolution = if prelude.krate == self.krate { 340 let resolution = if prelude.krate == self.krate {
259 self[prelude.module_id].items.get(name).cloned() 341 self[prelude.module_id].scope.items.get(name).cloned()
260 } else { 342 } else {
261 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned() 343 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
262 }; 344 };
diff --git a/crates/ra_hir/src/nameres/crate_def_map/collector.rs b/crates/ra_hir/src/nameres/crate_def_map/collector.rs
index cd328b755..2fbfa9e34 100644
--- a/crates/ra_hir/src/nameres/crate_def_map/collector.rs
+++ b/crates/ra_hir/src/nameres/crate_def_map/collector.rs
@@ -1,42 +1,25 @@
1use std::sync::Arc; 1use arrayvec::ArrayVec;
2
3use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
4use ra_arena::Arena; 3use relative_path::RelativePathBuf;
5use test_utils::tested_by; 4use test_utils::tested_by;
5use ra_db::FileId;
6 6
7use crate::{ 7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 Crate, PersistentHirDatabase, HirFileId, Name, Path, 9 PersistentHirDatabase, HirFileId, Name, Path, Problem,
10 KnownName, 10 KnownName,
11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode}, 11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode},
12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
13 module_tree::resolve_module_declaration,
14}; 13};
15 14
16use super::{CrateDefMap, ModuleId, ModuleData, raw}; 15use super::{CrateDefMap, ModuleId, ModuleData, raw};
17 16
18#[allow(unused)] 17pub(super) fn collect_defs(
19pub(crate) fn crate_def_map_query(
20 db: &impl PersistentHirDatabase, 18 db: &impl PersistentHirDatabase,
21 krate: Crate, 19 mut def_map: CrateDefMap,
22) -> Arc<CrateDefMap> { 20) -> CrateDefMap {
23 let mut def_map = {
24 let edition = krate.edition(db);
25 let mut modules: Arena<ModuleId, ModuleData> = Arena::default();
26 let root = modules.alloc(ModuleData::default());
27 CrateDefMap {
28 krate,
29 edition,
30 extern_prelude: FxHashMap::default(),
31 prelude: None,
32 root,
33 modules,
34 public_macros: FxHashMap::default(),
35 }
36 };
37
38 // populate external prelude 21 // populate external prelude
39 for dep in krate.dependencies(db) { 22 for dep in def_map.krate.dependencies(db) {
40 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate); 23 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
41 if let Some(module) = dep.krate.root_module(db) { 24 if let Some(module) = dep.krate.root_module(db) {
42 def_map.extern_prelude.insert(dep.name.clone(), module.into()); 25 def_map.extern_prelude.insert(dep.name.clone(), module.into());
@@ -52,7 +35,6 @@ pub(crate) fn crate_def_map_query(
52 35
53 let mut collector = DefCollector { 36 let mut collector = DefCollector {
54 db, 37 db,
55 krate,
56 def_map, 38 def_map,
57 glob_imports: FxHashMap::default(), 39 glob_imports: FxHashMap::default(),
58 unresolved_imports: Vec::new(), 40 unresolved_imports: Vec::new(),
@@ -60,14 +42,12 @@ pub(crate) fn crate_def_map_query(
60 global_macro_scope: FxHashMap::default(), 42 global_macro_scope: FxHashMap::default(),
61 }; 43 };
62 collector.collect(); 44 collector.collect();
63 let def_map = collector.finish(); 45 collector.finish()
64 Arc::new(def_map)
65} 46}
66 47
67/// Walks the tree of module recursively 48/// Walks the tree of module recursively
68struct DefCollector<DB> { 49struct DefCollector<DB> {
69 db: DB, 50 db: DB,
70 krate: Crate,
71 def_map: CrateDefMap, 51 def_map: CrateDefMap,
72 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, raw::ImportId)>>, 52 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, raw::ImportId)>>,
73 unresolved_imports: Vec<(ModuleId, raw::ImportId, raw::ImportData)>, 53 unresolved_imports: Vec<(ModuleId, raw::ImportId, raw::ImportData)>,
@@ -75,23 +55,16 @@ struct DefCollector<DB> {
75 global_macro_scope: FxHashMap<Name, mbe::MacroRules>, 55 global_macro_scope: FxHashMap<Name, mbe::MacroRules>,
76} 56}
77 57
78/// Walks a single module, populating defs, imports and macros
79struct ModCollector<'a, D> {
80 def_collector: D,
81 module_id: ModuleId,
82 file_id: HirFileId,
83 raw_items: &'a raw::RawItems,
84}
85
86impl<'a, DB> DefCollector<&'a DB> 58impl<'a, DB> DefCollector<&'a DB>
87where 59where
88 DB: PersistentHirDatabase, 60 DB: PersistentHirDatabase,
89{ 61{
90 fn collect(&mut self) { 62 fn collect(&mut self) {
91 let crate_graph = self.db.crate_graph(); 63 let crate_graph = self.db.crate_graph();
92 let file_id = crate_graph.crate_root(self.krate.crate_id()); 64 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
93 let raw_items = raw::RawItems::raw_items_query(self.db, file_id); 65 let raw_items = self.db.raw_items(file_id);
94 let module_id = self.def_map.root; 66 let module_id = self.def_map.root;
67 self.def_map.modules[module_id].definition = Some(file_id);
95 ModCollector { 68 ModCollector {
96 def_collector: &mut *self, 69 def_collector: &mut *self,
97 module_id, 70 module_id,
@@ -123,10 +96,6 @@ where
123 } 96 }
124 } 97 }
125 98
126 fn alloc_module(&mut self) -> ModuleId {
127 self.def_map.modules.alloc(ModuleData::default())
128 }
129
130 fn resolve_imports(&mut self) -> ReachedFixedPoint { 99 fn resolve_imports(&mut self) -> ReachedFixedPoint {
131 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 100 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
132 let mut resolved = Vec::new(); 101 let mut resolved = Vec::new();
@@ -184,7 +153,7 @@ where
184 if import.is_prelude { 153 if import.is_prelude {
185 tested_by!(std_prelude); 154 tested_by!(std_prelude);
186 self.def_map.prelude = Some(m); 155 self.def_map.prelude = Some(m);
187 } else if m.krate != self.krate { 156 } else if m.krate != self.def_map.krate {
188 tested_by!(glob_across_crates); 157 tested_by!(glob_across_crates);
189 // glob import from other crate => we can just import everything once 158 // glob import from other crate => we can just import everything once
190 let item_map = self.db.item_map(m.krate); 159 let item_map = self.db.item_map(m.krate);
@@ -199,7 +168,7 @@ where
199 // glob import from same crate => we do an initial 168 // glob import from same crate => we do an initial
200 // import, and then need to propagate any further 169 // import, and then need to propagate any further
201 // additions 170 // additions
202 let scope = &self.def_map[m.module_id]; 171 let scope = &self.def_map[m.module_id].scope;
203 let items = scope 172 let items = scope
204 .items 173 .items
205 .iter() 174 .iter()
@@ -243,11 +212,9 @@ where
243 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 212 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
244 213
245 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 214 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
246 if let Some(root_module) = self.krate.root_module(self.db) { 215 if import.is_extern_crate && module_id == self.def_map.root {
247 if import.is_extern_crate && module_id == root_module.module_id { 216 if let Some(def) = def.take_types() {
248 if let Some(def) = def.take_types() { 217 self.def_map.extern_prelude.insert(name.clone(), def);
249 self.def_map.extern_prelude.insert(name.clone(), def);
250 }
251 } 218 }
252 } 219 }
253 let resolution = Resolution { def, import: Some(import_id) }; 220 let resolution = Resolution { def, import: Some(import_id) };
@@ -324,8 +291,7 @@ where
324 Some(it) => it, 291 Some(it) => it,
325 _ => return true, 292 _ => return true,
326 }; 293 };
327 // FIXME: this should be a proper query 294 let def_map = self.db.crate_def_map(krate);
328 let def_map = crate_def_map_query(self.db, krate);
329 let rules = def_map.public_macros.get(&path.segments[1].name).cloned(); 295 let rules = def_map.public_macros.get(&path.segments[1].name).cloned();
330 resolved.push((*module_id, *call_id, rules, tt.clone())); 296 resolved.push((*module_id, *call_id, rules, tt.clone()));
331 false 297 false
@@ -367,6 +333,14 @@ where
367 } 333 }
368} 334}
369 335
336/// Walks a single module, populating defs, imports and macros
337struct ModCollector<'a, D> {
338 def_collector: D,
339 module_id: ModuleId,
340 file_id: HirFileId,
341 raw_items: &'a raw::RawItems,
342}
343
370impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> 344impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>>
371where 345where
372 DB: PersistentHirDatabase, 346 DB: PersistentHirDatabase,
@@ -389,8 +363,12 @@ where
389 fn collect_module(&mut self, module: &raw::ModuleData) { 363 fn collect_module(&mut self, module: &raw::ModuleData) {
390 match module { 364 match module {
391 // inline module, just recurse 365 // inline module, just recurse
392 raw::ModuleData::Definition { name, items } => { 366 raw::ModuleData::Definition { name, items, source_item_id } => {
393 let module_id = self.push_child_module(name.clone()); 367 let module_id = self.push_child_module(
368 name.clone(),
369 source_item_id.with_file_id(self.file_id),
370 None,
371 );
394 ModCollector { 372 ModCollector {
395 def_collector: &mut *self.def_collector, 373 def_collector: &mut *self.def_collector,
396 module_id, 374 module_id,
@@ -400,13 +378,20 @@ where
400 .collect(&*items); 378 .collect(&*items);
401 } 379 }
402 // out of line module, resovle, parse and recurse 380 // out of line module, resovle, parse and recurse
403 raw::ModuleData::Declaration { name } => { 381 raw::ModuleData::Declaration { name, source_item_id } => {
404 let module_id = self.push_child_module(name.clone()); 382 let source_item_id = source_item_id.with_file_id(self.file_id);
405 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 383 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
406 if let Some(file_id) = 384 let (file_ids, problem) =
407 resolve_module_declaration(self.def_collector.db, self.file_id, name, is_root) 385 resolve_submodule(self.def_collector.db, self.file_id, name, is_root);
408 { 386
409 let raw_items = raw::RawItems::raw_items_query(self.def_collector.db, file_id); 387 if let Some(problem) = problem {
388 self.def_collector.def_map.problems.add(source_item_id, problem)
389 }
390
391 if let Some(&file_id) = file_ids.first() {
392 let module_id =
393 self.push_child_module(name.clone(), source_item_id, Some(file_id));
394 let raw_items = self.def_collector.db.raw_items(file_id);
410 ModCollector { 395 ModCollector {
411 def_collector: &mut *self.def_collector, 396 def_collector: &mut *self.def_collector,
412 module_id, 397 module_id,
@@ -419,15 +404,23 @@ where
419 } 404 }
420 } 405 }
421 406
422 fn push_child_module(&mut self, name: Name) -> ModuleId { 407 fn push_child_module(
423 let res = self.def_collector.alloc_module(); 408 &mut self,
424 self.def_collector.def_map.modules[res].parent = Some(self.module_id); 409 name: Name,
425 self.def_collector.def_map.modules[self.module_id].children.insert(name, res); 410 declaration: SourceItemId,
411 definition: Option<FileId>,
412 ) -> ModuleId {
413 let modules = &mut self.def_collector.def_map.modules;
414 let res = modules.alloc(ModuleData::default());
415 modules[res].parent = Some(self.module_id);
416 modules[res].declaration = Some(declaration);
417 modules[res].definition = definition;
418 modules[self.module_id].children.insert(name, res);
426 res 419 res
427 } 420 }
428 421
429 fn define_def(&mut self, def: &raw::DefData) { 422 fn define_def(&mut self, def: &raw::DefData) {
430 let module = Module { krate: self.def_collector.krate, module_id: self.module_id }; 423 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id };
431 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into()); 424 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into());
432 macro_rules! id { 425 macro_rules! id {
433 () => { 426 () => {
@@ -462,7 +455,7 @@ where
462 455
463 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; 456 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id };
464 let macro_call_id = MacroCallLoc { 457 let macro_call_id = MacroCallLoc {
465 module: Module { krate: self.def_collector.krate, module_id: self.module_id }, 458 module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id },
466 source_item_id, 459 source_item_id,
467 } 460 }
468 .id(self.def_collector.db); 461 .id(self.def_collector.db);
@@ -491,3 +484,44 @@ where
491fn is_macro_rules(path: &Path) -> bool { 484fn is_macro_rules(path: &Path) -> bool {
492 path.as_ident().and_then(Name::as_known_name) == Some(KnownName::MacroRules) 485 path.as_ident().and_then(Name::as_known_name) == Some(KnownName::MacroRules)
493} 486}
487
488fn resolve_submodule(
489 db: &impl PersistentHirDatabase,
490 file_id: HirFileId,
491 name: &Name,
492 is_root: bool,
493) -> (Vec<FileId>, Option<Problem>) {
494 // FIXME: handle submodules of inline modules properly
495 let file_id = file_id.original_file(db);
496 let source_root_id = db.file_source_root(file_id);
497 let path = db.file_relative_path(file_id);
498 let root = RelativePathBuf::default();
499 let dir_path = path.parent().unwrap_or(&root);
500 let mod_name = path.file_stem().unwrap_or("unknown");
501 let is_dir_owner = is_root || mod_name == "mod";
502
503 let file_mod = dir_path.join(format!("{}.rs", name));
504 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
505 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
506 let mut candidates = ArrayVec::<[_; 2]>::new();
507 if is_dir_owner {
508 candidates.push(file_mod.clone());
509 candidates.push(dir_mod);
510 } else {
511 candidates.push(file_dir_mod.clone());
512 };
513 let sr = db.source_root(source_root_id);
514 let points_to = candidates
515 .into_iter()
516 .filter_map(|path| sr.files.get(&path))
517 .map(|&it| it)
518 .collect::<Vec<_>>();
519 let problem = if points_to.is_empty() {
520 Some(Problem::UnresolvedModule {
521 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
522 })
523 } else {
524 None
525 };
526 (points_to, problem)
527}
diff --git a/crates/ra_hir/src/nameres/crate_def_map/raw.rs b/crates/ra_hir/src/nameres/crate_def_map/raw.rs
index fe832b8da..f064f722c 100644
--- a/crates/ra_hir/src/nameres/crate_def_map/raw.rs
+++ b/crates/ra_hir/src/nameres/crate_def_map/raw.rs
@@ -3,6 +3,7 @@ use std::{
3 ops::Index, 3 ops::Index,
4}; 4};
5 5
6use test_utils::tested_by;
6use ra_db::FileId; 7use ra_db::FileId;
7use ra_arena::{Arena, impl_arena_id, RawId}; 8use ra_arena::{Arena, impl_arena_id, RawId};
8use ra_syntax::{ 9use ra_syntax::{
@@ -15,8 +16,8 @@ use crate::{
15 ids::{SourceFileItemId, SourceFileItems}, 16 ids::{SourceFileItemId, SourceFileItems},
16}; 17};
17 18
18#[derive(Default, PartialEq, Eq)] 19#[derive(Debug, Default, PartialEq, Eq)]
19pub(crate) struct RawItems { 20pub struct RawItems {
20 modules: Arena<Module, ModuleData>, 21 modules: Arena<Module, ModuleData>,
21 imports: Arena<ImportId, ImportData>, 22 imports: Arena<ImportId, ImportData>,
22 defs: Arena<Def, DefData>, 23 defs: Arena<Def, DefData>,
@@ -26,18 +27,21 @@ pub(crate) struct RawItems {
26} 27}
27 28
28impl RawItems { 29impl RawItems {
29 pub(crate) fn items(&self) -> &[RawItem] { 30 pub(crate) fn raw_items_query(
30 &self.items 31 db: &impl PersistentHirDatabase,
31 } 32 file_id: FileId,
32 33 ) -> Arc<RawItems> {
33 pub(crate) fn raw_items_query(db: &impl PersistentHirDatabase, file_id: FileId) -> RawItems {
34 let mut collector = RawItemsCollector { 34 let mut collector = RawItemsCollector {
35 raw_items: RawItems::default(), 35 raw_items: RawItems::default(),
36 source_file_items: db.file_items(file_id.into()), 36 source_file_items: db.file_items(file_id.into()),
37 }; 37 };
38 let source_file = db.parse(file_id); 38 let source_file = db.parse(file_id);
39 collector.process_module(None, &*source_file); 39 collector.process_module(None, &*source_file);
40 collector.raw_items 40 Arc::new(collector.raw_items)
41 }
42
43 pub(crate) fn items(&self) -> &[RawItem] {
44 &self.items
41 } 45 }
42 46
43 // We can't use queries during name resolution for fear of cycles, so this 47 // We can't use queries during name resolution for fear of cycles, so this
@@ -81,7 +85,7 @@ impl Index<Macro> for RawItems {
81 } 85 }
82} 86}
83 87
84#[derive(PartialEq, Eq, Clone, Copy)] 88#[derive(Debug, PartialEq, Eq, Clone, Copy)]
85pub(crate) enum RawItem { 89pub(crate) enum RawItem {
86 Module(Module), 90 Module(Module),
87 Import(ImportId), 91 Import(ImportId),
@@ -89,24 +93,24 @@ pub(crate) enum RawItem {
89 Macro(Macro), 93 Macro(Macro),
90} 94}
91 95
92#[derive(Clone, Copy, PartialEq, Eq, Hash)] 96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
93pub(crate) struct Module(RawId); 97pub(crate) struct Module(RawId);
94impl_arena_id!(Module); 98impl_arena_id!(Module);
95 99
96#[derive(PartialEq, Eq)] 100#[derive(Debug, PartialEq, Eq)]
97pub(crate) enum ModuleData { 101pub(crate) enum ModuleData {
98 Declaration { name: Name }, 102 Declaration { name: Name, source_item_id: SourceFileItemId },
99 Definition { name: Name, items: Vec<RawItem> }, 103 Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> },
100} 104}
101 105
102pub(crate) use crate::nameres::lower::ImportId; 106pub(crate) use crate::nameres::lower::ImportId;
103pub(super) use crate::nameres::lower::ImportData; 107pub(super) use crate::nameres::lower::ImportData;
104 108
105#[derive(Clone, Copy, PartialEq, Eq, Hash)] 109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106pub(crate) struct Def(RawId); 110pub(crate) struct Def(RawId);
107impl_arena_id!(Def); 111impl_arena_id!(Def);
108 112
109#[derive(PartialEq, Eq)] 113#[derive(Debug, PartialEq, Eq)]
110pub(crate) struct DefData { 114pub(crate) struct DefData {
111 pub(crate) source_item_id: SourceFileItemId, 115 pub(crate) source_item_id: SourceFileItemId,
112 pub(crate) name: Name, 116 pub(crate) name: Name,
@@ -124,11 +128,11 @@ pub(crate) enum DefKind {
124 TypeAlias, 128 TypeAlias,
125} 129}
126 130
127#[derive(Clone, Copy, PartialEq, Eq, Hash)] 131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128pub(crate) struct Macro(RawId); 132pub(crate) struct Macro(RawId);
129impl_arena_id!(Macro); 133impl_arena_id!(Macro);
130 134
131#[derive(PartialEq, Eq)] 135#[derive(Debug, PartialEq, Eq)]
132pub(crate) struct MacroData { 136pub(crate) struct MacroData {
133 pub(crate) source_item_id: SourceFileItemId, 137 pub(crate) source_item_id: SourceFileItemId,
134 pub(crate) path: Path, 138 pub(crate) path: Path,
@@ -191,18 +195,25 @@ impl RawItemsCollector {
191 Some(it) => it.as_name(), 195 Some(it) => it.as_name(),
192 None => return, 196 None => return,
193 }; 197 };
198 let source_item_id = self.source_file_items.id_of_unchecked(module.syntax());
194 if module.has_semi() { 199 if module.has_semi() {
195 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name }); 200 let item =
201 self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
196 self.push_item(current_module, RawItem::Module(item)); 202 self.push_item(current_module, RawItem::Module(item));
197 return; 203 return;
198 } 204 }
199 205
200 if let Some(item_list) = module.item_list() { 206 if let Some(item_list) = module.item_list() {
201 let item = 207 let item = self.raw_items.modules.alloc(ModuleData::Definition {
202 self.raw_items.modules.alloc(ModuleData::Definition { name, items: Vec::new() }); 208 name,
209 source_item_id,
210 items: Vec::new(),
211 });
203 self.process_module(Some(item), item_list); 212 self.process_module(Some(item), item_list);
204 self.push_item(current_module, RawItem::Module(item)); 213 self.push_item(current_module, RawItem::Module(item));
214 return;
205 } 215 }
216 tested_by!(name_res_works_for_broken_modules);
206 } 217 }
207 218
208 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) { 219 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
diff --git a/crates/ra_hir/src/nameres/crate_def_map/tests.rs b/crates/ra_hir/src/nameres/crate_def_map/tests.rs
index a56dbaf90..742a19e5c 100644
--- a/crates/ra_hir/src/nameres/crate_def_map/tests.rs
+++ b/crates/ra_hir/src/nameres/crate_def_map/tests.rs
@@ -15,7 +15,7 @@ fn compute_crate_def_map(fixture: &str, graph: Option<CrateGraphFixture>) -> Arc
15 } 15 }
16 let crate_id = db.crate_graph().iter().next().unwrap(); 16 let crate_id = db.crate_graph().iter().next().unwrap();
17 let krate = Crate { crate_id }; 17 let krate = Crate { crate_id };
18 collector::crate_def_map_query(&db, krate) 18 db.crate_def_map(krate)
19} 19}
20 20
21fn render_crate_def_map(map: &CrateDefMap) -> String { 21fn render_crate_def_map(map: &CrateDefMap) -> String {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 9b151bb0c..961e442a9 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -7,7 +7,7 @@ use crate::{
7 ItemMap, 7 ItemMap,
8 PersistentHirDatabase, 8 PersistentHirDatabase,
9 mock::MockDatabase, 9 mock::MockDatabase,
10 module_tree::ModuleId, 10 nameres::crate_def_map::ModuleId,
11}; 11};
12use super::Resolution; 12use super::Resolution;
13 13
@@ -359,6 +359,7 @@ fn std_prelude() {
359 let main_id = db.file_id_of("/main.rs"); 359 let main_id = db.file_id_of("/main.rs");
360 360
361 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); 361 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
362 eprintln!("module = {:?}", module);
362 let krate = module.krate(&db).unwrap(); 363 let krate = module.krate(&db).unwrap();
363 let item_map = db.item_map(krate); 364 let item_map = db.item_map(krate);
364 365
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 4a9921a85..62b699a64 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -80,8 +80,8 @@ fn module_from_source(
80 let source_root_id = db.file_source_root(file_id.as_original_file()); 80 let source_root_id = db.file_source_root(file_id.as_original_file());
81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( 81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
82 |krate| { 82 |krate| {
83 let module_tree = db.module_tree(krate); 83 let def_map = db.crate_def_map(krate);
84 let module_id = module_tree.find_module_by_source(file_id, decl_id)?; 84 let module_id = def_map.find_module_by_source(file_id, decl_id)?;
85 Some(Module { krate, module_id }) 85 Some(Module { krate, module_id })
86 }, 86 },
87 ) 87 )
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 94b757af2..7c77474b0 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -7,10 +7,12 @@ use std::sync::Arc;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait, 10 HirDatabase, Module, Crate, Name, Function, Trait,
11 ids::TraitId, 11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 12 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{AdtDef, Ty}, 13 ty::{AdtDef, Ty},
14 nameres::crate_def_map::ModuleId,
15
14}; 16};
15 17
16/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index d64b5a4e0..2395930f0 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -1,7 +1,7 @@
1use itertools::Itertools; 1use itertools::Itertools;
2use ra_syntax::{ 2use ra_syntax::{
3 TextRange, SyntaxNode, 3 TextRange, SyntaxNode,
4 ast::{self, AstNode, NameOwner, ModuleItemOwner}, 4 ast::{self, AstNode, NameOwner, ModuleItemOwner, AttrsOwner},
5}; 5};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7 7