aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs79
-rw-r--r--crates/ra_analysis/src/imp.rs44
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 @@
1pub(super) mod imp; 1pub(super) mod imp;
2pub(crate) mod scope; 2pub(crate) mod scope;
3 3
4use std::sync::Arc;
5
6use ra_editor::find_node_at_offset;
7
4use ra_syntax::{ 8use ra_syntax::{
5 ast::{self, AstNode, NameOwner}, 9 ast::{self, AstNode, NameOwner},
6 SmolStr, SyntaxNode, SyntaxNodeRef, 10 SmolStr, SyntaxNode, SyntaxNodeRef,
7}; 11};
8use relative_path::RelativePathBuf; 12use relative_path::RelativePathBuf;
9 13
10use crate::{db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId}; 14use crate::{
15 db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable,
16 descriptors::DescriptorDatabase,
17};
11 18
12pub(crate) use self::scope::ModuleScope; 19pub(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)]
24pub(crate) struct ModuleDescriptor {
25 tree: Arc<ModuleTree>,
26 module_id: ModuleId,
27}
28
29impl 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)?;