aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/descriptors.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-09-16 10:54:24 +0100
committerAleksey Kladov <[email protected]>2018-09-16 11:07:39 +0100
commitb5021411a84822cb3f1e3aeffad9550dd15bdeb6 (patch)
tree9dca564f8e51b298dced01c4ce669c756dce3142 /crates/ra_analysis/src/descriptors.rs
parentba0bfeee12e19da40b5eabc8d0408639af10e96f (diff)
rename all things
Diffstat (limited to 'crates/ra_analysis/src/descriptors.rs')
-rw-r--r--crates/ra_analysis/src/descriptors.rs220
1 files changed, 220 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs
new file mode 100644
index 000000000..0731b5572
--- /dev/null
+++ b/crates/ra_analysis/src/descriptors.rs
@@ -0,0 +1,220 @@
1use std::{
2 collections::BTreeMap,
3};
4use relative_path::RelativePathBuf;
5use ra_syntax::{
6 SmolStr,
7 ast::{self, NameOwner},
8};
9use {
10 FileId,
11 imp::FileResolverImp,
12};
13
14#[derive(Debug, Hash)]
15pub struct ModuleDescriptor {
16 pub submodules: Vec<Submodule>
17}
18
19impl ModuleDescriptor {
20 pub fn new(root: ast::Root) -> ModuleDescriptor {
21 let submodules = modules(root)
22 .map(|(name, _)| Submodule { name })
23 .collect();
24
25 ModuleDescriptor { submodules } }
26}
27
28fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item=(SmolStr, ast::Module<'a>)> {
29 root
30 .modules()
31 .filter_map(|module| {
32 let name = module.name()?.text();
33 if !module.has_semi() {
34 return None;
35 }
36 Some((name, module))
37 })
38}
39
40#[derive(Clone, Hash, PartialEq, Eq, Debug)]
41pub struct Submodule {
42 pub name: SmolStr,
43}
44
45#[derive(Hash, Debug)]
46pub(crate) struct ModuleTreeDescriptor {
47 nodes: Vec<NodeData>,
48 links: Vec<LinkData>,
49 file_id2node: BTreeMap<FileId, Node>,
50}
51
52#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
53struct Node(usize);
54#[derive(Hash, Debug)]
55struct NodeData {
56 file_id: FileId,
57 links: Vec<Link>,
58 parents: Vec<Link>
59}
60
61#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
62pub(crate) struct Link(usize);
63#[derive(Hash, Debug)]
64struct LinkData {
65 owner: Node,
66 name: SmolStr,
67 points_to: Vec<Node>,
68 problem: Option<Problem>,
69}
70
71
72#[derive(Clone, Debug, Hash)]
73pub enum Problem {
74 UnresolvedModule {
75 candidate: RelativePathBuf,
76 },
77 NotDirOwner {
78 move_to: RelativePathBuf,
79 candidate: RelativePathBuf,
80 }
81}
82
83impl ModuleTreeDescriptor {
84 pub(crate) fn new<'a>(
85 files: impl Iterator<Item=(FileId, &'a ModuleDescriptor)> + Clone,
86 file_resolver: &FileResolverImp,
87 ) -> ModuleTreeDescriptor {
88 let mut file_id2node = BTreeMap::new();
89 let mut nodes: Vec<NodeData> = files.clone().enumerate()
90 .map(|(idx, (file_id, _))| {
91 file_id2node.insert(file_id, Node(idx));
92 NodeData {
93 file_id,
94 links: Vec::new(),
95 parents: Vec::new(),
96 }
97 })
98 .collect();
99 let mut links = Vec::new();
100
101 for (idx, (file_id, descr)) in files.enumerate() {
102 let owner = Node(idx);
103 for sub in descr.submodules.iter() {
104 let link = Link(links.len());
105 nodes[owner.0].links.push(link);
106 let (points_to, problem) = resolve_submodule(file_id, &sub.name, file_resolver);
107 let points_to = points_to
108 .into_iter()
109 .map(|file_id| {
110 let node = file_id2node[&file_id];
111 nodes[node.0].parents.push(link);
112 node
113 })
114 .collect();
115
116 links.push(LinkData {
117 owner,
118 name: sub.name.clone(),
119 points_to,
120 problem,
121 })
122
123 }
124 }
125
126 ModuleTreeDescriptor {
127 nodes, links, file_id2node
128 }
129 }
130
131 pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> {
132 let node = self.file_id2node[&file_id];
133 self.node(node)
134 .parents
135 .clone()
136 }
137 pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> {
138 let node = self.file_id2node[&file_id];
139 self.node(node)
140 .links
141 .iter()
142 .filter(|it| it.name(self) == name)
143 .flat_map(|link| link.points_to(self).iter().map(|&node| self.node(node).file_id))
144 .collect()
145 }
146 pub(crate) fn problems<'a, 'b>(&'b self, file_id: FileId, root: ast::Root<'a>) -> Vec<(ast::Name<'a>, &'b Problem)> {
147 let node = self.file_id2node[&file_id];
148 self.node(node)
149 .links
150 .iter()
151 .filter_map(|&link| {
152 let problem = self.link(link).problem.as_ref()?;
153 let name = link.bind_source(self, root).name()?;
154 Some((name, problem))
155 })
156 .collect()
157 }
158
159 fn node(&self, node: Node) -> &NodeData {
160 &self.nodes[node.0]
161 }
162 fn link(&self, link: Link) -> &LinkData {
163 &self.links[link.0]
164 }
165}
166
167impl Link {
168 pub(crate) fn name(self, tree: &ModuleTreeDescriptor) -> SmolStr {
169 tree.link(self).name.clone()
170 }
171 pub(crate) fn owner(self, tree: &ModuleTreeDescriptor) -> FileId {
172 let owner = tree.link(self).owner;
173 tree.node(owner).file_id
174 }
175 fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] {
176 &tree.link(self).points_to
177 }
178 pub(crate) fn bind_source<'a>(self, tree: &ModuleTreeDescriptor, root: ast::Root<'a>) -> ast::Module<'a> {
179 modules(root)
180 .filter(|(name, _)| name == &tree.link(self).name)
181 .next()
182 .unwrap()
183 .1
184 }
185}
186
187
188fn resolve_submodule(
189 file_id: FileId,
190 name: &SmolStr,
191 file_resolver: &FileResolverImp
192) -> (Vec<FileId>, Option<Problem>) {
193 let mod_name = file_resolver.file_stem(file_id);
194 let is_dir_owner =
195 mod_name == "mod" || mod_name == "lib" || mod_name == "main";
196
197 let file_mod = RelativePathBuf::from(format!("../{}.rs", name));
198 let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name));
199 let points_to: Vec<FileId>;
200 let problem: Option<Problem>;
201 if is_dir_owner {
202 points_to = [&file_mod, &dir_mod].iter()
203 .filter_map(|path| file_resolver.resolve(file_id, path))
204 .collect();
205 problem = if points_to.is_empty() {
206 Some(Problem::UnresolvedModule {
207 candidate: file_mod,
208 })
209 } else {
210 None
211 }
212 } else {
213 points_to = Vec::new();
214 problem = Some(Problem::NotDirOwner {
215 move_to: RelativePathBuf::from(format!("../{}/mod.rs", mod_name)),
216 candidate: file_mod,
217 });
218 }
219 (points_to, problem)
220}