diff options
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 37 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 25 |
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; | |||
6 | use ra_editor::find_node_at_offset; | 6 | use ra_editor::find_node_at_offset; |
7 | 7 | ||
8 | use ra_syntax::{ | 8 | use 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 | ||
29 | impl ModuleDescriptor { | 30 | impl 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] |