diff options
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 79 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 44 |
2 files changed, 94 insertions, 29 deletions
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 055a56b54..d62826ee3 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs | |||
@@ -1,16 +1,90 @@ | |||
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::{ |
5 | ast::{self, AstNode, NameOwner}, | 9 | ast::{self, AstNode, NameOwner}, |
6 | SmolStr, SyntaxNode, SyntaxNodeRef, | 10 | SmolStr, SyntaxNode, SyntaxNodeRef, |
7 | }; | 11 | }; |
8 | use relative_path::RelativePathBuf; | 12 | use relative_path::RelativePathBuf; |
9 | 13 | ||
10 | use crate::{db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId}; | 14 | use crate::{ |
15 | db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable, | ||
16 | descriptors::DescriptorDatabase, | ||
17 | }; | ||
11 | 18 | ||
12 | pub(crate) use self::scope::ModuleScope; | 19 | pub(crate) use self::scope::ModuleScope; |
13 | 20 | ||
21 | /// `ModuleDescriptor` is API entry point to get all the information | ||
22 | /// about a particular module. | ||
23 | #[derive(Debug, Clone)] | ||
24 | pub(crate) struct ModuleDescriptor { | ||
25 | tree: Arc<ModuleTree>, | ||
26 | module_id: ModuleId, | ||
27 | } | ||
28 | |||
29 | impl ModuleDescriptor { | ||
30 | /// Lookup `ModuleDescriptor` by position in the source code. Note that this | ||
31 | /// is inherently lossy transformation: in general, a single source might | ||
32 | /// correspond to several modules. | ||
33 | pub fn guess_from_position( | ||
34 | db: &impl DescriptorDatabase, | ||
35 | position: FilePosition, | ||
36 | ) -> Cancelable<Option<ModuleDescriptor>> { | ||
37 | let source_root = db.file_source_root(position.file_id); | ||
38 | let module_tree = db.module_tree(source_root)?; | ||
39 | let file = db.file_syntax(position.file_id); | ||
40 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) | ||
41 | { | ||
42 | Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), | ||
43 | _ => ModuleSource::SourceFile(position.file_id), | ||
44 | }; | ||
45 | let res = match module_tree.any_module_for_source(module_source) { | ||
46 | None => None, | ||
47 | Some(module_id) => Some(ModuleDescriptor { | ||
48 | tree: module_tree, | ||
49 | module_id, | ||
50 | }), | ||
51 | }; | ||
52 | Ok(res) | ||
53 | } | ||
54 | |||
55 | /// Returns `mod foo;` or `mod foo {}` node whihc declared this module. | ||
56 | /// Returns `None` for the root module | ||
57 | pub fn parent_link_source( | ||
58 | &self, | ||
59 | db: &impl DescriptorDatabase, | ||
60 | ) -> Option<(FileId, ast::ModuleNode)> { | ||
61 | let link = self.module_id.parent_link(&self.tree)?; | ||
62 | let file_id = link.owner(&self.tree).source(&self.tree).file_id(); | ||
63 | let src = link.bind_source(&self.tree, db); | ||
64 | Some((file_id, src)) | ||
65 | } | ||
66 | |||
67 | pub fn parent(&self) -> Option<ModuleDescriptor> { | ||
68 | let parent_id = self.module_id.parent(&self.tree)?; | ||
69 | Some(ModuleDescriptor { | ||
70 | tree: Arc::clone(&self.tree), | ||
71 | module_id: parent_id, | ||
72 | }) | ||
73 | } | ||
74 | /// `name` is `None` for the crate's root module | ||
75 | pub fn name(&self) -> Option<SmolStr> { | ||
76 | let link = self.module_id.parent_link(&self.tree)?; | ||
77 | Some(link.name(&self.tree)) | ||
78 | } | ||
79 | pub fn child(&self, name: &str) -> Option<ModuleDescriptor> { | ||
80 | let child_id = self.module_id.child(&self.tree, name)?; | ||
81 | Some(ModuleDescriptor { | ||
82 | tree: Arc::clone(&self.tree), | ||
83 | module_id: child_id, | ||
84 | }) | ||
85 | } | ||
86 | } | ||
87 | |||
14 | /// Phisically, rust source is organized as a set of files, but logically it is | 88 | /// 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 | 89 | /// organized as a tree of modules. Usually, a single file corresponds to a |
16 | /// single module, but it is not nessary the case. | 90 | /// single module, but it is not nessary the case. |
@@ -136,6 +210,9 @@ impl LinkId { | |||
136 | pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { | 210 | pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { |
137 | tree.link(self).owner | 211 | tree.link(self).owner |
138 | } | 212 | } |
213 | pub(crate) fn name(self, tree: &ModuleTree) -> SmolStr { | ||
214 | tree.link(self).name.clone() | ||
215 | } | ||
139 | pub(crate) fn bind_source<'a>( | 216 | pub(crate) fn bind_source<'a>( |
140 | self, | 217 | self, |
141 | tree: &ModuleTree, | 218 | tree: &ModuleTree, |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 812fed32d..c0bed04bf 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, ModuleSource, ModuleTree, Problem}, |
25 | DeclarationDescriptor, DescriptorDatabase, | 25 | DeclarationDescriptor, DescriptorDatabase, |
26 | }, | 26 | }, |
27 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, | 27 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, |
@@ -221,34 +221,22 @@ impl AnalysisImpl { | |||
221 | self.db.module_tree(source_root) | 221 | self.db.module_tree(source_root) |
222 | } | 222 | } |
223 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 223 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
224 | let module_tree = self.module_tree(position.file_id)?; | 224 | let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? { |
225 | let file = self.db.file_syntax(position.file_id); | 225 | None => return Ok(Vec::new()), |
226 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) | 226 | 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 | }; | 227 | }; |
231 | 228 | let (file_id, decl) = match descr.parent_link_source(&*self.db) { | |
232 | let res = module_tree | 229 | None => return Ok(Vec::new()), |
233 | .modules_for_source(module_source) | 230 | Some(it) => it, |
234 | .into_iter() | 231 | }; |
235 | .filter_map(|module_id| { | 232 | let decl = decl.borrowed(); |
236 | let link = module_id.parent_link(&module_tree)?; | 233 | let decl_name = decl.name().unwrap(); |
237 | let file_id = link.owner(&module_tree).source(&module_tree).file_id(); | 234 | let sym = FileSymbol { |
238 | let decl = link.bind_source(&module_tree, &*self.db); | 235 | name: decl_name.text(), |
239 | let decl = decl.borrowed(); | 236 | node_range: decl_name.syntax().range(), |
240 | 237 | kind: MODULE, | |
241 | let decl_name = decl.name().unwrap(); | 238 | }; |
242 | 239 | 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 | } | 240 | } |
253 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 241 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
254 | let module_tree = self.module_tree(file_id)?; | 242 | let module_tree = self.module_tree(file_id)?; |