aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/descriptors.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-10-23 18:57:10 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-10-23 18:57:10 +0100
commitffbb60436305c9ef8c8944188e0373122051c53a (patch)
tree3240bdb3aa75eb278f13b7294f01591181189135 /crates/ra_analysis/src/descriptors.rs
parente49c628c0d7ab30a09e8d3ba3d7ac93ab967ff6d (diff)
parentdc477db757247d5184250bffe9dd0c38dd867778 (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.rs282
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 @@
1use std::collections::BTreeMap;
2
3use ra_syntax::{
4 ast::{self, AstNode, NameOwner},
5 text_utils::is_subrange,
6 SmolStr,
7};
8use relative_path::RelativePathBuf;
9
10use crate::{imp::FileResolverImp, FileId};
11
12#[derive(Debug, PartialEq, Eq, Hash)]
13pub struct ModuleDescriptor {
14 pub submodules: Vec<Submodule>,
15}
16
17impl 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
25fn 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)]
36pub struct Submodule {
37 pub name: SmolStr,
38}
39
40#[derive(Debug, PartialEq, Eq, Hash)]
41pub(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)]
48struct Node(usize);
49#[derive(Hash, Debug, PartialEq, Eq)]
50struct NodeData {
51 file_id: FileId,
52 links: Vec<Link>,
53 parents: Vec<Link>,
54}
55
56#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
57pub(crate) struct Link(usize);
58#[derive(Hash, Debug, PartialEq, Eq)]
59struct 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)]
67pub enum Problem {
68 UnresolvedModule {
69 candidate: RelativePathBuf,
70 },
71 NotDirOwner {
72 move_to: RelativePathBuf,
73 candidate: RelativePathBuf,
74 },
75}
76
77impl 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
170impl 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
193fn 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)]
228pub struct FnDescriptor {
229 pub name: String,
230 pub label: String,
231 pub ret_type: Option<String>,
232 pub params: Vec<String>,
233}
234
235impl 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}