aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 14:51:10 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 14:51:10 +0000
commitcf0ce14351af03c620aca784ee2c03aad86b866e (patch)
treebffd84981df9cca1143807796dc6772ddcfe8e0b /crates
parenteaf553dade9a28b41631387d7c88b09fd0ba64e2 (diff)
parent733383446fc229a35d4432d14c295c5a01e5a87f (diff)
Merge #429
429: Reorganize hir public API in terms of code model r=matklad a=matklad Recently, I've been thinking about introducing "object orient code model" API for rust: a set of APIs with types like `Function`, `Module`, etc, with methods like `get_containing_declaration()`, `get_type()`, etc. Here's how a similar API might look like in .Net land: https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.semanticmodel?view=roslyn-dotnet https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.imethodsymbol?view=roslyn-dotnet The main feature of such API is that it can be powered by different backends. For example, one can imagine a backend based on salsa, and a backend which reads all the data from a specially prepared JSON file. The "OO" bit is interesting mostly in this "can swap implementations via dynamic dispatch" aspect, the actual API could have a more database/ECS flavored feeling. It's not clear at this moment how exactly should we implement such a dynamically (or if we even need dynamism in the first pace) swapable API in Rust, but I'd love to experiment with this a bit. For starters, I propose creating a `code_model_api` which contains various definition types and their public methods (mandatory implemented as one-liners, so that the API has a header-file feel). Specifically, I propose that each type is a wrapper around some integer ID, and that all methods of it accept a `&db` argument. The actual impl goes elsewhere: into the db queries or, absent a better place, into the `code_model_api_impl`. In the first commit, I've moved the simplest type, `Crate`, over to this pattern. I *think* that we, at least initially, will be used types from `code_model_api` *inside* `hir` as well, but this is not required: we might pick a different implementation down the line, while preserving the API. Long term I'd love to replace the `db: &impl HirDatabase` argument by a `mp: &dyn ModelProvider`, implement `ModelProvider` for `T: HirDatabase`, and move `code_model_api` into the separate crate, which does not depend on `hir`. @flodiebold you've recently done some `Def`s work, would do you think of this plan? Could it become a good API in the future, or is it just a useless boilerplate duplicating method signatures between `code_model_api` and `code_model_impl`? Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/completion/complete_scope.rs5
-rw-r--r--crates/ra_analysis/src/goto_defenition.rs4
-rw-r--r--crates/ra_analysis/src/imp.rs30
-rw-r--r--crates/ra_analysis/src/lib.rs2
-rw-r--r--crates/ra_analysis/src/runnables.rs9
-rw-r--r--crates/ra_analysis/tests/test/main.rs1
-rw-r--r--crates/ra_hir/src/code_model_api.rs110
-rw-r--r--crates/ra_hir/src/code_model_impl.rs2
-rw-r--r--crates/ra_hir/src/code_model_impl/krate.rs (renamed from crates/ra_hir/src/krate.rs)35
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs154
-rw-r--r--crates/ra_hir/src/db.rs10
-rw-r--r--crates/ra_hir/src/ids.rs10
-rw-r--r--crates/ra_hir/src/impl_block.rs32
-rw-r--r--crates/ra_hir/src/lib.rs17
-rw-r--r--crates/ra_hir/src/module.rs376
-rw-r--r--crates/ra_hir/src/module/imp.rs190
-rw-r--r--crates/ra_hir/src/module_tree.rs409
-rw-r--r--crates/ra_hir/src/nameres.rs (renamed from crates/ra_hir/src/module/nameres.rs)12
-rw-r--r--crates/ra_hir/src/nameres/tests.rs (renamed from crates/ra_hir/src/module/nameres/tests.rs)4
-rw-r--r--crates/ra_hir/src/query_definitions.rs59
-rw-r--r--crates/ra_hir/src/source_binder.rs28
21 files changed, 790 insertions, 709 deletions
diff --git a/crates/ra_analysis/src/completion/complete_scope.rs b/crates/ra_analysis/src/completion/complete_scope.rs
index 21d77aa97..ee9052d3d 100644
--- a/crates/ra_analysis/src/completion/complete_scope.rs
+++ b/crates/ra_analysis/src/completion/complete_scope.rs
@@ -20,14 +20,17 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
20 } 20 }
21 21
22 let module_scope = module.scope(ctx.db)?; 22 let module_scope = module.scope(ctx.db)?;
23 let (file_id, _) = module.defenition_source(ctx.db)?;
23 module_scope 24 module_scope
24 .entries() 25 .entries()
25 .filter(|(_name, res)| { 26 .filter(|(_name, res)| {
26 // Don't expose this item 27 // Don't expose this item
28 // FIXME: this penetrates through all kinds of abstractions,
29 // we need to figura out the way to do it less ugly.
27 match res.import { 30 match res.import {
28 None => true, 31 None => true,
29 Some(import) => { 32 Some(import) => {
30 let range = import.range(ctx.db, module.file_id()); 33 let range = import.range(ctx.db, file_id);
31 !range.is_subrange(&ctx.leaf.range()) 34 !range.is_subrange(&ctx.leaf.range())
32 } 35 }
33 } 36 }
diff --git a/crates/ra_analysis/src/goto_defenition.rs b/crates/ra_analysis/src/goto_defenition.rs
index 68b6ac3ba..aa0616e3b 100644
--- a/crates/ra_analysis/src/goto_defenition.rs
+++ b/crates/ra_analysis/src/goto_defenition.rs
@@ -60,8 +60,8 @@ fn name_defenition(
60 if let Some(child_module) = 60 if let Some(child_module) =
61 hir::source_binder::module_from_declaration(db, file_id, module)? 61 hir::source_binder::module_from_declaration(db, file_id, module)?
62 { 62 {
63 let file_id = child_module.file_id(); 63 let (file_id, _) = child_module.defenition_source(db)?;
64 let name = match child_module.name() { 64 let name = match child_module.name(db)? {
65 Some(name) => name.to_string().into(), 65 Some(name) => name.to_string().into(),
66 None => "".into(), 66 None => "".into(),
67 }; 67 };
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 5988fb779..07a966290 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -105,39 +105,35 @@ impl db::RootDatabase {
105 &self, 105 &self,
106 position: FilePosition, 106 position: FilePosition,
107 ) -> Cancelable<Vec<NavigationTarget>> { 107 ) -> Cancelable<Vec<NavigationTarget>> {
108 let descr = match source_binder::module_from_position(self, position)? { 108 let module = match source_binder::module_from_position(self, position)? {
109 None => return Ok(Vec::new()), 109 None => return Ok(Vec::new()),
110 Some(it) => it, 110 Some(it) => it,
111 }; 111 };
112 let (file_id, decl) = match descr.parent_link_source(self) { 112 let (file_id, ast_module) = match module.declaration_source(self)? {
113 None => return Ok(Vec::new()), 113 None => return Ok(Vec::new()),
114 Some(it) => it, 114 Some(it) => it,
115 }; 115 };
116 let decl = decl.borrowed(); 116 let ast_module = ast_module.borrowed();
117 let decl_name = decl.name().unwrap(); 117 let name = ast_module.name().unwrap();
118 Ok(vec![NavigationTarget { 118 Ok(vec![NavigationTarget {
119 file_id, 119 file_id,
120 name: decl_name.text(), 120 name: name.text(),
121 range: decl_name.syntax().range(), 121 range: name.syntax().range(),
122 kind: MODULE, 122 kind: MODULE,
123 ptr: None, 123 ptr: None,
124 }]) 124 }])
125 } 125 }
126 /// Returns `Vec` for the same reason as `parent_module` 126 /// Returns `Vec` for the same reason as `parent_module`
127 pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 127 pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
128 let descr = match source_binder::module_from_file_id(self, file_id)? { 128 let module = match source_binder::module_from_file_id(self, file_id)? {
129 Some(it) => it,
129 None => return Ok(Vec::new()), 130 None => return Ok(Vec::new()),
131 };
132 let krate = match module.krate(self)? {
130 Some(it) => it, 133 Some(it) => it,
134 None => return Ok(Vec::new()),
131 }; 135 };
132 let root = descr.crate_root(); 136 Ok(vec![krate.crate_id()])
133 let file_id = root.file_id();
134
135 let crate_graph = self.crate_graph();
136 let crate_id = crate_graph.crate_id_for_crate_root(file_id);
137 Ok(crate_id.into_iter().collect())
138 }
139 pub(crate) fn crate_root(&self, crate_id: CrateId) -> FileId {
140 self.crate_graph().crate_root(crate_id)
141 } 137 }
142 pub(crate) fn find_all_refs( 138 pub(crate) fn find_all_refs(
143 &self, 139 &self,
@@ -209,7 +205,7 @@ impl db::RootDatabase {
209 }) 205 })
210 .collect::<Vec<_>>(); 206 .collect::<Vec<_>>();
211 if let Some(m) = source_binder::module_from_file_id(self, file_id)? { 207 if let Some(m) = source_binder::module_from_file_id(self, file_id)? {
212 for (name_node, problem) in m.problems(self) { 208 for (name_node, problem) in m.problems(self)? {
213 let source_root = self.file_source_root(file_id); 209 let source_root = self.file_source_root(file_id);
214 let diag = match problem { 210 let diag = match problem {
215 Problem::UnresolvedModule { candidate } => { 211 Problem::UnresolvedModule { candidate } => {
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 390c31c3f..77f77e9a8 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -397,7 +397,7 @@ impl Analysis {
397 } 397 }
398 /// Returns the root file of the given crate. 398 /// Returns the root file of the given crate.
399 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { 399 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
400 Ok(self.db.crate_root(crate_id)) 400 Ok(self.db.crate_graph().crate_root(crate_id))
401 } 401 }
402 /// Returns the set of possible targets to run for the current file. 402 /// Returns the set of possible targets to run for the current file.
403 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { 403 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
diff --git a/crates/ra_analysis/src/runnables.rs b/crates/ra_analysis/src/runnables.rs
index 474267605..216209098 100644
--- a/crates/ra_analysis/src/runnables.rs
+++ b/crates/ra_analysis/src/runnables.rs
@@ -72,12 +72,15 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
72 let range = module.syntax().range(); 72 let range = module.syntax().range();
73 let module = 73 let module =
74 hir::source_binder::module_from_child_node(db, file_id, module.syntax()).ok()??; 74 hir::source_binder::module_from_child_node(db, file_id, module.syntax()).ok()??;
75
76 // FIXME: thread cancellation instead of `.ok`ing
75 let path = module 77 let path = module
76 .path_to_root() 78 .path_to_root(db)
79 .ok()?
77 .into_iter() 80 .into_iter()
78 .rev() 81 .rev()
79 .into_iter() 82 .filter_map(|it| it.name(db).ok())
80 .filter_map(|it| it.name().map(Clone::clone)) 83 .filter_map(|it| it)
81 .join("::"); 84 .join("::");
82 Some(Runnable { 85 Some(Runnable {
83 range, 86 range,
diff --git a/crates/ra_analysis/tests/test/main.rs b/crates/ra_analysis/tests/test/main.rs
index 26da7c10c..85911de92 100644
--- a/crates/ra_analysis/tests/test/main.rs
+++ b/crates/ra_analysis/tests/test/main.rs
@@ -31,6 +31,7 @@ fn test_unresolved_module_diagnostic() {
31 ); 31 );
32} 32}
33 33
34// FIXME: move this test to hir
34#[test] 35#[test]
35fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 36fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
36 let (analysis, file_id) = single_file("mod foo {}"); 37 let (analysis, file_id) = single_file("mod foo {}");
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
new file mode 100644
index 000000000..09b532f74
--- /dev/null
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -0,0 +1,110 @@
1use relative_path::RelativePathBuf;
2use ra_db::{CrateId, Cancelable, FileId};
3use ra_syntax::{ast, SyntaxNode};
4
5use crate::{Name, db::HirDatabase, DefId, Path, PerNs, nameres::ModuleScope};
6
7/// hir::Crate describes a single crate. It's the main inteface with which
8/// crate's dependencies interact. Mostly, it should be just a proxy for the
9/// root module.
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub struct Crate {
12 pub(crate) crate_id: CrateId,
13}
14
15#[derive(Debug)]
16pub struct CrateDependency {
17 pub krate: Crate,
18 pub name: Name,
19}
20
21impl Crate {
22 pub fn crate_id(&self) -> CrateId {
23 self.crate_id
24 }
25 pub fn dependencies(&self, db: &impl HirDatabase) -> Cancelable<Vec<CrateDependency>> {
26 Ok(self.dependencies_impl(db))
27 }
28 pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
29 self.root_module_impl(db)
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct Module {
35 pub(crate) def_id: DefId,
36}
37
38pub enum ModuleSource {
39 SourceFile(ast::SourceFileNode),
40 Module(ast::ModuleNode),
41}
42
43#[derive(Clone, Debug, Hash, PartialEq, Eq)]
44pub enum Problem {
45 UnresolvedModule {
46 candidate: RelativePathBuf,
47 },
48 NotDirOwner {
49 move_to: RelativePathBuf,
50 candidate: RelativePathBuf,
51 },
52}
53
54impl Module {
55 /// Name of this module.
56 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
57 self.name_impl(db)
58 }
59
60 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
61 pub fn defenition_source(&self, db: &impl HirDatabase) -> Cancelable<(FileId, ModuleSource)> {
62 self.defenition_source_impl(db)
63 }
64 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
65 /// `None` for the crate root.
66 pub fn declaration_source(
67 &self,
68 db: &impl HirDatabase,
69 ) -> Cancelable<Option<(FileId, ast::ModuleNode)>> {
70 self.declaration_source_impl(db)
71 }
72
73 /// Returns the crate this module is part of.
74 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
75 self.krate_impl(db)
76 }
77 /// Topmost parent of this module. Every module has a `crate_root`, but some
78 /// might miss `krate`. This can happen if a module's file is not included
79 /// into any module tree of any target from Cargo.toml.
80 pub fn crate_root(&self, db: &impl HirDatabase) -> Cancelable<Module> {
81 self.crate_root_impl(db)
82 }
83 /// Finds a child module with the specified name.
84 pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
85 self.child_impl(db, name)
86 }
87 /// Finds a parent module.
88 pub fn parent(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
89 self.parent_impl(db)
90 }
91 pub fn path_to_root(&self, db: &impl HirDatabase) -> Cancelable<Vec<Module>> {
92 let mut res = vec![self.clone()];
93 let mut curr = self.clone();
94 while let Some(next) = curr.parent(db)? {
95 res.push(next.clone());
96 curr = next
97 }
98 Ok(res)
99 }
100 /// Returns a `ModuleScope`: a set of items, visible in this module.
101 pub fn scope(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
102 self.scope_impl(db)
103 }
104 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
105 self.resolve_path_impl(db, path)
106 }
107 pub fn problems(&self, db: &impl HirDatabase) -> Cancelable<Vec<(SyntaxNode, Problem)>> {
108 self.problems_impl(db)
109 }
110}
diff --git a/crates/ra_hir/src/code_model_impl.rs b/crates/ra_hir/src/code_model_impl.rs
new file mode 100644
index 000000000..157b0c616
--- /dev/null
+++ b/crates/ra_hir/src/code_model_impl.rs
@@ -0,0 +1,2 @@
1mod krate; // `crate` is invalid ident :(
2mod module;
diff --git a/crates/ra_hir/src/krate.rs b/crates/ra_hir/src/code_model_impl/krate.rs
index 5194e280b..591a81597 100644
--- a/crates/ra_hir/src/krate.rs
+++ b/crates/ra_hir/src/code_model_impl/krate.rs
@@ -1,26 +1,15 @@
1pub use ra_db::{CrateId, Cancelable}; 1use ra_db::{CrateId, Cancelable};
2 2
3use crate::{HirDatabase, Module, Name, AsName, HirFileId}; 3use crate::{
4 4 HirFileId, Crate, CrateDependency, AsName, DefLoc, DefKind, Module,
5/// hir::Crate describes a single crate. It's the main inteface with which 5 db::HirDatabase,
6/// crate's dependencies interact. Mostly, it should be just a proxy for the 6};
7/// root module.
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct Crate {
10 crate_id: CrateId,
11}
12
13#[derive(Debug)]
14pub struct CrateDependency {
15 pub krate: Crate,
16 pub name: Name,
17}
18 7
19impl Crate { 8impl Crate {
20 pub(crate) fn new(crate_id: CrateId) -> Crate { 9 pub(crate) fn new(crate_id: CrateId) -> Crate {
21 Crate { crate_id } 10 Crate { crate_id }
22 } 11 }
23 pub fn dependencies(&self, db: &impl HirDatabase) -> Vec<CrateDependency> { 12 pub(crate) fn dependencies_impl(&self, db: &impl HirDatabase) -> Vec<CrateDependency> {
24 let crate_graph = db.crate_graph(); 13 let crate_graph = db.crate_graph();
25 crate_graph 14 crate_graph
26 .dependencies(self.crate_id) 15 .dependencies(self.crate_id)
@@ -31,7 +20,7 @@ impl Crate {
31 }) 20 })
32 .collect() 21 .collect()
33 } 22 }
34 pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> { 23 pub(crate) fn root_module_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
35 let crate_graph = db.crate_graph(); 24 let crate_graph = db.crate_graph();
36 let file_id = crate_graph.crate_root(self.crate_id); 25 let file_id = crate_graph.crate_root(self.crate_id);
37 let source_root_id = db.file_source_root(file_id); 26 let source_root_id = db.file_source_root(file_id);
@@ -42,7 +31,15 @@ impl Crate {
42 .modules_with_sources() 31 .modules_with_sources()
43 .find(|(_, src)| src.file_id() == file_id)); 32 .find(|(_, src)| src.file_id() == file_id));
44 33
45 let module = Module::new(db, source_root_id, module_id)?; 34 let def_loc = DefLoc {
35 kind: DefKind::Module,
36 source_root_id,
37 module_id,
38 source_item_id: module_id.source(&module_tree).0,
39 };
40 let def_id = def_loc.id(db);
41
42 let module = Module::new(def_id);
46 Ok(Some(module)) 43 Ok(Some(module))
47 } 44 }
48} 45}
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
new file mode 100644
index 000000000..02078f188
--- /dev/null
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -0,0 +1,154 @@
1use ra_db::{Cancelable, SourceRootId, FileId};
2use ra_syntax::{ast, SyntaxNode, AstNode};
3
4use crate::{
5 Module, ModuleSource, Problem,
6 Crate, DefId, DefLoc, DefKind, Name, Path, PathKind, PerNs, Def, ModuleId,
7 nameres::ModuleScope,
8 db::HirDatabase,
9};
10
11impl Module {
12 pub(crate) fn new(def_id: DefId) -> Self {
13 crate::code_model_api::Module { def_id }
14 }
15 pub(crate) fn from_module_id(
16 db: &impl HirDatabase,
17 source_root_id: SourceRootId,
18 module_id: ModuleId,
19 ) -> Cancelable<Self> {
20 let module_tree = db.module_tree(source_root_id)?;
21 let def_loc = DefLoc {
22 kind: DefKind::Module,
23 source_root_id,
24 module_id,
25 source_item_id: module_id.source(&module_tree).0,
26 };
27 let def_id = def_loc.id(db);
28 let module = Module::new(def_id);
29 Ok(module)
30 }
31
32 pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
33 let loc = self.def_id.loc(db);
34 let module_tree = db.module_tree(loc.source_root_id)?;
35 let link = ctry!(loc.module_id.parent_link(&module_tree));
36 Ok(Some(link.name(&module_tree).clone()))
37 }
38
39 pub fn defenition_source_impl(
40 &self,
41 db: &impl HirDatabase,
42 ) -> Cancelable<(FileId, ModuleSource)> {
43 let loc = self.def_id.loc(db);
44 let file_id = loc.source_item_id.file_id.as_original_file();
45 let syntax_node = db.file_item(loc.source_item_id);
46 let syntax_node = syntax_node.borrowed();
47 let module_source = if let Some(source_file) = ast::SourceFile::cast(syntax_node) {
48 ModuleSource::SourceFile(source_file.owned())
49 } else {
50 let module = ast::Module::cast(syntax_node).unwrap();
51 ModuleSource::Module(module.owned())
52 };
53 Ok((file_id, module_source))
54 }
55
56 pub fn declaration_source_impl(
57 &self,
58 db: &impl HirDatabase,
59 ) -> Cancelable<Option<(FileId, ast::ModuleNode)>> {
60 let loc = self.def_id.loc(db);
61 let module_tree = db.module_tree(loc.source_root_id)?;
62 let link = ctry!(loc.module_id.parent_link(&module_tree));
63 let file_id = link
64 .owner(&module_tree)
65 .source(&module_tree)
66 .file_id()
67 .as_original_file();
68 let src = link.bind_source(&module_tree, db);
69 Ok(Some((file_id, src)))
70 }
71
72 pub(crate) fn krate_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
73 let root = self.crate_root(db)?;
74 let loc = root.def_id.loc(db);
75 let file_id = loc.source_item_id.file_id.as_original_file();
76
77 let crate_graph = db.crate_graph();
78 let crate_id = ctry!(crate_graph.crate_id_for_crate_root(file_id));
79 Ok(Some(Crate::new(crate_id)))
80 }
81
82 pub(crate) fn crate_root_impl(&self, db: &impl HirDatabase) -> Cancelable<Module> {
83 let loc = self.def_id.loc(db);
84 let module_tree = db.module_tree(loc.source_root_id)?;
85 let module_id = loc.module_id.crate_root(&module_tree);
86 Module::from_module_id(db, loc.source_root_id, module_id)
87 }
88 /// Finds a child module with the specified name.
89 pub fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
90 let loc = self.def_id.loc(db);
91 let module_tree = db.module_tree(loc.source_root_id)?;
92 let child_id = ctry!(loc.module_id.child(&module_tree, name));
93 Module::from_module_id(db, loc.source_root_id, child_id).map(Some)
94 }
95 pub fn parent_impl(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
96 let loc = self.def_id.loc(db);
97 let module_tree = db.module_tree(loc.source_root_id)?;
98 let parent_id = ctry!(loc.module_id.parent(&module_tree));
99 Module::from_module_id(db, loc.source_root_id, parent_id).map(Some)
100 }
101 /// Returns a `ModuleScope`: a set of items, visible in this module.
102 pub fn scope_impl(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
103 let loc = self.def_id.loc(db);
104 let item_map = db.item_map(loc.source_root_id)?;
105 let res = item_map.per_module[&loc.module_id].clone();
106 Ok(res)
107 }
108 pub fn resolve_path_impl(
109 &self,
110 db: &impl HirDatabase,
111 path: &Path,
112 ) -> Cancelable<PerNs<DefId>> {
113 let mut curr_per_ns = PerNs::types(
114 match path.kind {
115 PathKind::Crate => self.crate_root(db)?,
116 PathKind::Self_ | PathKind::Plain => self.clone(),
117 PathKind::Super => {
118 if let Some(p) = self.parent(db)? {
119 p
120 } else {
121 return Ok(PerNs::none());
122 }
123 }
124 }
125 .def_id,
126 );
127
128 let segments = &path.segments;
129 for name in segments.iter() {
130 let curr = if let Some(r) = curr_per_ns.as_ref().take_types() {
131 r
132 } else {
133 return Ok(PerNs::none());
134 };
135 let module = match curr.resolve(db)? {
136 Def::Module(it) => it,
137 // TODO here would be the place to handle enum variants...
138 _ => return Ok(PerNs::none()),
139 };
140 let scope = module.scope(db)?;
141 curr_per_ns = if let Some(r) = scope.get(&name) {
142 r.def_id
143 } else {
144 return Ok(PerNs::none());
145 };
146 }
147 Ok(curr_per_ns)
148 }
149 pub fn problems_impl(&self, db: &impl HirDatabase) -> Cancelable<Vec<(SyntaxNode, Problem)>> {
150 let loc = self.def_id.loc(db);
151 let module_tree = db.module_tree(loc.source_root_id)?;
152 Ok(loc.module_id.problems(&module_tree, db))
153 }
154}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 96a3c60b9..e4249de14 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -9,8 +9,8 @@ use crate::{
9 query_definitions, 9 query_definitions,
10 FnSignature, FnScopes, 10 FnSignature, FnScopes,
11 macros::MacroExpansion, 11 macros::MacroExpansion,
12 module::{ModuleId, ModuleTree, ModuleSource, 12 module_tree::{ModuleId, ModuleTree, ModuleSource},
13 nameres::{ItemMap, InputModuleItems}}, 13 nameres::{ItemMap, InputModuleItems},
14 ty::{InferenceResult, Ty}, 14 ty::{InferenceResult, Ty},
15 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData},
16 impl_block::ModuleImplBlocks, 16 impl_block::ModuleImplBlocks,
@@ -71,9 +71,9 @@ pub trait HirDatabase: SyntaxDatabase
71 use fn query_definitions::file_item; 71 use fn query_definitions::file_item;
72 } 72 }
73 73
74 fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<crate::module::imp::Submodule>>> { 74 fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<crate::module_tree::Submodule>>> {
75 type SubmodulesQuery; 75 type SubmodulesQuery;
76 use fn query_definitions::submodules; 76 use fn crate::module_tree::Submodule::submodules_query;
77 } 77 }
78 78
79 fn input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> { 79 fn input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> {
@@ -86,7 +86,7 @@ pub trait HirDatabase: SyntaxDatabase
86 } 86 }
87 fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { 87 fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
88 type ModuleTreeQuery; 88 type ModuleTreeQuery;
89 use fn crate::module::imp::module_tree; 89 use fn crate::module_tree::ModuleTree::module_tree_query;
90 } 90 }
91 91
92 fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> { 92 fn impls_in_module(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleImplBlocks>> {
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 4d6378e02..c7391ee05 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -2,7 +2,9 @@ use ra_db::{SourceRootId, LocationIntener, Cancelable, FileId};
2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast}; 2use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, SourceFile, AstNode, ast};
3use ra_arena::{Arena, RawId, impl_arena_id}; 3use ra_arena::{Arena, RawId, impl_arena_id};
4 4
5use crate::{HirDatabase, PerNs, ModuleId, Module, Def, Function, Struct, Enum, ImplBlock, Crate}; 5use crate::{HirDatabase, PerNs, ModuleId, Def, Function, Struct, Enum, ImplBlock, Crate};
6
7use crate::code_model_api::Module;
6 8
7/// hir makes a heavy use of ids: integer (u32) handlers to various things. You 9/// hir makes a heavy use of ids: integer (u32) handlers to various things. You
8/// can think of id as a pointer (but without a lifetime) or a file descriptor 10/// can think of id as a pointer (but without a lifetime) or a file descriptor
@@ -151,7 +153,7 @@ impl DefId {
151 let loc = self.loc(db); 153 let loc = self.loc(db);
152 let res = match loc.kind { 154 let res = match loc.kind {
153 DefKind::Module => { 155 DefKind::Module => {
154 let module = Module::new(db, loc.source_root_id, loc.module_id)?; 156 let module = Module::from_module_id(db, loc.source_root_id, loc.module_id)?;
155 Def::Module(module) 157 Def::Module(module)
156 } 158 }
157 DefKind::Function => { 159 DefKind::Function => {
@@ -175,12 +177,12 @@ impl DefId {
175 /// For a module, returns that module; for any other def, returns the containing module. 177 /// For a module, returns that module; for any other def, returns the containing module.
176 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> { 178 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> {
177 let loc = self.loc(db); 179 let loc = self.loc(db);
178 Module::new(db, loc.source_root_id, loc.module_id) 180 Module::from_module_id(db, loc.source_root_id, loc.module_id)
179 } 181 }
180 182
181 /// Returns the containing crate. 183 /// Returns the containing crate.
182 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> { 184 pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
183 Ok(self.module(db)?.krate(db)) 185 Ok(self.module(db)?.krate(db)?)
184 } 186 }
185 187
186 /// Returns the containing impl block, if this is an impl item. 188 /// Returns the containing impl block, if this is an impl item.
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 01afa84c4..7ce8d17e6 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -7,12 +7,14 @@ use ra_db::{LocationIntener, Cancelable, SourceRootId};
7 7
8use crate::{ 8use crate::{
9 DefId, DefLoc, DefKind, SourceItemId, SourceFileItems, 9 DefId, DefLoc, DefKind, SourceItemId, SourceFileItems,
10 Module, Function, 10 Function,
11 db::HirDatabase, 11 db::HirDatabase,
12 type_ref::TypeRef, 12 type_ref::TypeRef,
13 module::{ModuleSourceNode, ModuleId}, 13 module_tree::ModuleId,
14}; 14};
15 15
16use crate::code_model_api::{Module, ModuleSource};
17
16#[derive(Debug, Clone, PartialEq, Eq)] 18#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ImplBlock { 19pub struct ImplBlock {
18 module_impl_blocks: Arc<ModuleImplBlocks>, 20 module_impl_blocks: Arc<ModuleImplBlocks>,
@@ -64,7 +66,7 @@ impl ImplData {
64 ) -> Self { 66 ) -> Self {
65 let target_trait = node.target_type().map(TypeRef::from_ast); 67 let target_trait = node.target_type().map(TypeRef::from_ast);
66 let target_type = TypeRef::from_ast_opt(node.target_type()); 68 let target_type = TypeRef::from_ast_opt(node.target_type());
67 let file_id = module.source().file_id(); 69 let module_loc = module.def_id.loc(db);
68 let items = if let Some(item_list) = node.item_list() { 70 let items = if let Some(item_list) = node.item_list() {
69 item_list 71 item_list
70 .impl_items() 72 .impl_items()
@@ -75,14 +77,14 @@ impl ImplData {
75 ast::ImplItem::TypeDef(..) => DefKind::Item, 77 ast::ImplItem::TypeDef(..) => DefKind::Item,
76 }; 78 };
77 let item_id = file_items.id_of_unchecked(item_node.syntax()); 79 let item_id = file_items.id_of_unchecked(item_node.syntax());
80 let source_item_id = SourceItemId {
81 file_id: module_loc.source_item_id.file_id,
82 item_id: Some(item_id),
83 };
78 let def_loc = DefLoc { 84 let def_loc = DefLoc {
79 kind, 85 kind,
80 source_root_id: module.source_root_id, 86 source_item_id,
81 module_id: module.module_id, 87 ..module_loc
82 source_item_id: SourceItemId {
83 file_id,
84 item_id: Some(item_id),
85 },
86 }; 88 };
87 let def_id = def_loc.id(db); 89 let def_id = def_loc.id(db);
88 match item_node { 90 match item_node {
@@ -148,13 +150,13 @@ impl ModuleImplBlocks {
148 } 150 }
149 151
150 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> { 152 fn collect(&mut self, db: &impl HirDatabase, module: Module) -> Cancelable<()> {
151 let module_source_node = module.source().resolve(db); 153 let (file_id, module_source) = module.defenition_source(db)?;
152 let node = match &module_source_node { 154 let node = match &module_source {
153 ModuleSourceNode::SourceFile(node) => node.borrowed().syntax(), 155 ModuleSource::SourceFile(node) => node.borrowed().syntax(),
154 ModuleSourceNode::Module(node) => node.borrowed().syntax(), 156 ModuleSource::Module(node) => node.borrowed().syntax(),
155 }; 157 };
156 158
157 let source_file_items = db.file_items(module.source().file_id()); 159 let source_file_items = db.file_items(file_id.into());
158 160
159 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { 161 for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) {
160 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast); 162 let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast);
@@ -174,7 +176,7 @@ pub(crate) fn impls_in_module(
174 module_id: ModuleId, 176 module_id: ModuleId,
175) -> Cancelable<Arc<ModuleImplBlocks>> { 177) -> Cancelable<Arc<ModuleImplBlocks>> {
176 let mut result = ModuleImplBlocks::new(); 178 let mut result = ModuleImplBlocks::new();
177 let module = Module::new(db, source_root_id, module_id)?; 179 let module = Module::from_module_id(db, source_root_id, module_id)?;
178 result.collect(db, module)?; 180 result.collect(db, module)?;
179 Ok(Arc::new(result)) 181 Ok(Arc::new(result))
180} 182}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index d600b91df..9f133f174 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -24,9 +24,8 @@ pub mod source_binder;
24mod ids; 24mod ids;
25mod macros; 25mod macros;
26mod name; 26mod name;
27// can't use `crate` or `r#crate` here :( 27mod module_tree;
28mod krate; 28mod nameres;
29mod module;
30mod function; 29mod function;
31mod adt; 30mod adt;
32mod type_ref; 31mod type_ref;
@@ -34,6 +33,9 @@ mod ty;
34mod impl_block; 33mod impl_block;
35mod expr; 34mod expr;
36 35
36mod code_model_api;
37mod code_model_impl;
38
37use crate::{ 39use crate::{
38 db::HirDatabase, 40 db::HirDatabase,
39 name::{AsName, KnownName}, 41 name::{AsName, KnownName},
@@ -43,10 +45,10 @@ use crate::{
43pub use self::{ 45pub use self::{
44 path::{Path, PathKind}, 46 path::{Path, PathKind},
45 name::Name, 47 name::Name,
46 krate::Crate,
47 ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc}, 48 ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc},
48 macros::{MacroDef, MacroInput, MacroExpansion}, 49 macros::{MacroDef, MacroInput, MacroExpansion},
49 module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, 50 module_tree::ModuleId,
51 nameres::{ItemMap, PerNs, Namespace, Resolution},
50 function::{Function, FnSignature, FnScopes, ScopesWithSyntaxMapping}, 52 function::{Function, FnSignature, FnScopes, ScopesWithSyntaxMapping},
51 adt::{Struct, Enum}, 53 adt::{Struct, Enum},
52 ty::Ty, 54 ty::Ty,
@@ -55,6 +57,11 @@ pub use self::{
55 57
56pub use self::function::FnSignatureInfo; 58pub use self::function::FnSignatureInfo;
57 59
60pub use self::code_model_api::{
61 Crate, CrateDependency,
62 Module, ModuleSource, Problem,
63};
64
58pub enum Def { 65pub enum Def {
59 Module(Module), 66 Module(Module),
60 Function(Function), 67 Function(Function),
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
deleted file mode 100644
index b9821115c..000000000
--- a/crates/ra_hir/src/module.rs
+++ /dev/null
@@ -1,376 +0,0 @@
1pub(super) mod imp;
2pub(super) mod nameres;
3
4use std::sync::Arc;
5use log;
6
7use ra_syntax::{
8 algo::generate,
9 ast::{self, AstNode, NameOwner},
10 SyntaxNode,
11};
12use ra_arena::{Arena, RawId, impl_arena_id};
13use ra_db::{SourceRootId, FileId, Cancelable};
14use relative_path::RelativePathBuf;
15
16use crate::{
17 Def, DefKind, DefLoc, DefId,
18 Name, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId, Crate,
19 HirFileId,
20};
21
22pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs};
23
24/// `Module` is API entry point to get all the information
25/// about a particular module.
26#[derive(Debug, Clone)]
27pub struct Module {
28 tree: Arc<ModuleTree>,
29 pub(crate) source_root_id: SourceRootId,
30 pub(crate) module_id: ModuleId,
31}
32
33impl Module {
34 pub(super) fn new(
35 db: &impl HirDatabase,
36 source_root_id: SourceRootId,
37 module_id: ModuleId,
38 ) -> Cancelable<Module> {
39 let module_tree = db.module_tree(source_root_id)?;
40 let res = Module {
41 tree: module_tree,
42 source_root_id,
43 module_id,
44 };
45 Ok(res)
46 }
47
48 /// Returns `mod foo;` or `mod foo {}` node whihc declared this module.
49 /// Returns `None` for the root module
50 pub fn parent_link_source(&self, db: &impl HirDatabase) -> Option<(FileId, ast::ModuleNode)> {
51 let link = self.module_id.parent_link(&self.tree)?;
52 let file_id = link
53 .owner(&self.tree)
54 .source(&self.tree)
55 .file_id()
56 .as_original_file();
57 let src = link.bind_source(&self.tree, db);
58 Some((file_id, src))
59 }
60
61 pub fn file_id(&self) -> FileId {
62 self.source().file_id().as_original_file()
63 }
64
65 /// Parent module. Returns `None` if this is a root module.
66 pub fn parent(&self) -> Option<Module> {
67 let parent_id = self.module_id.parent(&self.tree)?;
68 Some(Module {
69 module_id: parent_id,
70 ..self.clone()
71 })
72 }
73
74 /// Returns an iterator of all children of this module.
75 pub fn children<'a>(&'a self) -> impl Iterator<Item = (Name, Module)> + 'a {
76 self.module_id
77 .children(&self.tree)
78 .map(move |(name, module_id)| {
79 (
80 name,
81 Module {
82 module_id,
83 ..self.clone()
84 },
85 )
86 })
87 }
88
89 /// Returns the crate this module is part of.
90 pub fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
91 let root_id = self.module_id.crate_root(&self.tree);
92 let file_id = root_id.source(&self.tree).file_id().as_original_file();
93 let crate_graph = db.crate_graph();
94 let crate_id = crate_graph.crate_id_for_crate_root(file_id)?;
95 Some(Crate::new(crate_id))
96 }
97
98 /// Returns the all modules on the way to the root.
99 pub fn path_to_root(&self) -> Vec<Module> {
100 generate(Some(self.clone()), move |it| it.parent()).collect::<Vec<Module>>()
101 }
102
103 /// The root of the tree this module is part of
104 pub fn crate_root(&self) -> Module {
105 let root_id = self.module_id.crate_root(&self.tree);
106 Module {
107 module_id: root_id,
108 ..self.clone()
109 }
110 }
111
112 /// `name` is `None` for the crate's root module
113 pub fn name(&self) -> Option<&Name> {
114 let link = self.module_id.parent_link(&self.tree)?;
115 Some(link.name(&self.tree))
116 }
117
118 pub fn def_id(&self, db: &impl HirDatabase) -> DefId {
119 let def_loc = DefLoc {
120 kind: DefKind::Module,
121 source_root_id: self.source_root_id,
122 module_id: self.module_id,
123 source_item_id: self.module_id.source(&self.tree).0,
124 };
125 def_loc.id(db)
126 }
127
128 /// Finds a child module with the specified name.
129 pub fn child(&self, name: &Name) -> Option<Module> {
130 let child_id = self.module_id.child(&self.tree, name)?;
131 Some(Module {
132 module_id: child_id,
133 ..self.clone()
134 })
135 }
136
137 /// Returns a `ModuleScope`: a set of items, visible in this module.
138 pub fn scope(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
139 let item_map = db.item_map(self.source_root_id)?;
140 let res = item_map.per_module[&self.module_id].clone();
141 Ok(res)
142 }
143
144 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
145 let mut curr_per_ns = PerNs::types(
146 match path.kind {
147 PathKind::Crate => self.crate_root(),
148 PathKind::Self_ | PathKind::Plain => self.clone(),
149 PathKind::Super => {
150 if let Some(p) = self.parent() {
151 p
152 } else {
153 return Ok(PerNs::none());
154 }
155 }
156 }
157 .def_id(db),
158 );
159
160 let segments = &path.segments;
161 for name in segments.iter() {
162 let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) {
163 r
164 } else {
165 return Ok(PerNs::none());
166 };
167 let module = match curr.resolve(db)? {
168 Def::Module(it) => it,
169 // TODO here would be the place to handle enum variants...
170 _ => return Ok(PerNs::none()),
171 };
172 let scope = module.scope(db)?;
173 curr_per_ns = if let Some(r) = scope.get(&name) {
174 r.def_id
175 } else {
176 return Ok(PerNs::none());
177 };
178 }
179 Ok(curr_per_ns)
180 }
181
182 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
183 self.module_id.problems(&self.tree, db)
184 }
185
186 pub(crate) fn source(&self) -> ModuleSource {
187 self.module_id.source(&self.tree)
188 }
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
192pub struct ModuleId(RawId);
193impl_arena_id!(ModuleId);
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
196pub struct LinkId(RawId);
197impl_arena_id!(LinkId);
198
199/// Physically, rust source is organized as a set of files, but logically it is
200/// organized as a tree of modules. Usually, a single file corresponds to a
201/// single module, but it is not nessary the case.
202///
203/// Module encapsulate the logic of transitioning from the fuzzy world of files
204/// (which can have multiple parents) to the precise world of modules (which
205/// always have one parent).
206#[derive(Default, Debug, PartialEq, Eq)]
207pub struct ModuleTree {
208 mods: Arena<ModuleId, ModuleData>,
209 links: Arena<LinkId, LinkData>,
210}
211
212impl ModuleTree {
213 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
214 self.mods.iter().map(|(id, _)| id)
215 }
216
217 pub(crate) fn modules_with_sources<'a>(
218 &'a self,
219 ) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a {
220 self.mods.iter().map(|(id, m)| (id, m.source))
221 }
222}
223
224/// `ModuleSource` is the syntax tree element that produced this module:
225/// either a file, or an inlinde module.
226#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
227pub struct ModuleSource(SourceItemId);
228
229/// An owned syntax node for a module. Unlike `ModuleSource`,
230/// this holds onto the AST for the whole file.
231pub(crate) enum ModuleSourceNode {
232 SourceFile(ast::SourceFileNode),
233 Module(ast::ModuleNode),
234}
235
236#[derive(Clone, Debug, Hash, PartialEq, Eq)]
237pub enum Problem {
238 UnresolvedModule {
239 candidate: RelativePathBuf,
240 },
241 NotDirOwner {
242 move_to: RelativePathBuf,
243 candidate: RelativePathBuf,
244 },
245}
246
247impl ModuleId {
248 pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource {
249 tree.mods[self].source
250 }
251 fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
252 tree.mods[self].parent
253 }
254 fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
255 let link = self.parent_link(tree)?;
256 Some(tree.links[link].owner)
257 }
258 fn crate_root(self, tree: &ModuleTree) -> ModuleId {
259 generate(Some(self), move |it| it.parent(tree))
260 .last()
261 .unwrap()
262 }
263 fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
264 let link = tree.mods[self]
265 .children
266 .iter()
267 .map(|&it| &tree.links[it])
268 .find(|it| it.name == *name)?;
269 Some(*link.points_to.first()?)
270 }
271 fn children<'a>(self, tree: &'a ModuleTree) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
272 tree.mods[self].children.iter().filter_map(move |&it| {
273 let link = &tree.links[it];
274 let module = *link.points_to.first()?;
275 Some((link.name.clone(), module))
276 })
277 }
278 fn problems(self, tree: &ModuleTree, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
279 tree.mods[self]
280 .children
281 .iter()
282 .filter_map(|&it| {
283 let p = tree.links[it].problem.clone()?;
284 let s = it.bind_source(tree, db);
285 let s = s.borrowed().name().unwrap().syntax().owned();
286 Some((s, p))
287 })
288 .collect()
289 }
290}
291
292impl LinkId {
293 fn owner(self, tree: &ModuleTree) -> ModuleId {
294 tree.links[self].owner
295 }
296 fn name(self, tree: &ModuleTree) -> &Name {
297 &tree.links[self].name
298 }
299 fn bind_source<'a>(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode {
300 let owner = self.owner(tree);
301 match owner.source(tree).resolve(db) {
302 ModuleSourceNode::SourceFile(root) => {
303 let ast = imp::modules(root.borrowed())
304 .find(|(name, _)| name == &tree.links[self].name)
305 .unwrap()
306 .1;
307 ast.owned()
308 }
309 ModuleSourceNode::Module(it) => it,
310 }
311 }
312}
313
314#[derive(Debug, PartialEq, Eq, Hash)]
315pub struct ModuleData {
316 source: ModuleSource,
317 parent: Option<LinkId>,
318 children: Vec<LinkId>,
319}
320
321impl ModuleSource {
322 // precondition: item_id **must** point to module
323 fn new(file_id: HirFileId, item_id: Option<SourceFileItemId>) -> ModuleSource {
324 let source_item_id = SourceItemId { file_id, item_id };
325 ModuleSource(source_item_id)
326 }
327
328 pub(crate) fn new_file(file_id: HirFileId) -> ModuleSource {
329 ModuleSource::new(file_id, None)
330 }
331
332 pub(crate) fn new_inline(
333 db: &impl HirDatabase,
334 file_id: HirFileId,
335 m: ast::Module,
336 ) -> ModuleSource {
337 assert!(!m.has_semi());
338 let file_items = db.file_items(file_id);
339 let item_id = file_items.id_of(file_id, m.syntax());
340 ModuleSource::new(file_id, Some(item_id))
341 }
342
343 pub(crate) fn file_id(self) -> HirFileId {
344 self.0.file_id
345 }
346
347 pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
348 let syntax_node = db.file_item(self.0);
349 let syntax_node = syntax_node.borrowed();
350 if let Some(file) = ast::SourceFile::cast(syntax_node) {
351 return ModuleSourceNode::SourceFile(file.owned());
352 }
353 let module = ast::Module::cast(syntax_node).unwrap();
354 ModuleSourceNode::Module(module.owned())
355 }
356}
357
358#[derive(Hash, Debug, PartialEq, Eq)]
359struct LinkData {
360 owner: ModuleId,
361 name: Name,
362 points_to: Vec<ModuleId>,
363 problem: Option<Problem>,
364}
365
366impl ModuleTree {
367 fn push_mod(&mut self, data: ModuleData) -> ModuleId {
368 self.mods.alloc(data)
369 }
370 fn push_link(&mut self, data: LinkData) -> LinkId {
371 let owner = data.owner;
372 let id = self.links.alloc(data);
373 self.mods[owner].children.push(id);
374 id
375 }
376}
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
deleted file mode 100644
index 3849026db..000000000
--- a/crates/ra_hir/src/module/imp.rs
+++ /dev/null
@@ -1,190 +0,0 @@
1use std::sync::Arc;
2
3use ra_syntax::ast::{self, NameOwner};
4use relative_path::RelativePathBuf;
5use rustc_hash::{FxHashMap, FxHashSet};
6use arrayvec::ArrayVec;
7use ra_db::{SourceRoot, SourceRootId, Cancelable, FileId};
8
9use crate::{
10 HirDatabase, Name, AsName,
11};
12
13use super::{
14 LinkData, LinkId, ModuleData, ModuleId, ModuleSource,
15 ModuleTree, Problem,
16};
17
18#[derive(Clone, Hash, PartialEq, Eq, Debug)]
19pub enum Submodule {
20 Declaration(Name),
21 Definition(Name, ModuleSource),
22}
23
24impl Submodule {
25 fn name(&self) -> &Name {
26 match self {
27 Submodule::Declaration(name) => name,
28 Submodule::Definition(name, _) => name,
29 }
30 }
31}
32
33pub(crate) fn modules<'a>(
34 root: impl ast::ModuleItemOwner<'a>,
35) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
36 root.items()
37 .filter_map(|item| match item {
38 ast::ModuleItem::Module(m) => Some(m),
39 _ => None,
40 })
41 .filter_map(|module| {
42 let name = module.name()?.as_name();
43 Some((name, module))
44 })
45}
46
47pub(crate) fn module_tree(
48 db: &impl HirDatabase,
49 source_root: SourceRootId,
50) -> Cancelable<Arc<ModuleTree>> {
51 db.check_canceled()?;
52 let res = create_module_tree(db, source_root)?;
53 Ok(Arc::new(res))
54}
55
56fn create_module_tree<'a>(
57 db: &impl HirDatabase,
58 source_root: SourceRootId,
59) -> Cancelable<ModuleTree> {
60 let mut tree = ModuleTree::default();
61
62 let mut roots = FxHashMap::default();
63 let mut visited = FxHashSet::default();
64
65 let source_root = db.source_root(source_root);
66 for &file_id in source_root.files.values() {
67 let source = ModuleSource::new_file(file_id.into());
68 if visited.contains(&source) {
69 continue; // TODO: use explicit crate_roots here
70 }
71 assert!(!roots.contains_key(&file_id));
72 let module_id = build_subtree(
73 db,
74 &source_root,
75 &mut tree,
76 &mut visited,
77 &mut roots,
78 None,
79 source,
80 )?;
81 roots.insert(file_id, module_id);
82 }
83 Ok(tree)
84}
85
86fn build_subtree(
87 db: &impl HirDatabase,
88 source_root: &SourceRoot,
89 tree: &mut ModuleTree,
90 visited: &mut FxHashSet<ModuleSource>,
91 roots: &mut FxHashMap<FileId, ModuleId>,
92 parent: Option<LinkId>,
93 source: ModuleSource,
94) -> Cancelable<ModuleId> {
95 visited.insert(source);
96 let id = tree.push_mod(ModuleData {
97 source,
98 parent,
99 children: Vec::new(),
100 });
101 for sub in db.submodules(source)?.iter() {
102 let link = tree.push_link(LinkData {
103 name: sub.name().clone(),
104 owner: id,
105 points_to: Vec::new(),
106 problem: None,
107 });
108
109 let (points_to, problem) = match sub {
110 Submodule::Declaration(name) => {
111 let (points_to, problem) = resolve_submodule(db, source, &name);
112 let points_to = points_to
113 .into_iter()
114 .map(|file_id| match roots.remove(&file_id) {
115 Some(module_id) => {
116 tree.mods[module_id].parent = Some(link);
117 Ok(module_id)
118 }
119 None => build_subtree(
120 db,
121 source_root,
122 tree,
123 visited,
124 roots,
125 Some(link),
126 ModuleSource::new_file(file_id.into()),
127 ),
128 })
129 .collect::<Cancelable<Vec<_>>>()?;
130 (points_to, problem)
131 }
132 Submodule::Definition(_name, submodule_source) => {
133 let points_to = build_subtree(
134 db,
135 source_root,
136 tree,
137 visited,
138 roots,
139 Some(link),
140 *submodule_source,
141 )?;
142 (vec![points_to], None)
143 }
144 };
145
146 tree.links[link].points_to = points_to;
147 tree.links[link].problem = problem;
148 }
149 Ok(id)
150}
151
152fn resolve_submodule(
153 db: &impl HirDatabase,
154 source: ModuleSource,
155 name: &Name,
156) -> (Vec<FileId>, Option<Problem>) {
157 // FIXME: handle submodules of inline modules properly
158 let file_id = source.file_id().original_file(db);
159 let source_root_id = db.file_source_root(file_id);
160 let path = db.file_relative_path(file_id);
161 let root = RelativePathBuf::default();
162 let dir_path = path.parent().unwrap_or(&root);
163 let mod_name = path.file_stem().unwrap_or("unknown");
164 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
165
166 let file_mod = dir_path.join(format!("{}.rs", name));
167 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
168 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
169 let mut candidates = ArrayVec::<[_; 2]>::new();
170 if is_dir_owner {
171 candidates.push(file_mod.clone());
172 candidates.push(dir_mod);
173 } else {
174 candidates.push(file_dir_mod.clone());
175 };
176 let sr = db.source_root(source_root_id);
177 let points_to = candidates
178 .into_iter()
179 .filter_map(|path| sr.files.get(&path))
180 .map(|&it| it)
181 .collect::<Vec<_>>();
182 let problem = if points_to.is_empty() {
183 Some(Problem::UnresolvedModule {
184 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
185 })
186 } else {
187 None
188 };
189 (points_to, problem)
190}
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
new file mode 100644
index 000000000..b7912ba5e
--- /dev/null
+++ b/crates/ra_hir/src/module_tree.rs
@@ -0,0 +1,409 @@
1use std::sync::Arc;
2
3use rustc_hash::{FxHashMap, FxHashSet};
4use arrayvec::ArrayVec;
5use relative_path::RelativePathBuf;
6use ra_db::{FileId, SourceRootId, Cancelable, SourceRoot};
7use ra_syntax::{
8 algo::generate,
9 ast::{self, AstNode, NameOwner},
10 SyntaxNode,
11};
12use ra_arena::{Arena, RawId, impl_arena_id};
13
14use crate::{Name, AsName, HirDatabase, SourceItemId, SourceFileItemId, HirFileId, Problem};
15
16#[derive(Clone, Hash, PartialEq, Eq, Debug)]
17pub enum Submodule {
18 Declaration(Name),
19 Definition(Name, ModuleSource),
20}
21
22impl Submodule {
23 pub(crate) fn submodules_query(
24 db: &impl HirDatabase,
25 source: ModuleSource,
26 ) -> Cancelable<Arc<Vec<Submodule>>> {
27 db.check_canceled()?;
28 let file_id = source.file_id();
29 let submodules = match source.resolve(db) {
30 ModuleSourceNode::SourceFile(it) => collect_submodules(db, file_id, it.borrowed()),
31 ModuleSourceNode::Module(it) => it
32 .borrowed()
33 .item_list()
34 .map(|it| collect_submodules(db, file_id, it))
35 .unwrap_or_else(Vec::new),
36 };
37 return Ok(Arc::new(submodules));
38
39 fn collect_submodules<'a>(
40 db: &impl HirDatabase,
41 file_id: HirFileId,
42 root: impl ast::ModuleItemOwner<'a>,
43 ) -> Vec<Submodule> {
44 modules(root)
45 .map(|(name, m)| {
46 if m.has_semi() {
47 Submodule::Declaration(name)
48 } else {
49 let src = ModuleSource::new_inline(db, file_id, m);
50 Submodule::Definition(name, src)
51 }
52 })
53 .collect()
54 }
55 }
56
57 fn name(&self) -> &Name {
58 match self {
59 Submodule::Declaration(name) => name,
60 Submodule::Definition(name, _) => name,
61 }
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
66pub struct ModuleId(RawId);
67impl_arena_id!(ModuleId);
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
70pub struct LinkId(RawId);
71impl_arena_id!(LinkId);
72
73/// Physically, rust source is organized as a set of files, but logically it is
74/// organized as a tree of modules. Usually, a single file corresponds to a
75/// single module, but it is not nessary the case.
76///
77/// Module encapsulate the logic of transitioning from the fuzzy world of files
78/// (which can have multiple parents) to the precise world of modules (which
79/// always have one parent).
80#[derive(Default, Debug, PartialEq, Eq)]
81pub struct ModuleTree {
82 mods: Arena<ModuleId, ModuleData>,
83 links: Arena<LinkId, LinkData>,
84}
85
86#[derive(Debug, PartialEq, Eq, Hash)]
87pub struct ModuleData {
88 source: ModuleSource,
89 parent: Option<LinkId>,
90 children: Vec<LinkId>,
91}
92
93#[derive(Hash, Debug, PartialEq, Eq)]
94struct LinkData {
95 owner: ModuleId,
96 name: Name,
97 points_to: Vec<ModuleId>,
98 problem: Option<Problem>,
99}
100
101impl ModuleTree {
102 pub(crate) fn module_tree_query(
103 db: &impl HirDatabase,
104 source_root: SourceRootId,
105 ) -> Cancelable<Arc<ModuleTree>> {
106 db.check_canceled()?;
107 let res = create_module_tree(db, source_root)?;
108 Ok(Arc::new(res))
109 }
110
111 pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a {
112 self.mods.iter().map(|(id, _)| id)
113 }
114
115 pub(crate) fn modules_with_sources<'a>(
116 &'a self,
117 ) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a {
118 self.mods.iter().map(|(id, m)| (id, m.source))
119 }
120}
121
122/// `ModuleSource` is the syntax tree element that produced this module:
123/// either a file, or an inlinde module.
124#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
125pub struct ModuleSource(pub(crate) SourceItemId);
126
127/// An owned syntax node for a module. Unlike `ModuleSource`,
128/// this holds onto the AST for the whole file.
129pub(crate) enum ModuleSourceNode {
130 SourceFile(ast::SourceFileNode),
131 Module(ast::ModuleNode),
132}
133
134impl ModuleId {
135 pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource {
136 tree.mods[self].source
137 }
138 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
139 tree.mods[self].parent
140 }
141 pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> {
142 let link = self.parent_link(tree)?;
143 Some(tree.links[link].owner)
144 }
145 pub(crate) fn crate_root(self, tree: &ModuleTree) -> ModuleId {
146 generate(Some(self), move |it| it.parent(tree))
147 .last()
148 .unwrap()
149 }
150 pub(crate) fn child(self, tree: &ModuleTree, name: &Name) -> Option<ModuleId> {
151 let link = tree.mods[self]
152 .children
153 .iter()
154 .map(|&it| &tree.links[it])
155 .find(|it| it.name == *name)?;
156 Some(*link.points_to.first()?)
157 }
158 pub(crate) fn children<'a>(
159 self,
160 tree: &'a ModuleTree,
161 ) -> impl Iterator<Item = (Name, ModuleId)> + 'a {
162 tree.mods[self].children.iter().filter_map(move |&it| {
163 let link = &tree.links[it];
164 let module = *link.points_to.first()?;
165 Some((link.name.clone(), module))
166 })
167 }
168 pub(crate) fn problems(
169 self,
170 tree: &ModuleTree,
171 db: &impl HirDatabase,
172 ) -> Vec<(SyntaxNode, Problem)> {
173 tree.mods[self]
174 .children
175 .iter()
176 .filter_map(|&it| {
177 let p = tree.links[it].problem.clone()?;
178 let s = it.bind_source(tree, db);
179 let s = s.borrowed().name().unwrap().syntax().owned();
180 Some((s, p))
181 })
182 .collect()
183 }
184}
185
186impl LinkId {
187 pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId {
188 tree.links[self].owner
189 }
190 pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
191 &tree.links[self].name
192 }
193 pub(crate) fn bind_source<'a>(
194 self,
195 tree: &ModuleTree,
196 db: &impl HirDatabase,
197 ) -> ast::ModuleNode {
198 let owner = self.owner(tree);
199 match owner.source(tree).resolve(db) {
200 ModuleSourceNode::SourceFile(root) => {
201 let ast = modules(root.borrowed())
202 .find(|(name, _)| name == &tree.links[self].name)
203 .unwrap()
204 .1;
205 ast.owned()
206 }
207 ModuleSourceNode::Module(it) => it,
208 }
209 }
210}
211
212impl ModuleSource {
213 // precondition: item_id **must** point to module
214 fn new(file_id: HirFileId, item_id: Option<SourceFileItemId>) -> ModuleSource {
215 let source_item_id = SourceItemId { file_id, item_id };
216 ModuleSource(source_item_id)
217 }
218
219 pub(crate) fn new_file(file_id: HirFileId) -> ModuleSource {
220 ModuleSource::new(file_id, None)
221 }
222
223 pub(crate) fn new_inline(
224 db: &impl HirDatabase,
225 file_id: HirFileId,
226 m: ast::Module,
227 ) -> ModuleSource {
228 assert!(!m.has_semi());
229 let file_items = db.file_items(file_id);
230 let item_id = file_items.id_of(file_id, m.syntax());
231 ModuleSource::new(file_id, Some(item_id))
232 }
233
234 pub(crate) fn file_id(self) -> HirFileId {
235 self.0.file_id
236 }
237
238 pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
239 let syntax_node = db.file_item(self.0);
240 let syntax_node = syntax_node.borrowed();
241 if let Some(file) = ast::SourceFile::cast(syntax_node) {
242 return ModuleSourceNode::SourceFile(file.owned());
243 }
244 let module = ast::Module::cast(syntax_node).unwrap();
245 ModuleSourceNode::Module(module.owned())
246 }
247}
248
249impl ModuleTree {
250 fn push_mod(&mut self, data: ModuleData) -> ModuleId {
251 self.mods.alloc(data)
252 }
253 fn push_link(&mut self, data: LinkData) -> LinkId {
254 let owner = data.owner;
255 let id = self.links.alloc(data);
256 self.mods[owner].children.push(id);
257 id
258 }
259}
260
261fn modules<'a>(
262 root: impl ast::ModuleItemOwner<'a>,
263) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
264 root.items()
265 .filter_map(|item| match item {
266 ast::ModuleItem::Module(m) => Some(m),
267 _ => None,
268 })
269 .filter_map(|module| {
270 let name = module.name()?.as_name();
271 Some((name, module))
272 })
273}
274
275fn create_module_tree<'a>(
276 db: &impl HirDatabase,
277 source_root: SourceRootId,
278) -> Cancelable<ModuleTree> {
279 let mut tree = ModuleTree::default();
280
281 let mut roots = FxHashMap::default();
282 let mut visited = FxHashSet::default();
283
284 let source_root = db.source_root(source_root);
285 for &file_id in source_root.files.values() {
286 let source = ModuleSource::new_file(file_id.into());
287 if visited.contains(&source) {
288 continue; // TODO: use explicit crate_roots here
289 }
290 assert!(!roots.contains_key(&file_id));
291 let module_id = build_subtree(
292 db,
293 &source_root,
294 &mut tree,
295 &mut visited,
296 &mut roots,
297 None,
298 source,
299 )?;
300 roots.insert(file_id, module_id);
301 }
302 Ok(tree)
303}
304
305fn build_subtree(
306 db: &impl HirDatabase,
307 source_root: &SourceRoot,
308 tree: &mut ModuleTree,
309 visited: &mut FxHashSet<ModuleSource>,
310 roots: &mut FxHashMap<FileId, ModuleId>,
311 parent: Option<LinkId>,
312 source: ModuleSource,
313) -> Cancelable<ModuleId> {
314 visited.insert(source);
315 let id = tree.push_mod(ModuleData {
316 source,
317 parent,
318 children: Vec::new(),
319 });
320 for sub in db.submodules(source)?.iter() {
321 let link = tree.push_link(LinkData {
322 name: sub.name().clone(),
323 owner: id,
324 points_to: Vec::new(),
325 problem: None,
326 });
327
328 let (points_to, problem) = match sub {
329 Submodule::Declaration(name) => {
330 let (points_to, problem) = resolve_submodule(db, source, &name);
331 let points_to = points_to
332 .into_iter()
333 .map(|file_id| match roots.remove(&file_id) {
334 Some(module_id) => {
335 tree.mods[module_id].parent = Some(link);
336 Ok(module_id)
337 }
338 None => build_subtree(
339 db,
340 source_root,
341 tree,
342 visited,
343 roots,
344 Some(link),
345 ModuleSource::new_file(file_id.into()),
346 ),
347 })
348 .collect::<Cancelable<Vec<_>>>()?;
349 (points_to, problem)
350 }
351 Submodule::Definition(_name, submodule_source) => {
352 let points_to = build_subtree(
353 db,
354 source_root,
355 tree,
356 visited,
357 roots,
358 Some(link),
359 *submodule_source,
360 )?;
361 (vec![points_to], None)
362 }
363 };
364
365 tree.links[link].points_to = points_to;
366 tree.links[link].problem = problem;
367 }
368 Ok(id)
369}
370
371fn resolve_submodule(
372 db: &impl HirDatabase,
373 source: ModuleSource,
374 name: &Name,
375) -> (Vec<FileId>, Option<Problem>) {
376 // FIXME: handle submodules of inline modules properly
377 let file_id = source.file_id().original_file(db);
378 let source_root_id = db.file_source_root(file_id);
379 let path = db.file_relative_path(file_id);
380 let root = RelativePathBuf::default();
381 let dir_path = path.parent().unwrap_or(&root);
382 let mod_name = path.file_stem().unwrap_or("unknown");
383 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
384
385 let file_mod = dir_path.join(format!("{}.rs", name));
386 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
387 let file_dir_mod = dir_path.join(format!("{}/{}.rs", mod_name, name));
388 let mut candidates = ArrayVec::<[_; 2]>::new();
389 if is_dir_owner {
390 candidates.push(file_mod.clone());
391 candidates.push(dir_mod);
392 } else {
393 candidates.push(file_dir_mod.clone());
394 };
395 let sr = db.source_root(source_root_id);
396 let points_to = candidates
397 .into_iter()
398 .filter_map(|path| sr.files.get(&path))
399 .map(|&it| it)
400 .collect::<Vec<_>>();
401 let problem = if points_to.is_empty() {
402 Some(Problem::UnresolvedModule {
403 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
404 })
405 } else {
406 None
407 };
408 (points_to, problem)
409}
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/nameres.rs
index 3c6851a0a..e65cbcb27 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -31,7 +31,7 @@ use crate::{
31 Path, PathKind, 31 Path, PathKind,
32 HirDatabase, Crate, 32 HirDatabase, Crate,
33 Name, AsName, 33 Name, AsName,
34 module::{Module, ModuleId, ModuleTree}, 34 module_tree::{ModuleId, ModuleTree},
35}; 35};
36 36
37/// Item map is the result of the name resolution. Item map contains, for each 37/// Item map is the result of the name resolution. Item map contains, for each
@@ -177,11 +177,11 @@ impl<T> PerNs<T> {
177 } 177 }
178 178
179 pub fn take_types(self) -> Option<T> { 179 pub fn take_types(self) -> Option<T> {
180 self.types 180 self.take(Namespace::Types)
181 } 181 }
182 182
183 pub fn take_values(self) -> Option<T> { 183 pub fn take_values(self) -> Option<T> {
184 self.values 184 self.take(Namespace::Values)
185 } 185 }
186 186
187 pub fn get(&self, namespace: Namespace) -> Option<&T> { 187 pub fn get(&self, namespace: Namespace) -> Option<&T> {
@@ -344,9 +344,9 @@ where
344 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) 344 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
345 { 345 {
346 let krate = Crate::new(crate_id); 346 let krate = Crate::new(crate_id);
347 for dep in krate.dependencies(self.db) { 347 for dep in krate.dependencies(self.db)? {
348 if let Some(module) = dep.krate.root_module(self.db)? { 348 if let Some(module) = dep.krate.root_module(self.db)? {
349 let def_id = module.def_id(self.db); 349 let def_id = module.def_id;
350 self.add_module_item( 350 self.add_module_item(
351 &mut module_items, 351 &mut module_items,
352 dep.name.clone(), 352 dep.name.clone(),
@@ -466,7 +466,7 @@ where
466 if source_root_id == self.source_root { 466 if source_root_id == self.source_root {
467 target_module_id 467 target_module_id
468 } else { 468 } else {
469 let module = Module::new(self.db, source_root_id, target_module_id)?; 469 let module = crate::code_model_api::Module::new(type_def_id);
470 let path = Path { 470 let path = Path {
471 segments: import.path.segments[i + 1..].iter().cloned().collect(), 471 segments: import.path.segments[i + 1..].iter().cloned().collect(),
472 kind: PathKind::Crate, 472 kind: PathKind::Crate,
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index a6a0bea31..dcbe65aec 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -17,7 +17,7 @@ fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
17 let module = hir::source_binder::module_from_position(&db, pos) 17 let module = hir::source_binder::module_from_position(&db, pos)
18 .unwrap() 18 .unwrap()
19 .unwrap(); 19 .unwrap();
20 let module_id = module.module_id; 20 let module_id = module.def_id.loc(&db).module_id;
21 (db.item_map(source_root).unwrap(), module_id) 21 (db.item_map(source_root).unwrap(), module_id)
22} 22}
23 23
@@ -155,7 +155,7 @@ fn item_map_across_crates() {
155 let module = hir::source_binder::module_from_file_id(&db, main_id) 155 let module = hir::source_binder::module_from_file_id(&db, main_id)
156 .unwrap() 156 .unwrap()
157 .unwrap(); 157 .unwrap();
158 let module_id = module.module_id; 158 let module_id = module.def_id.loc(&db).module_id;
159 let item_map = db.item_map(source_root).unwrap(); 159 let item_map = db.item_map(source_root).unwrap();
160 160
161 check_module_item_map( 161 check_module_item_map(
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index d9ee9d37f..f4b380022 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -6,20 +6,17 @@ use std::{
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use ra_syntax::{ 7use ra_syntax::{
8 AstNode, SyntaxNode, 8 AstNode, SyntaxNode,
9 ast::{self, NameOwner, ModuleItemOwner} 9 ast::{self, ModuleItemOwner}
10}; 10};
11use ra_db::{SourceRootId, Cancelable,}; 11use ra_db::{SourceRootId, Cancelable,};
12 12
13use crate::{ 13use crate::{
14 SourceFileItems, SourceItemId, DefKind, DefId, Name, AsName, HirFileId, 14 SourceFileItems, SourceItemId, DefKind, DefId, HirFileId,
15 MacroCallLoc, 15 MacroCallLoc,
16 db::HirDatabase, 16 db::HirDatabase,
17 function::FnScopes, 17 function::FnScopes,
18 module::{ 18 module_tree::{ModuleId, ModuleSourceNode},
19 ModuleSource, ModuleSourceNode, ModuleId, 19 nameres::{InputModuleItems, ItemMap, Resolver},
20 imp::Submodule,
21 nameres::{InputModuleItems, ItemMap, Resolver},
22 },
23 adt::{StructData, EnumData}, 20 adt::{StructData, EnumData},
24}; 21};
25 22
@@ -61,54 +58,6 @@ pub(super) fn file_item(db: &impl HirDatabase, source_item_id: SourceItemId) ->
61 } 58 }
62} 59}
63 60
64pub(crate) fn submodules(
65 db: &impl HirDatabase,
66 source: ModuleSource,
67) -> Cancelable<Arc<Vec<Submodule>>> {
68 db.check_canceled()?;
69 let file_id = source.file_id();
70 let submodules = match source.resolve(db) {
71 ModuleSourceNode::SourceFile(it) => collect_submodules(db, file_id, it.borrowed()),
72 ModuleSourceNode::Module(it) => it
73 .borrowed()
74 .item_list()
75 .map(|it| collect_submodules(db, file_id, it))
76 .unwrap_or_else(Vec::new),
77 };
78 return Ok(Arc::new(submodules));
79
80 fn collect_submodules<'a>(
81 db: &impl HirDatabase,
82 file_id: HirFileId,
83 root: impl ast::ModuleItemOwner<'a>,
84 ) -> Vec<Submodule> {
85 modules(root)
86 .map(|(name, m)| {
87 if m.has_semi() {
88 Submodule::Declaration(name)
89 } else {
90 let src = ModuleSource::new_inline(db, file_id, m);
91 Submodule::Definition(name, src)
92 }
93 })
94 .collect()
95 }
96}
97
98pub(crate) fn modules<'a>(
99 root: impl ast::ModuleItemOwner<'a>,
100) -> impl Iterator<Item = (Name, ast::Module<'a>)> {
101 root.items()
102 .filter_map(|item| match item {
103 ast::ModuleItem::Module(m) => Some(m),
104 _ => None,
105 })
106 .filter_map(|module| {
107 let name = module.name()?.as_name();
108 Some((name, module))
109 })
110}
111
112pub(super) fn input_module_items( 61pub(super) fn input_module_items(
113 db: &impl HirDatabase, 62 db: &impl HirDatabase,
114 source_root_id: SourceRootId, 63 source_root_id: SourceRootId,
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 29a3960e9..b7e3ff9b0 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -13,11 +13,13 @@ use ra_syntax::{
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Module, Function, SourceItemId, 16 HirDatabase, Function, SourceItemId,
17 module::ModuleSource, 17 module_tree::ModuleSource,
18 DefKind, DefLoc, AsName, 18 DefKind, DefLoc, AsName,
19}; 19};
20 20
21use crate::code_model_api::Module;
22
21/// Locates the module by `FileId`. Picks topmost module in the file. 23/// Locates the module by `FileId`. Picks topmost module in the file.
22pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> { 24pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> {
23 let module_source = ModuleSource::new_file(file_id.into()); 25 let module_source = ModuleSource::new_file(file_id.into());
@@ -34,7 +36,7 @@ pub fn module_from_declaration(
34 let child_name = decl.name(); 36 let child_name = decl.name();
35 match (parent_module, child_name) { 37 match (parent_module, child_name) {
36 (Some(parent_module), Some(child_name)) => { 38 (Some(parent_module), Some(child_name)) => {
37 if let Some(child) = parent_module.child(&child_name.as_name()) { 39 if let Some(child) = parent_module.child(db, &child_name.as_name())? {
38 return Ok(Some(child)); 40 return Ok(Some(child));
39 } 41 }
40 } 42 }
@@ -84,7 +86,15 @@ fn module_from_source(
84 .modules_with_sources() 86 .modules_with_sources()
85 .find(|(_id, src)| src == &module_source); 87 .find(|(_id, src)| src == &module_source);
86 let module_id = ctry!(m).0; 88 let module_id = ctry!(m).0;
87 Ok(Some(Module::new(db, source_root_id, module_id)?)) 89 let def_loc = DefLoc {
90 kind: DefKind::Module,
91 source_root_id,
92 module_id,
93 source_item_id: module_source.0,
94 };
95 let def_id = def_loc.id(db);
96
97 Ok(Some(Module::new(def_id)))
88} 98}
89 99
90pub fn function_from_position( 100pub fn function_from_position(
@@ -114,7 +124,8 @@ pub fn function_from_module(
114 module: &Module, 124 module: &Module,
115 fn_def: ast::FnDef, 125 fn_def: ast::FnDef,
116) -> Function { 126) -> Function {
117 let file_id = module.source().file_id(); 127 let loc = module.def_id.loc(db);
128 let file_id = loc.source_item_id.file_id;
118 let file_items = db.file_items(file_id); 129 let file_items = db.file_items(file_id);
119 let item_id = file_items.id_of(file_id, fn_def.syntax()); 130 let item_id = file_items.id_of(file_id, fn_def.syntax());
120 let source_item_id = SourceItemId { 131 let source_item_id = SourceItemId {
@@ -123,8 +134,8 @@ pub fn function_from_module(
123 }; 134 };
124 let def_loc = DefLoc { 135 let def_loc = DefLoc {
125 kind: DefKind::Function, 136 kind: DefKind::Function,
126 source_root_id: module.source_root_id, 137 source_root_id: loc.source_root_id,
127 module_id: module.module_id, 138 module_id: loc.module_id,
128 source_item_id, 139 source_item_id,
129 }; 140 };
130 Function::new(def_loc.id(db)) 141 Function::new(def_loc.id(db))
@@ -147,7 +158,8 @@ pub fn macro_symbols(
147 Some(it) => it, 158 Some(it) => it,
148 None => return Ok(Vec::new()), 159 None => return Ok(Vec::new()),
149 }; 160 };
150 let items = db.input_module_items(module.source_root_id, module.module_id)?; 161 let loc = module.def_id.loc(db);
162 let items = db.input_module_items(loc.source_root_id, loc.module_id)?;
151 let mut res = Vec::new(); 163 let mut res = Vec::new();
152 164
153 for macro_call_id in items 165 for macro_call_id in items