diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-23 18:57:10 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-23 18:57:10 +0100 |
commit | ffbb60436305c9ef8c8944188e0373122051c53a (patch) | |
tree | 3240bdb3aa75eb278f13b7294f01591181189135 /crates/ra_analysis/src/descriptors.rs | |
parent | e49c628c0d7ab30a09e8d3ba3d7ac93ab967ff6d (diff) | |
parent | dc477db757247d5184250bffe9dd0c38dd867778 (diff) |
Merge #157
157: Introduce ModuleId r=matklad a=matklad
Previously, module was synonym with a file, and so a module could have
had several parents. This commit introduces a separate module concept,
such that each module has only one parent, but a single file can
correspond to different modules.
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_analysis/src/descriptors.rs')
-rw-r--r-- | crates/ra_analysis/src/descriptors.rs | 282 |
1 files changed, 0 insertions, 282 deletions
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs deleted file mode 100644 index 92da26493..000000000 --- a/crates/ra_analysis/src/descriptors.rs +++ /dev/null | |||
@@ -1,282 +0,0 @@ | |||
1 | use std::collections::BTreeMap; | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | ast::{self, AstNode, NameOwner}, | ||
5 | text_utils::is_subrange, | ||
6 | SmolStr, | ||
7 | }; | ||
8 | use relative_path::RelativePathBuf; | ||
9 | |||
10 | use crate::{imp::FileResolverImp, FileId}; | ||
11 | |||
12 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
13 | pub struct ModuleDescriptor { | ||
14 | pub submodules: Vec<Submodule>, | ||
15 | } | ||
16 | |||
17 | impl ModuleDescriptor { | ||
18 | pub fn new(root: ast::Root) -> ModuleDescriptor { | ||
19 | let submodules = modules(root).map(|(name, _)| Submodule { name }).collect(); | ||
20 | |||
21 | ModuleDescriptor { submodules } | ||
22 | } | ||
23 | } | ||
24 | |||
25 | fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast::Module<'_>)> { | ||
26 | root.modules().filter_map(|module| { | ||
27 | let name = module.name()?.text(); | ||
28 | if !module.has_semi() { | ||
29 | return None; | ||
30 | } | ||
31 | Some((name, module)) | ||
32 | }) | ||
33 | } | ||
34 | |||
35 | #[derive(Clone, Hash, PartialEq, Eq, Debug)] | ||
36 | pub struct Submodule { | ||
37 | pub name: SmolStr, | ||
38 | } | ||
39 | |||
40 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
41 | pub(crate) struct ModuleTreeDescriptor { | ||
42 | nodes: Vec<NodeData>, | ||
43 | links: Vec<LinkData>, | ||
44 | file_id2node: BTreeMap<FileId, Node>, | ||
45 | } | ||
46 | |||
47 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
48 | struct Node(usize); | ||
49 | #[derive(Hash, Debug, PartialEq, Eq)] | ||
50 | struct NodeData { | ||
51 | file_id: FileId, | ||
52 | links: Vec<Link>, | ||
53 | parents: Vec<Link>, | ||
54 | } | ||
55 | |||
56 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
57 | pub(crate) struct Link(usize); | ||
58 | #[derive(Hash, Debug, PartialEq, Eq)] | ||
59 | struct LinkData { | ||
60 | owner: Node, | ||
61 | name: SmolStr, | ||
62 | points_to: Vec<Node>, | ||
63 | problem: Option<Problem>, | ||
64 | } | ||
65 | |||
66 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | ||
67 | pub enum Problem { | ||
68 | UnresolvedModule { | ||
69 | candidate: RelativePathBuf, | ||
70 | }, | ||
71 | NotDirOwner { | ||
72 | move_to: RelativePathBuf, | ||
73 | candidate: RelativePathBuf, | ||
74 | }, | ||
75 | } | ||
76 | |||
77 | impl ModuleTreeDescriptor { | ||
78 | pub(crate) fn new<'a>( | ||
79 | files: impl Iterator<Item = (FileId, &'a ModuleDescriptor)> + Clone, | ||
80 | file_resolver: &FileResolverImp, | ||
81 | ) -> ModuleTreeDescriptor { | ||
82 | let mut file_id2node = BTreeMap::new(); | ||
83 | let mut nodes: Vec<NodeData> = files | ||
84 | .clone() | ||
85 | .enumerate() | ||
86 | .map(|(idx, (file_id, _))| { | ||
87 | file_id2node.insert(file_id, Node(idx)); | ||
88 | NodeData { | ||
89 | file_id, | ||
90 | links: Vec::new(), | ||
91 | parents: Vec::new(), | ||
92 | } | ||
93 | }) | ||
94 | .collect(); | ||
95 | let mut links = Vec::new(); | ||
96 | |||
97 | for (idx, (file_id, descr)) in files.enumerate() { | ||
98 | let owner = Node(idx); | ||
99 | for sub in descr.submodules.iter() { | ||
100 | let link = Link(links.len()); | ||
101 | nodes[owner.0].links.push(link); | ||
102 | let (points_to, problem) = resolve_submodule(file_id, &sub.name, file_resolver); | ||
103 | let points_to = points_to | ||
104 | .into_iter() | ||
105 | .map(|file_id| { | ||
106 | let node = file_id2node[&file_id]; | ||
107 | nodes[node.0].parents.push(link); | ||
108 | node | ||
109 | }) | ||
110 | .collect(); | ||
111 | |||
112 | links.push(LinkData { | ||
113 | owner, | ||
114 | name: sub.name.clone(), | ||
115 | points_to, | ||
116 | problem, | ||
117 | }) | ||
118 | } | ||
119 | } | ||
120 | |||
121 | ModuleTreeDescriptor { | ||
122 | nodes, | ||
123 | links, | ||
124 | file_id2node, | ||
125 | } | ||
126 | } | ||
127 | |||
128 | pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> { | ||
129 | let node = self.file_id2node[&file_id]; | ||
130 | self.node(node).parents.clone() | ||
131 | } | ||
132 | pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> { | ||
133 | let node = self.file_id2node[&file_id]; | ||
134 | self.node(node) | ||
135 | .links | ||
136 | .iter() | ||
137 | .filter(|it| it.name(self) == name) | ||
138 | .flat_map(|link| { | ||
139 | link.points_to(self) | ||
140 | .iter() | ||
141 | .map(|&node| self.node(node).file_id) | ||
142 | }) | ||
143 | .collect() | ||
144 | } | ||
145 | pub(crate) fn problems<'a, 'b>( | ||
146 | &'b self, | ||
147 | file_id: FileId, | ||
148 | root: ast::Root<'a>, | ||
149 | ) -> Vec<(ast::Name<'a>, &'b Problem)> { | ||
150 | let node = self.file_id2node[&file_id]; | ||
151 | self.node(node) | ||
152 | .links | ||
153 | .iter() | ||
154 | .filter_map(|&link| { | ||
155 | let problem = self.link(link).problem.as_ref()?; | ||
156 | let name = link.bind_source(self, root).name()?; | ||
157 | Some((name, problem)) | ||
158 | }) | ||
159 | .collect() | ||
160 | } | ||
161 | |||
162 | fn node(&self, node: Node) -> &NodeData { | ||
163 | &self.nodes[node.0] | ||
164 | } | ||
165 | fn link(&self, link: Link) -> &LinkData { | ||
166 | &self.links[link.0] | ||
167 | } | ||
168 | } | ||
169 | |||
170 | impl Link { | ||
171 | pub(crate) fn name(self, tree: &ModuleTreeDescriptor) -> SmolStr { | ||
172 | tree.link(self).name.clone() | ||
173 | } | ||
174 | pub(crate) fn owner(self, tree: &ModuleTreeDescriptor) -> FileId { | ||
175 | let owner = tree.link(self).owner; | ||
176 | tree.node(owner).file_id | ||
177 | } | ||
178 | fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] { | ||
179 | &tree.link(self).points_to | ||
180 | } | ||
181 | pub(crate) fn bind_source<'a>( | ||
182 | self, | ||
183 | tree: &ModuleTreeDescriptor, | ||
184 | root: ast::Root<'a>, | ||
185 | ) -> ast::Module<'a> { | ||
186 | modules(root) | ||
187 | .find(|(name, _)| name == &tree.link(self).name) | ||
188 | .unwrap() | ||
189 | .1 | ||
190 | } | ||
191 | } | ||
192 | |||
193 | fn resolve_submodule( | ||
194 | file_id: FileId, | ||
195 | name: &SmolStr, | ||
196 | file_resolver: &FileResolverImp, | ||
197 | ) -> (Vec<FileId>, Option<Problem>) { | ||
198 | let mod_name = file_resolver.file_stem(file_id); | ||
199 | let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; | ||
200 | |||
201 | let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); | ||
202 | let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); | ||
203 | let points_to: Vec<FileId>; | ||
204 | let problem: Option<Problem>; | ||
205 | if is_dir_owner { | ||
206 | points_to = [&file_mod, &dir_mod] | ||
207 | .iter() | ||
208 | .filter_map(|path| file_resolver.resolve(file_id, path)) | ||
209 | .collect(); | ||
210 | problem = if points_to.is_empty() { | ||
211 | Some(Problem::UnresolvedModule { | ||
212 | candidate: file_mod, | ||
213 | }) | ||
214 | } else { | ||
215 | None | ||
216 | } | ||
217 | } else { | ||
218 | points_to = Vec::new(); | ||
219 | problem = Some(Problem::NotDirOwner { | ||
220 | move_to: RelativePathBuf::from(format!("../{}/mod.rs", mod_name)), | ||
221 | candidate: file_mod, | ||
222 | }); | ||
223 | } | ||
224 | (points_to, problem) | ||
225 | } | ||
226 | |||
227 | #[derive(Debug, Clone)] | ||
228 | pub struct FnDescriptor { | ||
229 | pub name: String, | ||
230 | pub label: String, | ||
231 | pub ret_type: Option<String>, | ||
232 | pub params: Vec<String>, | ||
233 | } | ||
234 | |||
235 | impl FnDescriptor { | ||
236 | pub fn new(node: ast::FnDef) -> Option<Self> { | ||
237 | let name = node.name()?.text().to_string(); | ||
238 | |||
239 | // Strip the body out for the label. | ||
240 | let label: String = if let Some(body) = node.body() { | ||
241 | let body_range = body.syntax().range(); | ||
242 | let label: String = node | ||
243 | .syntax() | ||
244 | .children() | ||
245 | .filter(|child| !is_subrange(body_range, child.range())) | ||
246 | .map(|node| node.text().to_string()) | ||
247 | .collect(); | ||
248 | label | ||
249 | } else { | ||
250 | node.syntax().text().to_string() | ||
251 | }; | ||
252 | |||
253 | let params = FnDescriptor::param_list(node); | ||
254 | let ret_type = node.ret_type().map(|r| r.syntax().text().to_string()); | ||
255 | |||
256 | Some(FnDescriptor { | ||
257 | name, | ||
258 | ret_type, | ||
259 | params, | ||
260 | label, | ||
261 | }) | ||
262 | } | ||
263 | |||
264 | fn param_list(node: ast::FnDef) -> Vec<String> { | ||
265 | let mut res = vec![]; | ||
266 | if let Some(param_list) = node.param_list() { | ||
267 | if let Some(self_param) = param_list.self_param() { | ||
268 | res.push(self_param.syntax().text().to_string()) | ||
269 | } | ||
270 | |||
271 | // Maybe use param.pat here? See if we can just extract the name? | ||
272 | //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); | ||
273 | res.extend( | ||
274 | param_list | ||
275 | .params() | ||
276 | .filter_map(|p| p.pat()) | ||
277 | .map(|pat| pat.syntax().text().to_string()), | ||
278 | ); | ||
279 | } | ||
280 | res | ||
281 | } | ||
282 | } | ||