diff options
Diffstat (limited to 'crates/ra_analysis/src/descriptors/module')
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 79 |
1 files changed, 78 insertions, 1 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, |