diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-20 14:33:54 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-20 14:33:54 +0000 |
commit | 713c3ea30b38199e05e1f70094d85177f16915f8 (patch) | |
tree | f4f3c59a59e4a607b77321cb685bf616824dc8f7 | |
parent | 902778ccaefc7b51548cab459715aaf8653bbbc6 (diff) | |
parent | a2fdb41ace4de7737a3ba0e4ef5e68d0a41e924d (diff) |
Merge #234
234: Global module r=matklad a=matklad
This series of commits re-introdces `ModuleDescriptor` as one stop shop for all information about a module.
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ra_analysis/src/completion/mod.rs | 25 | ||||
-rw-r--r-- | crates/ra_analysis/src/completion/reference_completion.rs | 31 | ||||
-rw-r--r-- | crates/ra_analysis/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/function/imp.rs | 2 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/mod.rs | 21 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/imp.rs | 4 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 190 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 136 | ||||
-rw-r--r-- | crates/ra_analysis/src/loc2id.rs | 23 |
9 files changed, 233 insertions, 203 deletions
diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs index 2e082705e..5e3ee79dd 100644 --- a/crates/ra_analysis/src/completion/mod.rs +++ b/crates/ra_analysis/src/completion/mod.rs | |||
@@ -2,7 +2,6 @@ mod reference_completion; | |||
2 | 2 | ||
3 | use ra_editor::find_node_at_offset; | 3 | use ra_editor::find_node_at_offset; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | algo::find_leaf_at_offset, | ||
6 | algo::visit::{visitor_ctx, VisitorCtx}, | 5 | algo::visit::{visitor_ctx, VisitorCtx}, |
7 | ast, | 6 | ast, |
8 | AstNode, AtomEdit, | 7 | AstNode, AtomEdit, |
@@ -12,8 +11,9 @@ use rustc_hash::{FxHashMap}; | |||
12 | 11 | ||
13 | use crate::{ | 12 | use crate::{ |
14 | db::{self, SyntaxDatabase}, | 13 | db::{self, SyntaxDatabase}, |
15 | descriptors::{DescriptorDatabase, module::ModuleSource}, | 14 | descriptors::{ |
16 | input::{FilesDatabase}, | 15 | module::{ModuleDescriptor} |
16 | }, | ||
17 | Cancelable, FilePosition | 17 | Cancelable, FilePosition |
18 | }; | 18 | }; |
19 | 19 | ||
@@ -38,14 +38,7 @@ pub(crate) fn completions( | |||
38 | original_file.reparse(&edit) | 38 | original_file.reparse(&edit) |
39 | }; | 39 | }; |
40 | 40 | ||
41 | let leaf = match find_leaf_at_offset(original_file.syntax(), position.offset).left_biased() { | 41 | let module = match ModuleDescriptor::guess_from_position(db, position)? { |
42 | None => return Ok(None), | ||
43 | Some(it) => it, | ||
44 | }; | ||
45 | let source_root_id = db.file_source_root(position.file_id); | ||
46 | let module_tree = db.module_tree(source_root_id)?; | ||
47 | let module_source = ModuleSource::for_node(position.file_id, leaf); | ||
48 | let module_id = match module_tree.any_module_for_source(module_source) { | ||
49 | None => return Ok(None), | 42 | None => return Ok(None), |
50 | Some(it) => it, | 43 | Some(it) => it, |
51 | }; | 44 | }; |
@@ -55,15 +48,7 @@ pub(crate) fn completions( | |||
55 | // First, let's try to complete a reference to some declaration. | 48 | // First, let's try to complete a reference to some declaration. |
56 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { | 49 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { |
57 | has_completions = true; | 50 | has_completions = true; |
58 | reference_completion::completions( | 51 | reference_completion::completions(&mut res, db, &module, &file, name_ref)?; |
59 | &mut res, | ||
60 | db, | ||
61 | source_root_id, | ||
62 | &module_tree, | ||
63 | module_id, | ||
64 | &file, | ||
65 | name_ref, | ||
66 | )?; | ||
67 | // special case, `trait T { fn foo(i_am_a_name_ref) {} }` | 52 | // special case, `trait T { fn foo(i_am_a_name_ref) {} }` |
68 | if is_node::<ast::Param>(name_ref.syntax()) { | 53 | if is_node::<ast::Param>(name_ref.syntax()) { |
69 | param_completions(name_ref.syntax(), &mut res); | 54 | param_completions(name_ref.syntax(), &mut res); |
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index 6c5fd0be6..c94d9af75 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs | |||
@@ -9,20 +9,16 @@ use ra_syntax::{ | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::RootDatabase, | 11 | db::RootDatabase, |
12 | input::{SourceRootId}, | ||
13 | completion::CompletionItem, | 12 | completion::CompletionItem, |
14 | descriptors::module::{ModuleId, ModuleTree}, | 13 | descriptors::module::{ModuleDescriptor}, |
15 | descriptors::function::FnScopes, | 14 | descriptors::function::FnScopes, |
16 | descriptors::DescriptorDatabase, | ||
17 | Cancelable | 15 | Cancelable |
18 | }; | 16 | }; |
19 | 17 | ||
20 | pub(super) fn completions( | 18 | pub(super) fn completions( |
21 | acc: &mut Vec<CompletionItem>, | 19 | acc: &mut Vec<CompletionItem>, |
22 | db: &RootDatabase, | 20 | db: &RootDatabase, |
23 | source_root_id: SourceRootId, | 21 | module: &ModuleDescriptor, |
24 | module_tree: &ModuleTree, | ||
25 | module_id: ModuleId, | ||
26 | file: &SourceFileNode, | 22 | file: &SourceFileNode, |
27 | name_ref: ast::NameRef, | 23 | name_ref: ast::NameRef, |
28 | ) -> Cancelable<()> { | 24 | ) -> Cancelable<()> { |
@@ -40,7 +36,7 @@ pub(super) fn completions( | |||
40 | complete_expr_snippets(acc); | 36 | complete_expr_snippets(acc); |
41 | } | 37 | } |
42 | 38 | ||
43 | let module_scope = db.module_scope(source_root_id, module_id)?; | 39 | let module_scope = module.scope(db)?; |
44 | acc.extend( | 40 | acc.extend( |
45 | module_scope | 41 | module_scope |
46 | .entries() | 42 | .entries() |
@@ -56,9 +52,7 @@ pub(super) fn completions( | |||
56 | }), | 52 | }), |
57 | ); | 53 | ); |
58 | } | 54 | } |
59 | NameRefKind::CratePath(path) => { | 55 | NameRefKind::CratePath(path) => complete_path(acc, db, module, path)?, |
60 | complete_path(acc, db, source_root_id, module_tree, module_id, path)? | ||
61 | } | ||
62 | NameRefKind::BareIdentInMod => { | 56 | NameRefKind::BareIdentInMod => { |
63 | let name_range = name_ref.syntax().range(); | 57 | let name_range = name_ref.syntax().range(); |
64 | let top_node = name_ref | 58 | let top_node = name_ref |
@@ -171,16 +165,14 @@ fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<Completi | |||
171 | fn complete_path( | 165 | fn complete_path( |
172 | acc: &mut Vec<CompletionItem>, | 166 | acc: &mut Vec<CompletionItem>, |
173 | db: &RootDatabase, | 167 | db: &RootDatabase, |
174 | source_root_id: SourceRootId, | 168 | module: &ModuleDescriptor, |
175 | module_tree: &ModuleTree, | ||
176 | module_id: ModuleId, | ||
177 | crate_path: Vec<ast::NameRef>, | 169 | crate_path: Vec<ast::NameRef>, |
178 | ) -> Cancelable<()> { | 170 | ) -> Cancelable<()> { |
179 | let target_module_id = match find_target_module(module_tree, module_id, crate_path) { | 171 | let target_module = match find_target_module(module, crate_path) { |
180 | None => return Ok(()), | 172 | None => return Ok(()), |
181 | Some(it) => it, | 173 | Some(it) => it, |
182 | }; | 174 | }; |
183 | let module_scope = db.module_scope(source_root_id, target_module_id)?; | 175 | let module_scope = target_module.scope(db)?; |
184 | let completions = module_scope.entries().iter().map(|entry| CompletionItem { | 176 | let completions = module_scope.entries().iter().map(|entry| CompletionItem { |
185 | label: entry.name().to_string(), | 177 | label: entry.name().to_string(), |
186 | lookup: None, | 178 | lookup: None, |
@@ -191,14 +183,13 @@ fn complete_path( | |||
191 | } | 183 | } |
192 | 184 | ||
193 | fn find_target_module( | 185 | fn find_target_module( |
194 | module_tree: &ModuleTree, | 186 | module: &ModuleDescriptor, |
195 | module_id: ModuleId, | ||
196 | mut crate_path: Vec<ast::NameRef>, | 187 | mut crate_path: Vec<ast::NameRef>, |
197 | ) -> Option<ModuleId> { | 188 | ) -> Option<ModuleDescriptor> { |
198 | crate_path.pop(); | 189 | crate_path.pop(); |
199 | let mut target_module = module_id.root(&module_tree); | 190 | let mut target_module = module.crate_root(); |
200 | for name in crate_path { | 191 | for name in crate_path { |
201 | target_module = target_module.child(module_tree, name.text().as_str())?; | 192 | target_module = target_module.child(name.text().as_str())?; |
202 | } | 193 | } |
203 | Some(target_module) | 194 | Some(target_module) |
204 | } | 195 | } |
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index d78b6afb9..8133b7875 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -85,10 +85,10 @@ salsa::database_storage! { | |||
85 | } | 85 | } |
86 | impl DescriptorDatabase { | 86 | impl DescriptorDatabase { |
87 | fn module_tree() for ModuleTreeQuery; | 87 | fn module_tree() for ModuleTreeQuery; |
88 | fn module_descriptor() for SubmodulesQuery; | ||
89 | fn module_scope() for ModuleScopeQuery; | 88 | fn module_scope() for ModuleScopeQuery; |
90 | fn fn_syntax() for FnSyntaxQuery; | ||
91 | fn fn_scopes() for FnScopesQuery; | 89 | fn fn_scopes() for FnScopesQuery; |
90 | fn _fn_syntax() for FnSyntaxQuery; | ||
91 | fn _submodules() for SubmodulesQuery; | ||
92 | } | 92 | } |
93 | } | 93 | } |
94 | } | 94 | } |
diff --git a/crates/ra_analysis/src/descriptors/function/imp.rs b/crates/ra_analysis/src/descriptors/function/imp.rs index a7257acf9..e09deba0f 100644 --- a/crates/ra_analysis/src/descriptors/function/imp.rs +++ b/crates/ra_analysis/src/descriptors/function/imp.rs | |||
@@ -15,7 +15,7 @@ pub(crate) fn fn_syntax(db: &impl DescriptorDatabase, fn_id: FnId) -> FnDefNode | |||
15 | } | 15 | } |
16 | 16 | ||
17 | pub(crate) fn fn_scopes(db: &impl DescriptorDatabase, fn_id: FnId) -> Arc<FnScopes> { | 17 | pub(crate) fn fn_scopes(db: &impl DescriptorDatabase, fn_id: FnId) -> Arc<FnScopes> { |
18 | let syntax = db.fn_syntax(fn_id); | 18 | let syntax = db._fn_syntax(fn_id); |
19 | let res = FnScopes::new(syntax.borrowed()); | 19 | let res = FnScopes::new(syntax.borrowed()); |
20 | Arc::new(res) | 20 | Arc::new(res) |
21 | } | 21 | } |
diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs index d602c4e04..a8489f89c 100644 --- a/crates/ra_analysis/src/descriptors/mod.rs +++ b/crates/ra_analysis/src/descriptors/mod.rs | |||
@@ -20,27 +20,28 @@ use crate::{ | |||
20 | 20 | ||
21 | salsa::query_group! { | 21 | salsa::query_group! { |
22 | pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase { | 22 | pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase { |
23 | fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { | 23 | fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { |
24 | type FnScopesQuery; | ||
25 | use fn function::imp::fn_scopes; | ||
26 | } | ||
27 | |||
28 | fn _module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { | ||
24 | type ModuleTreeQuery; | 29 | type ModuleTreeQuery; |
25 | use fn module::imp::module_tree; | 30 | use fn module::imp::module_tree; |
26 | } | 31 | } |
27 | fn submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> { | 32 | fn _module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> { |
28 | type SubmodulesQuery; | ||
29 | use fn module::imp::submodules; | ||
30 | } | ||
31 | fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> { | ||
32 | type ModuleScopeQuery; | 33 | type ModuleScopeQuery; |
33 | use fn module::imp::module_scope; | 34 | use fn module::imp::module_scope; |
34 | } | 35 | } |
35 | fn fn_syntax(fn_id: FnId) -> FnDefNode { | 36 | fn _fn_syntax(fn_id: FnId) -> FnDefNode { |
36 | type FnSyntaxQuery; | 37 | type FnSyntaxQuery; |
37 | // Don't retain syntax trees in memory | 38 | // Don't retain syntax trees in memory |
38 | storage volatile; | 39 | storage volatile; |
39 | use fn function::imp::fn_syntax; | 40 | use fn function::imp::fn_syntax; |
40 | } | 41 | } |
41 | fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { | 42 | fn _submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> { |
42 | type FnScopesQuery; | 43 | type SubmodulesQuery; |
43 | use fn function::imp::fn_scopes; | 44 | use fn module::imp::submodules; |
44 | } | 45 | } |
45 | } | 46 | } |
46 | } | 47 | } |
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index ade96ddc0..defe87216 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs | |||
@@ -86,7 +86,7 @@ pub(crate) fn module_scope( | |||
86 | source_root_id: SourceRootId, | 86 | source_root_id: SourceRootId, |
87 | module_id: ModuleId, | 87 | module_id: ModuleId, |
88 | ) -> Cancelable<Arc<ModuleScope>> { | 88 | ) -> Cancelable<Arc<ModuleScope>> { |
89 | let tree = db.module_tree(source_root_id)?; | 89 | let tree = db._module_tree(source_root_id)?; |
90 | let source = module_id.source(&tree).resolve(db); | 90 | let source = module_id.source(&tree).resolve(db); |
91 | let res = match source { | 91 | let res = match source { |
92 | ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()), | 92 | ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()), |
@@ -155,7 +155,7 @@ fn build_subtree( | |||
155 | parent, | 155 | parent, |
156 | children: Vec::new(), | 156 | children: Vec::new(), |
157 | }); | 157 | }); |
158 | for sub in db.submodules(source)?.iter() { | 158 | for sub in db._submodules(source)?.iter() { |
159 | let link = tree.push_link(LinkData { | 159 | let link = tree.push_link(LinkData { |
160 | name: sub.name().clone(), | 160 | name: sub.name().clone(), |
161 | owner: id, | 161 | owner: id, |
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 055a56b54..047454cff 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs | |||
@@ -1,16 +1,137 @@ | |||
1 | pub(super) mod imp; | 1 | pub(super) mod imp; |
2 | pub(crate) mod scope; | 2 | pub(crate) mod scope; |
3 | 3 | ||
4 | use std::sync::Arc; | ||
5 | |||
6 | use ra_editor::find_node_at_offset; | ||
7 | |||
4 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | algo::generate, | ||
5 | ast::{self, AstNode, NameOwner}, | 10 | ast::{self, AstNode, NameOwner}, |
6 | SmolStr, SyntaxNode, SyntaxNodeRef, | 11 | SmolStr, SyntaxNode, |
7 | }; | 12 | }; |
8 | use relative_path::RelativePathBuf; | 13 | use relative_path::RelativePathBuf; |
9 | 14 | ||
10 | use crate::{db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId}; | 15 | use crate::{ |
16 | db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable, | ||
17 | descriptors::DescriptorDatabase, | ||
18 | input::SourceRootId | ||
19 | }; | ||
11 | 20 | ||
12 | pub(crate) use self::scope::ModuleScope; | 21 | pub(crate) use self::scope::ModuleScope; |
13 | 22 | ||
23 | /// `ModuleDescriptor` is API entry point to get all the information | ||
24 | /// about a particular module. | ||
25 | #[derive(Debug, Clone)] | ||
26 | pub(crate) struct ModuleDescriptor { | ||
27 | tree: Arc<ModuleTree>, | ||
28 | source_root_id: SourceRootId, | ||
29 | module_id: ModuleId, | ||
30 | } | ||
31 | |||
32 | impl ModuleDescriptor { | ||
33 | /// Lookup `ModuleDescriptor` by `FileId`. Note that this is inherently | ||
34 | /// lossy transformation: in general, a single source might correspond to | ||
35 | /// several modules. | ||
36 | pub fn guess_from_file_id( | ||
37 | db: &impl DescriptorDatabase, | ||
38 | file_id: FileId, | ||
39 | ) -> Cancelable<Option<ModuleDescriptor>> { | ||
40 | ModuleDescriptor::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id)) | ||
41 | } | ||
42 | |||
43 | /// Lookup `ModuleDescriptor` by position in the source code. Note that this | ||
44 | /// is inherently lossy transformation: in general, a single source might | ||
45 | /// correspond to several modules. | ||
46 | pub fn guess_from_position( | ||
47 | db: &impl DescriptorDatabase, | ||
48 | position: FilePosition, | ||
49 | ) -> Cancelable<Option<ModuleDescriptor>> { | ||
50 | let file = db.file_syntax(position.file_id); | ||
51 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) | ||
52 | { | ||
53 | Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), | ||
54 | _ => ModuleSource::SourceFile(position.file_id), | ||
55 | }; | ||
56 | ModuleDescriptor::guess_from_source(db, position.file_id, module_source) | ||
57 | } | ||
58 | |||
59 | fn guess_from_source( | ||
60 | db: &impl DescriptorDatabase, | ||
61 | file_id: FileId, | ||
62 | module_source: ModuleSource, | ||
63 | ) -> Cancelable<Option<ModuleDescriptor>> { | ||
64 | let source_root_id = db.file_source_root(file_id); | ||
65 | let module_tree = db._module_tree(source_root_id)?; | ||
66 | |||
67 | let res = match module_tree.any_module_for_source(module_source) { | ||
68 | None => None, | ||
69 | Some(module_id) => Some(ModuleDescriptor { | ||
70 | tree: module_tree, | ||
71 | source_root_id, | ||
72 | module_id, | ||
73 | }), | ||
74 | }; | ||
75 | Ok(res) | ||
76 | } | ||
77 | |||
78 | /// Returns `mod foo;` or `mod foo {}` node whihc declared this module. | ||
79 | /// Returns `None` for the root module | ||
80 | pub fn parent_link_source( | ||
81 | &self, | ||
82 | db: &impl DescriptorDatabase, | ||
83 | ) -> Option<(FileId, ast::ModuleNode)> { | ||
84 | let link = self.module_id.parent_link(&self.tree)?; | ||
85 | let file_id = link.owner(&self.tree).source(&self.tree).file_id(); | ||
86 | let src = link.bind_source(&self.tree, db); | ||
87 | Some((file_id, src)) | ||
88 | } | ||
89 | |||
90 | pub fn source(&self) -> ModuleSource { | ||
91 | self.module_id.source(&self.tree) | ||
92 | } | ||
93 | |||
94 | /// Parent module. Returns `None` if this is a root module. | ||
95 | pub fn parent(&self) -> Option<ModuleDescriptor> { | ||
96 | let parent_id = self.module_id.parent(&self.tree)?; | ||
97 | Some(ModuleDescriptor { | ||
98 | module_id: parent_id, | ||
99 | ..self.clone() | ||
100 | }) | ||
101 | } | ||
102 | |||
103 | /// The root of the tree this module is part of | ||
104 | pub fn crate_root(&self) -> ModuleDescriptor { | ||
105 | generate(Some(self.clone()), |it| it.parent()) | ||
106 | .last() | ||
107 | .unwrap() | ||
108 | } | ||
109 | |||
110 | /// `name` is `None` for the crate's root module | ||
111 | pub fn name(&self) -> Option<SmolStr> { | ||
112 | let link = self.module_id.parent_link(&self.tree)?; | ||
113 | Some(link.name(&self.tree)) | ||
114 | } | ||
115 | |||
116 | /// Finds a child module with the specified name. | ||
117 | pub fn child(&self, name: &str) -> Option<ModuleDescriptor> { | ||
118 | let child_id = self.module_id.child(&self.tree, name)?; | ||
119 | Some(ModuleDescriptor { | ||
120 | module_id: child_id, | ||
121 | ..self.clone() | ||
122 | }) | ||
123 | } | ||
124 | |||
125 | /// Returns a `ModuleScope`: a set of items, visible in this module. | ||
126 | pub fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable<Arc<ModuleScope>> { | ||
127 | db._module_scope(self.source_root_id, self.module_id) | ||
128 | } | ||
129 | |||
130 | pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> { | ||
131 | self.module_id.problems(&self.tree, db) | ||
132 | } | ||
133 | } | ||
134 | |||
14 | /// Phisically, rust source is organized as a set of files, but logically it is | 135 | /// Phisically, rust source is organized as a set of files, but logically it is |
15 | /// organized as a tree of modules. Usually, a single file corresponds to a | 136 | /// organized as a tree of modules. Usually, a single file corresponds to a |
16 | /// single module, but it is not nessary the case. | 137 | /// single module, but it is not nessary the case. |
@@ -25,7 +146,7 @@ pub(crate) struct ModuleTree { | |||
25 | } | 146 | } |
26 | 147 | ||
27 | impl ModuleTree { | 148 | impl ModuleTree { |
28 | pub(crate) fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> { | 149 | fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> { |
29 | self.mods | 150 | self.mods |
30 | .iter() | 151 | .iter() |
31 | .enumerate() | 152 | .enumerate() |
@@ -34,7 +155,7 @@ impl ModuleTree { | |||
34 | .collect() | 155 | .collect() |
35 | } | 156 | } |
36 | 157 | ||
37 | pub(crate) fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> { | 158 | fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> { |
38 | self.modules_for_source(source).pop() | 159 | self.modules_for_source(source).pop() |
39 | } | 160 | } |
40 | } | 161 | } |
@@ -58,17 +179,8 @@ enum ModuleSourceNode { | |||
58 | #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] | 179 | #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] |
59 | pub(crate) struct ModuleId(u32); | 180 | pub(crate) struct ModuleId(u32); |
60 | 181 | ||
61 | impl crate::loc2id::NumericId for ModuleId { | ||
62 | fn from_u32(id: u32) -> Self { | ||
63 | ModuleId(id) | ||
64 | } | ||
65 | fn to_u32(self) -> u32 { | ||
66 | self.0 | ||
67 | } | ||
68 | } | ||
69 | |||
70 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | 182 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
71 | pub(crate) struct LinkId(u32); | 183 | struct LinkId(u32); |
72 | 184 | ||
73 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 185 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
74 | pub enum Problem { | 186 | pub enum Problem { |
@@ -82,30 +194,17 @@ pub enum Problem { | |||
82 | } | 194 | } |
83 | 195 | ||
84 | impl ModuleId { | 196 | impl ModuleId { |
85 | pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { | 197 | fn source(self, tree: &ModuleTree) -> ModuleSource { |
86 | tree.module(self).source | 198 | tree.module(self).source |
87 | } | 199 | } |
88 | pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { | 200 | fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { |
89 | tree.module(self).parent | 201 | tree.module(self).parent |
90 | } | 202 | } |
91 | pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> { | 203 | fn parent(self, tree: &ModuleTree) -> Option<ModuleId> { |
92 | let link = self.parent_link(tree)?; | 204 | let link = self.parent_link(tree)?; |
93 | Some(tree.link(link).owner) | 205 | Some(tree.link(link).owner) |
94 | } | 206 | } |
95 | pub(crate) fn root(self, tree: &ModuleTree) -> ModuleId { | 207 | fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> { |
96 | let mut curr = self; | ||
97 | let mut i = 0; | ||
98 | while let Some(next) = curr.parent(tree) { | ||
99 | curr = next; | ||
100 | i += 1; | ||
101 | // simplistic cycle detection | ||
102 | if i > 100 { | ||
103 | return self; | ||
104 | } | ||
105 | } | ||
106 | curr | ||
107 | } | ||
108 | pub(crate) fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> { | ||
109 | let link = tree | 208 | let link = tree |
110 | .module(self) | 209 | .module(self) |
111 | .children | 210 | .children |
@@ -114,11 +213,7 @@ impl ModuleId { | |||
114 | .find(|it| it.name == name)?; | 213 | .find(|it| it.name == name)?; |
115 | Some(*link.points_to.first()?) | 214 | Some(*link.points_to.first()?) |
116 | } | 215 | } |
117 | pub(crate) fn problems( | 216 | fn problems(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> Vec<(SyntaxNode, Problem)> { |
118 | self, | ||
119 | tree: &ModuleTree, | ||
120 | db: &impl SyntaxDatabase, | ||
121 | ) -> Vec<(SyntaxNode, Problem)> { | ||
122 | tree.module(self) | 217 | tree.module(self) |
123 | .children | 218 | .children |
124 | .iter() | 219 | .iter() |
@@ -133,14 +228,13 @@ impl ModuleId { | |||
133 | } | 228 | } |
134 | 229 | ||
135 | impl LinkId { | 230 | impl LinkId { |
136 | pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { | 231 | fn owner(self, tree: &ModuleTree) -> ModuleId { |
137 | tree.link(self).owner | 232 | tree.link(self).owner |
138 | } | 233 | } |
139 | pub(crate) fn bind_source<'a>( | 234 | fn name(self, tree: &ModuleTree) -> SmolStr { |
140 | self, | 235 | tree.link(self).name.clone() |
141 | tree: &ModuleTree, | 236 | } |
142 | db: &impl SyntaxDatabase, | 237 | fn bind_source<'a>(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> ast::ModuleNode { |
143 | ) -> ast::ModuleNode { | ||
144 | let owner = self.owner(tree); | 238 | let owner = self.owner(tree); |
145 | match owner.source(tree).resolve(db) { | 239 | match owner.source(tree).resolve(db) { |
146 | ModuleSourceNode::SourceFile(root) => { | 240 | ModuleSourceNode::SourceFile(root) => { |
@@ -163,17 +257,7 @@ struct ModuleData { | |||
163 | } | 257 | } |
164 | 258 | ||
165 | impl ModuleSource { | 259 | impl ModuleSource { |
166 | pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource { | 260 | fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { |
167 | for node in node.ancestors() { | ||
168 | if let Some(m) = ast::Module::cast(node) { | ||
169 | if !m.has_semi() { | ||
170 | return ModuleSource::new_inline(file_id, m); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | ModuleSource::SourceFile(file_id) | ||
175 | } | ||
176 | pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { | ||
177 | assert!(!module.has_semi()); | 261 | assert!(!module.has_semi()); |
178 | let ptr = SyntaxPtr::new(file_id, module.syntax()); | 262 | let ptr = SyntaxPtr::new(file_id, module.syntax()); |
179 | ModuleSource::Module(ptr) | 263 | ModuleSource::Module(ptr) |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 812fed32d..e1493bdaa 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -21,7 +21,7 @@ use crate::{ | |||
21 | db::{self, FileSyntaxQuery, SyntaxDatabase}, | 21 | db::{self, FileSyntaxQuery, SyntaxDatabase}, |
22 | descriptors::{ | 22 | descriptors::{ |
23 | function::{FnDescriptor, FnId}, | 23 | function::{FnDescriptor, FnId}, |
24 | module::{ModuleSource, ModuleTree, Problem}, | 24 | module::{ModuleDescriptor, Problem}, |
25 | DeclarationDescriptor, DescriptorDatabase, | 25 | DeclarationDescriptor, DescriptorDatabase, |
26 | }, | 26 | }, |
27 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, | 27 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, |
@@ -216,52 +216,41 @@ impl AnalysisImpl { | |||
216 | .sweep(salsa::SweepStrategy::default().discard_values()); | 216 | .sweep(salsa::SweepStrategy::default().discard_values()); |
217 | Ok(query.search(&buf)) | 217 | Ok(query.search(&buf)) |
218 | } | 218 | } |
219 | fn module_tree(&self, file_id: FileId) -> Cancelable<Arc<ModuleTree>> { | 219 | /// This return `Vec`: a module may be included from several places. We |
220 | let source_root = self.db.file_source_root(file_id); | 220 | /// don't handle this case yet though, so the Vec has length at most one. |
221 | self.db.module_tree(source_root) | ||
222 | } | ||
223 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 221 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
224 | let module_tree = self.module_tree(position.file_id)?; | 222 | let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? { |
225 | let file = self.db.file_syntax(position.file_id); | 223 | None => return Ok(Vec::new()), |
226 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) | 224 | Some(it) => it, |
227 | { | ||
228 | Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), | ||
229 | _ => ModuleSource::SourceFile(position.file_id), | ||
230 | }; | 225 | }; |
231 | 226 | let (file_id, decl) = match descr.parent_link_source(&*self.db) { | |
232 | let res = module_tree | 227 | None => return Ok(Vec::new()), |
233 | .modules_for_source(module_source) | 228 | Some(it) => it, |
234 | .into_iter() | 229 | }; |
235 | .filter_map(|module_id| { | 230 | let decl = decl.borrowed(); |
236 | let link = module_id.parent_link(&module_tree)?; | 231 | let decl_name = decl.name().unwrap(); |
237 | let file_id = link.owner(&module_tree).source(&module_tree).file_id(); | 232 | let sym = FileSymbol { |
238 | let decl = link.bind_source(&module_tree, &*self.db); | 233 | name: decl_name.text(), |
239 | let decl = decl.borrowed(); | 234 | node_range: decl_name.syntax().range(), |
240 | 235 | kind: MODULE, | |
241 | let decl_name = decl.name().unwrap(); | 236 | }; |
242 | 237 | Ok(vec![(file_id, sym)]) | |
243 | let sym = FileSymbol { | ||
244 | name: decl_name.text(), | ||
245 | node_range: decl_name.syntax().range(), | ||
246 | kind: MODULE, | ||
247 | }; | ||
248 | Some((file_id, sym)) | ||
249 | }) | ||
250 | .collect(); | ||
251 | Ok(res) | ||
252 | } | 238 | } |
239 | /// Returns `Vec` for the same reason as `parent_module` | ||
253 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 240 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
254 | let module_tree = self.module_tree(file_id)?; | 241 | let descr = match ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? { |
255 | let crate_graph = self.db.crate_graph(); | 242 | None => return Ok(Vec::new()), |
256 | let res = module_tree | 243 | Some(it) => it, |
257 | .modules_for_source(ModuleSource::SourceFile(file_id)) | 244 | }; |
258 | .into_iter() | 245 | let root = descr.crate_root(); |
259 | .map(|it| it.root(&module_tree)) | 246 | let file_id = root |
260 | .filter_map(|it| it.source(&module_tree).as_file()) | 247 | .source() |
261 | .filter_map(|it| crate_graph.crate_id_for_crate_root(it)) | 248 | .as_file() |
262 | .collect(); | 249 | .expect("root module always has a file as a source"); |
263 | 250 | ||
264 | Ok(res) | 251 | let crate_graph = self.db.crate_graph(); |
252 | let crate_id = crate_graph.crate_id_for_crate_root(file_id); | ||
253 | Ok(crate_id.into_iter().collect()) | ||
265 | } | 254 | } |
266 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 255 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { |
267 | self.db.crate_graph().crate_roots[&crate_id] | 256 | self.db.crate_graph().crate_roots[&crate_id] |
@@ -273,7 +262,6 @@ impl AnalysisImpl { | |||
273 | &self, | 262 | &self, |
274 | position: FilePosition, | 263 | position: FilePosition, |
275 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 264 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
276 | let module_tree = self.module_tree(position.file_id)?; | ||
277 | let file = self.db.file_syntax(position.file_id); | 265 | let file = self.db.file_syntax(position.file_id); |
278 | let syntax = file.syntax(); | 266 | let syntax = file.syntax(); |
279 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | 267 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { |
@@ -299,25 +287,23 @@ impl AnalysisImpl { | |||
299 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | 287 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { |
300 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 288 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
301 | if module.has_semi() { | 289 | if module.has_semi() { |
302 | let file_ids = self.resolve_module(&*module_tree, position.file_id, module); | 290 | let parent_module = |
303 | 291 | ModuleDescriptor::guess_from_file_id(&*self.db, position.file_id)?; | |
304 | let res = file_ids | 292 | let child_name = module.name(); |
305 | .into_iter() | 293 | match (parent_module, child_name) { |
306 | .map(|id| { | 294 | (Some(parent_module), Some(child_name)) => { |
307 | let name = module | 295 | if let Some(child) = parent_module.child(&child_name.text()) { |
308 | .name() | 296 | let file_id = child.source().file_id(); |
309 | .map(|n| n.text()) | 297 | let symbol = FileSymbol { |
310 | .unwrap_or_else(|| SmolStr::new("")); | 298 | name: child_name.text(), |
311 | let symbol = FileSymbol { | 299 | node_range: TextRange::offset_len(0.into(), 0.into()), |
312 | name, | 300 | kind: MODULE, |
313 | node_range: TextRange::offset_len(0.into(), 0.into()), | 301 | }; |
314 | kind: MODULE, | 302 | return Ok(vec![(file_id, symbol)]); |
315 | }; | 303 | } |
316 | (id, symbol) | 304 | } |
317 | }) | 305 | _ => (), |
318 | .collect(); | 306 | } |
319 | |||
320 | return Ok(res); | ||
321 | } | 307 | } |
322 | } | 308 | } |
323 | } | 309 | } |
@@ -364,7 +350,6 @@ impl AnalysisImpl { | |||
364 | } | 350 | } |
365 | 351 | ||
366 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 352 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
367 | let module_tree = self.module_tree(file_id)?; | ||
368 | let syntax = self.db.file_syntax(file_id); | 353 | let syntax = self.db.file_syntax(file_id); |
369 | 354 | ||
370 | let mut res = ra_editor::diagnostics(&syntax) | 355 | let mut res = ra_editor::diagnostics(&syntax) |
@@ -375,8 +360,8 @@ impl AnalysisImpl { | |||
375 | fix: None, | 360 | fix: None, |
376 | }) | 361 | }) |
377 | .collect::<Vec<_>>(); | 362 | .collect::<Vec<_>>(); |
378 | if let Some(m) = module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) { | 363 | if let Some(m) = ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? { |
379 | for (name_node, problem) in m.problems(&module_tree, &*self.db) { | 364 | for (name_node, problem) in m.problems(&*self.db) { |
380 | let diag = match problem { | 365 | let diag = match problem { |
381 | Problem::UnresolvedModule { candidate } => { | 366 | Problem::UnresolvedModule { candidate } => { |
382 | let create_file = FileSystemEdit::CreateFile { | 367 | let create_file = FileSystemEdit::CreateFile { |
@@ -526,27 +511,6 @@ impl AnalysisImpl { | |||
526 | query.limit(4); | 511 | query.limit(4); |
527 | self.world_symbols(query) | 512 | self.world_symbols(query) |
528 | } | 513 | } |
529 | |||
530 | fn resolve_module( | ||
531 | &self, | ||
532 | module_tree: &ModuleTree, | ||
533 | file_id: FileId, | ||
534 | module: ast::Module, | ||
535 | ) -> Vec<FileId> { | ||
536 | let name = match module.name() { | ||
537 | Some(name) => name.text(), | ||
538 | None => return Vec::new(), | ||
539 | }; | ||
540 | let module_id = match module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) { | ||
541 | Some(id) => id, | ||
542 | None => return Vec::new(), | ||
543 | }; | ||
544 | module_id | ||
545 | .child(module_tree, name.as_str()) | ||
546 | .and_then(|it| it.source(&module_tree).as_file()) | ||
547 | .into_iter() | ||
548 | .collect() | ||
549 | } | ||
550 | } | 514 | } |
551 | 515 | ||
552 | impl SourceChange { | 516 | impl SourceChange { |
diff --git a/crates/ra_analysis/src/loc2id.rs b/crates/ra_analysis/src/loc2id.rs index 8eaa24997..8c297156a 100644 --- a/crates/ra_analysis/src/loc2id.rs +++ b/crates/ra_analysis/src/loc2id.rs | |||
@@ -72,17 +72,22 @@ pub(crate) trait NumericId: Clone + Eq + Hash { | |||
72 | fn to_u32(self) -> u32; | 72 | fn to_u32(self) -> u32; |
73 | } | 73 | } |
74 | 74 | ||
75 | macro_rules! impl_numeric_id { | ||
76 | ($id:ident) => { | ||
77 | impl NumericId for $id { | ||
78 | fn from_u32(id: u32) -> Self { | ||
79 | $id(id) | ||
80 | } | ||
81 | fn to_u32(self) -> u32 { | ||
82 | self.0 | ||
83 | } | ||
84 | } | ||
85 | }; | ||
86 | } | ||
87 | |||
75 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 88 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
76 | pub(crate) struct FnId(u32); | 89 | pub(crate) struct FnId(u32); |
77 | 90 | impl_numeric_id!(FnId); | |
78 | impl NumericId for FnId { | ||
79 | fn from_u32(id: u32) -> FnId { | ||
80 | FnId(id) | ||
81 | } | ||
82 | fn to_u32(self) -> u32 { | ||
83 | self.0 | ||
84 | } | ||
85 | } | ||
86 | 91 | ||
87 | pub(crate) trait IdDatabase: salsa::Database { | 92 | pub(crate) trait IdDatabase: salsa::Database { |
88 | fn id_maps(&self) -> &IdMaps; | 93 | fn id_maps(&self) -> &IdMaps; |