diff options
Diffstat (limited to 'crates/ra_analysis/src/descriptors/module')
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/imp.rs | 4 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 190 |
2 files changed, 139 insertions, 55 deletions
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index ade96ddc0..defe87216 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs | |||
@@ -86,7 +86,7 @@ pub(crate) fn module_scope( | |||
86 | source_root_id: SourceRootId, | 86 | source_root_id: SourceRootId, |
87 | module_id: ModuleId, | 87 | module_id: ModuleId, |
88 | ) -> Cancelable<Arc<ModuleScope>> { | 88 | ) -> Cancelable<Arc<ModuleScope>> { |
89 | let tree = db.module_tree(source_root_id)?; | 89 | let tree = db._module_tree(source_root_id)?; |
90 | let source = module_id.source(&tree).resolve(db); | 90 | let source = module_id.source(&tree).resolve(db); |
91 | let res = match source { | 91 | let res = match source { |
92 | ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()), | 92 | ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()), |
@@ -155,7 +155,7 @@ fn build_subtree( | |||
155 | parent, | 155 | parent, |
156 | children: Vec::new(), | 156 | children: Vec::new(), |
157 | }); | 157 | }); |
158 | for sub in db.submodules(source)?.iter() { | 158 | for sub in db._submodules(source)?.iter() { |
159 | let link = tree.push_link(LinkData { | 159 | let link = tree.push_link(LinkData { |
160 | name: sub.name().clone(), | 160 | name: sub.name().clone(), |
161 | owner: id, | 161 | owner: id, |
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 055a56b54..047454cff 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs | |||
@@ -1,16 +1,137 @@ | |||
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::{ |
9 | algo::generate, | ||
5 | ast::{self, AstNode, NameOwner}, | 10 | ast::{self, AstNode, NameOwner}, |
6 | SmolStr, SyntaxNode, SyntaxNodeRef, | 11 | SmolStr, SyntaxNode, |
7 | }; | 12 | }; |
8 | use relative_path::RelativePathBuf; | 13 | use relative_path::RelativePathBuf; |
9 | 14 | ||
10 | use crate::{db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId}; | 15 | use crate::{ |
16 | db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId, FilePosition, Cancelable, | ||
17 | descriptors::DescriptorDatabase, | ||
18 | input::SourceRootId | ||
19 | }; | ||
11 | 20 | ||
12 | pub(crate) use self::scope::ModuleScope; | 21 | pub(crate) use self::scope::ModuleScope; |
13 | 22 | ||
23 | /// `ModuleDescriptor` is API entry point to get all the information | ||
24 | /// about a particular module. | ||
25 | #[derive(Debug, Clone)] | ||
26 | pub(crate) struct ModuleDescriptor { | ||
27 | tree: Arc<ModuleTree>, | ||
28 | source_root_id: SourceRootId, | ||
29 | module_id: ModuleId, | ||
30 | } | ||
31 | |||
32 | impl ModuleDescriptor { | ||
33 | /// Lookup `ModuleDescriptor` by `FileId`. Note that this is inherently | ||
34 | /// lossy transformation: in general, a single source might correspond to | ||
35 | /// several modules. | ||
36 | pub fn guess_from_file_id( | ||
37 | db: &impl DescriptorDatabase, | ||
38 | file_id: FileId, | ||
39 | ) -> Cancelable<Option<ModuleDescriptor>> { | ||
40 | ModuleDescriptor::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id)) | ||
41 | } | ||
42 | |||
43 | /// Lookup `ModuleDescriptor` by position in the source code. Note that this | ||
44 | /// is inherently lossy transformation: in general, a single source might | ||
45 | /// correspond to several modules. | ||
46 | pub fn guess_from_position( | ||
47 | db: &impl DescriptorDatabase, | ||
48 | position: FilePosition, | ||
49 | ) -> Cancelable<Option<ModuleDescriptor>> { | ||
50 | let file = db.file_syntax(position.file_id); | ||
51 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) | ||
52 | { | ||
53 | Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), | ||
54 | _ => ModuleSource::SourceFile(position.file_id), | ||
55 | }; | ||
56 | ModuleDescriptor::guess_from_source(db, position.file_id, module_source) | ||
57 | } | ||
58 | |||
59 | fn guess_from_source( | ||
60 | db: &impl DescriptorDatabase, | ||
61 | file_id: FileId, | ||
62 | module_source: ModuleSource, | ||
63 | ) -> Cancelable<Option<ModuleDescriptor>> { | ||
64 | let source_root_id = db.file_source_root(file_id); | ||
65 | let module_tree = db._module_tree(source_root_id)?; | ||
66 | |||
67 | let res = match module_tree.any_module_for_source(module_source) { | ||
68 | None => None, | ||
69 | Some(module_id) => Some(ModuleDescriptor { | ||
70 | tree: module_tree, | ||
71 | source_root_id, | ||
72 | module_id, | ||
73 | }), | ||
74 | }; | ||
75 | Ok(res) | ||
76 | } | ||
77 | |||
78 | /// Returns `mod foo;` or `mod foo {}` node whihc declared this module. | ||
79 | /// Returns `None` for the root module | ||
80 | pub fn parent_link_source( | ||
81 | &self, | ||
82 | db: &impl DescriptorDatabase, | ||
83 | ) -> Option<(FileId, ast::ModuleNode)> { | ||
84 | let link = self.module_id.parent_link(&self.tree)?; | ||
85 | let file_id = link.owner(&self.tree).source(&self.tree).file_id(); | ||
86 | let src = link.bind_source(&self.tree, db); | ||
87 | Some((file_id, src)) | ||
88 | } | ||
89 | |||
90 | pub fn source(&self) -> ModuleSource { | ||
91 | self.module_id.source(&self.tree) | ||
92 | } | ||
93 | |||
94 | /// Parent module. Returns `None` if this is a root module. | ||
95 | pub fn parent(&self) -> Option<ModuleDescriptor> { | ||
96 | let parent_id = self.module_id.parent(&self.tree)?; | ||
97 | Some(ModuleDescriptor { | ||
98 | module_id: parent_id, | ||
99 | ..self.clone() | ||
100 | }) | ||
101 | } | ||
102 | |||
103 | /// The root of the tree this module is part of | ||
104 | pub fn crate_root(&self) -> ModuleDescriptor { | ||
105 | generate(Some(self.clone()), |it| it.parent()) | ||
106 | .last() | ||
107 | .unwrap() | ||
108 | } | ||
109 | |||
110 | /// `name` is `None` for the crate's root module | ||
111 | pub fn name(&self) -> Option<SmolStr> { | ||
112 | let link = self.module_id.parent_link(&self.tree)?; | ||
113 | Some(link.name(&self.tree)) | ||
114 | } | ||
115 | |||
116 | /// Finds a child module with the specified name. | ||
117 | pub fn child(&self, name: &str) -> Option<ModuleDescriptor> { | ||
118 | let child_id = self.module_id.child(&self.tree, name)?; | ||
119 | Some(ModuleDescriptor { | ||
120 | module_id: child_id, | ||
121 | ..self.clone() | ||
122 | }) | ||
123 | } | ||
124 | |||
125 | /// Returns a `ModuleScope`: a set of items, visible in this module. | ||
126 | pub fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable<Arc<ModuleScope>> { | ||
127 | db._module_scope(self.source_root_id, self.module_id) | ||
128 | } | ||
129 | |||
130 | pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> { | ||
131 | self.module_id.problems(&self.tree, db) | ||
132 | } | ||
133 | } | ||
134 | |||
14 | /// Phisically, rust source is organized as a set of files, but logically it is | 135 | /// 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 | 136 | /// organized as a tree of modules. Usually, a single file corresponds to a |
16 | /// single module, but it is not nessary the case. | 137 | /// single module, but it is not nessary the case. |
@@ -25,7 +146,7 @@ pub(crate) struct ModuleTree { | |||
25 | } | 146 | } |
26 | 147 | ||
27 | impl ModuleTree { | 148 | impl ModuleTree { |
28 | pub(crate) fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> { | 149 | fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> { |
29 | self.mods | 150 | self.mods |
30 | .iter() | 151 | .iter() |
31 | .enumerate() | 152 | .enumerate() |
@@ -34,7 +155,7 @@ impl ModuleTree { | |||
34 | .collect() | 155 | .collect() |
35 | } | 156 | } |
36 | 157 | ||
37 | pub(crate) fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> { | 158 | fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> { |
38 | self.modules_for_source(source).pop() | 159 | self.modules_for_source(source).pop() |
39 | } | 160 | } |
40 | } | 161 | } |
@@ -58,17 +179,8 @@ enum ModuleSourceNode { | |||
58 | #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] | 179 | #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] |
59 | pub(crate) struct ModuleId(u32); | 180 | pub(crate) struct ModuleId(u32); |
60 | 181 | ||
61 | impl crate::loc2id::NumericId for ModuleId { | ||
62 | fn from_u32(id: u32) -> Self { | ||
63 | ModuleId(id) | ||
64 | } | ||
65 | fn to_u32(self) -> u32 { | ||
66 | self.0 | ||
67 | } | ||
68 | } | ||
69 | |||
70 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | 182 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
71 | pub(crate) struct LinkId(u32); | 183 | struct LinkId(u32); |
72 | 184 | ||
73 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 185 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
74 | pub enum Problem { | 186 | pub enum Problem { |
@@ -82,30 +194,17 @@ pub enum Problem { | |||
82 | } | 194 | } |
83 | 195 | ||
84 | impl ModuleId { | 196 | impl ModuleId { |
85 | pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { | 197 | fn source(self, tree: &ModuleTree) -> ModuleSource { |
86 | tree.module(self).source | 198 | tree.module(self).source |
87 | } | 199 | } |
88 | pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { | 200 | fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { |
89 | tree.module(self).parent | 201 | tree.module(self).parent |
90 | } | 202 | } |
91 | pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> { | 203 | fn parent(self, tree: &ModuleTree) -> Option<ModuleId> { |
92 | let link = self.parent_link(tree)?; | 204 | let link = self.parent_link(tree)?; |
93 | Some(tree.link(link).owner) | 205 | Some(tree.link(link).owner) |
94 | } | 206 | } |
95 | pub(crate) fn root(self, tree: &ModuleTree) -> ModuleId { | 207 | fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> { |
96 | let mut curr = self; | ||
97 | let mut i = 0; | ||
98 | while let Some(next) = curr.parent(tree) { | ||
99 | curr = next; | ||
100 | i += 1; | ||
101 | // simplistic cycle detection | ||
102 | if i > 100 { | ||
103 | return self; | ||
104 | } | ||
105 | } | ||
106 | curr | ||
107 | } | ||
108 | pub(crate) fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> { | ||
109 | let link = tree | 208 | let link = tree |
110 | .module(self) | 209 | .module(self) |
111 | .children | 210 | .children |
@@ -114,11 +213,7 @@ impl ModuleId { | |||
114 | .find(|it| it.name == name)?; | 213 | .find(|it| it.name == name)?; |
115 | Some(*link.points_to.first()?) | 214 | Some(*link.points_to.first()?) |
116 | } | 215 | } |
117 | pub(crate) fn problems( | 216 | fn problems(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> Vec<(SyntaxNode, Problem)> { |
118 | self, | ||
119 | tree: &ModuleTree, | ||
120 | db: &impl SyntaxDatabase, | ||
121 | ) -> Vec<(SyntaxNode, Problem)> { | ||
122 | tree.module(self) | 217 | tree.module(self) |
123 | .children | 218 | .children |
124 | .iter() | 219 | .iter() |
@@ -133,14 +228,13 @@ impl ModuleId { | |||
133 | } | 228 | } |
134 | 229 | ||
135 | impl LinkId { | 230 | impl LinkId { |
136 | pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { | 231 | fn owner(self, tree: &ModuleTree) -> ModuleId { |
137 | tree.link(self).owner | 232 | tree.link(self).owner |
138 | } | 233 | } |
139 | pub(crate) fn bind_source<'a>( | 234 | fn name(self, tree: &ModuleTree) -> SmolStr { |
140 | self, | 235 | tree.link(self).name.clone() |
141 | tree: &ModuleTree, | 236 | } |
142 | db: &impl SyntaxDatabase, | 237 | fn bind_source<'a>(self, tree: &ModuleTree, db: &impl SyntaxDatabase) -> ast::ModuleNode { |
143 | ) -> ast::ModuleNode { | ||
144 | let owner = self.owner(tree); | 238 | let owner = self.owner(tree); |
145 | match owner.source(tree).resolve(db) { | 239 | match owner.source(tree).resolve(db) { |
146 | ModuleSourceNode::SourceFile(root) => { | 240 | ModuleSourceNode::SourceFile(root) => { |
@@ -163,17 +257,7 @@ struct ModuleData { | |||
163 | } | 257 | } |
164 | 258 | ||
165 | impl ModuleSource { | 259 | impl ModuleSource { |
166 | pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource { | 260 | fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { |
167 | for node in node.ancestors() { | ||
168 | if let Some(m) = ast::Module::cast(node) { | ||
169 | if !m.has_semi() { | ||
170 | return ModuleSource::new_inline(file_id, m); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | ModuleSource::SourceFile(file_id) | ||
175 | } | ||
176 | pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { | ||
177 | assert!(!module.has_semi()); | 261 | assert!(!module.has_semi()); |
178 | let ptr = SyntaxPtr::new(file_id, module.syntax()); | 262 | let ptr = SyntaxPtr::new(file_id, module.syntax()); |
179 | ModuleSource::Module(ptr) | 263 | ModuleSource::Module(ptr) |