aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs37
-rw-r--r--crates/ra_analysis/src/imp.rs25
2 files changed, 50 insertions, 12 deletions
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs
index 8a75e11be..16faea94e 100644
--- a/crates/ra_analysis/src/descriptors/module/mod.rs
+++ b/crates/ra_analysis/src/descriptors/module/mod.rs
@@ -6,6 +6,7 @@ use std::sync::Arc;
6use ra_editor::find_node_at_offset; 6use ra_editor::find_node_at_offset;
7 7
8use ra_syntax::{ 8use ra_syntax::{
9 algo::generate,
9 ast::{self, AstNode, NameOwner}, 10 ast::{self, AstNode, NameOwner},
10 SmolStr, SyntaxNode, SyntaxNodeRef, 11 SmolStr, SyntaxNode, SyntaxNodeRef,
11}; 12};
@@ -27,6 +28,16 @@ pub(crate) struct ModuleDescriptor {
27} 28}
28 29
29impl ModuleDescriptor { 30impl ModuleDescriptor {
31 /// Lookup `ModuleDescriptor` by `FileId`. Note that this is inherently
32 /// lossy transformation: in general, a single source might correspond to
33 /// several modules.
34 pub fn guess_from_file_id(
35 db: &impl DescriptorDatabase,
36 file_id: FileId,
37 ) -> Cancelable<Option<ModuleDescriptor>> {
38 ModuleDescriptor::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id))
39 }
40
30 /// Lookup `ModuleDescriptor` by position in the source code. Note that this 41 /// Lookup `ModuleDescriptor` by position in the source code. Note that this
31 /// is inherently lossy transformation: in general, a single source might 42 /// is inherently lossy transformation: in general, a single source might
32 /// correspond to several modules. 43 /// correspond to several modules.
@@ -34,14 +45,23 @@ impl ModuleDescriptor {
34 db: &impl DescriptorDatabase, 45 db: &impl DescriptorDatabase,
35 position: FilePosition, 46 position: FilePosition,
36 ) -> Cancelable<Option<ModuleDescriptor>> { 47 ) -> 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); 48 let file = db.file_syntax(position.file_id);
40 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) 49 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
41 { 50 {
42 Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), 51 Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
43 _ => ModuleSource::SourceFile(position.file_id), 52 _ => ModuleSource::SourceFile(position.file_id),
44 }; 53 };
54 ModuleDescriptor::guess_from_source(db, position.file_id, module_source)
55 }
56
57 fn guess_from_source(
58 db: &impl DescriptorDatabase,
59 file_id: FileId,
60 module_source: ModuleSource,
61 ) -> Cancelable<Option<ModuleDescriptor>> {
62 let source_root = db.file_source_root(file_id);
63 let module_tree = db.module_tree(source_root)?;
64
45 let res = match module_tree.any_module_for_source(module_source) { 65 let res = match module_tree.any_module_for_source(module_source) {
46 None => None, 66 None => None,
47 Some(module_id) => Some(ModuleDescriptor { 67 Some(module_id) => Some(ModuleDescriptor {
@@ -64,6 +84,11 @@ impl ModuleDescriptor {
64 Some((file_id, src)) 84 Some((file_id, src))
65 } 85 }
66 86
87 pub fn source(&self) -> ModuleSource {
88 self.module_id.source(&self.tree)
89 }
90
91 /// Parent module. Returns `None` if this is a root module.
67 pub fn parent(&self) -> Option<ModuleDescriptor> { 92 pub fn parent(&self) -> Option<ModuleDescriptor> {
68 let parent_id = self.module_id.parent(&self.tree)?; 93 let parent_id = self.module_id.parent(&self.tree)?;
69 Some(ModuleDescriptor { 94 Some(ModuleDescriptor {
@@ -71,6 +96,14 @@ impl ModuleDescriptor {
71 module_id: parent_id, 96 module_id: parent_id,
72 }) 97 })
73 } 98 }
99
100 /// The root of the tree this module is part of
101 pub fn crate_root(&self) -> ModuleDescriptor {
102 generate(Some(self.clone()), |it| it.parent())
103 .last()
104 .unwrap()
105 }
106
74 /// `name` is `None` for the crate's root module 107 /// `name` is `None` for the crate's root module
75 pub fn name(&self) -> Option<SmolStr> { 108 pub fn name(&self) -> Option<SmolStr> {
76 let link = self.module_id.parent_link(&self.tree)?; 109 let link = self.module_id.parent_link(&self.tree)?;
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index c0bed04bf..49b863756 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -220,6 +220,8 @@ impl AnalysisImpl {
220 let source_root = self.db.file_source_root(file_id); 220 let source_root = self.db.file_source_root(file_id);
221 self.db.module_tree(source_root) 221 self.db.module_tree(source_root)
222 } 222 }
223 /// This return `Vec`: a module may be inclucded from several places.
224 /// We don't handle this case yet though, so the Vec has length at most one.
223 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 225 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
224 let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? { 226 let descr = match ModuleDescriptor::guess_from_position(&*self.db, position)? {
225 None => return Ok(Vec::new()), 227 None => return Ok(Vec::new()),
@@ -238,18 +240,21 @@ impl AnalysisImpl {
238 }; 240 };
239 Ok(vec![(file_id, sym)]) 241 Ok(vec![(file_id, sym)])
240 } 242 }
243 /// Returns `Vec` for the same reason as `parent_module`
241 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 244 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
242 let module_tree = self.module_tree(file_id)?; 245 let descr = match ModuleDescriptor::guess_from_file_id(&*self.db, file_id)? {
243 let crate_graph = self.db.crate_graph(); 246 None => return Ok(Vec::new()),
244 let res = module_tree 247 Some(it) => it,
245 .modules_for_source(ModuleSource::SourceFile(file_id)) 248 };
246 .into_iter() 249 let root = descr.crate_root();
247 .map(|it| it.root(&module_tree)) 250 let file_id = root
248 .filter_map(|it| it.source(&module_tree).as_file()) 251 .source()
249 .filter_map(|it| crate_graph.crate_id_for_crate_root(it)) 252 .as_file()
250 .collect(); 253 .expect("root module always has a file as a source");
251 254
252 Ok(res) 255 let crate_graph = self.db.crate_graph();
256 let crate_id = crate_graph.crate_id_for_crate_root(file_id);
257 Ok(crate_id.into_iter().collect())
253 } 258 }
254 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 259 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
255 self.db.crate_graph().crate_roots[&crate_id] 260 self.db.crate_graph().crate_roots[&crate_id]