diff options
Diffstat (limited to 'crates/ra_analysis/src/descriptors/module/mod.rs')
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs new file mode 100644 index 000000000..52da650b3 --- /dev/null +++ b/crates/ra_analysis/src/descriptors/module/mod.rs | |||
@@ -0,0 +1,176 @@ | |||
1 | mod imp; | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use relative_path::RelativePathBuf; | ||
6 | use ra_syntax::{ast::{self, NameOwner, AstNode}, SmolStr, SyntaxNode}; | ||
7 | |||
8 | use crate::{ | ||
9 | FileId, Cancelable, | ||
10 | db::SyntaxDatabase, | ||
11 | }; | ||
12 | |||
13 | salsa::query_group! { | ||
14 | pub(crate) trait ModulesDatabase: SyntaxDatabase { | ||
15 | fn module_tree() -> Cancelable<Arc<ModuleTree>> { | ||
16 | type ModuleTreeQuery; | ||
17 | use fn imp::module_tree; | ||
18 | } | ||
19 | fn submodules(file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> { | ||
20 | type SubmodulesQuery; | ||
21 | use fn imp::submodules; | ||
22 | } | ||
23 | } | ||
24 | } | ||
25 | |||
26 | |||
27 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
28 | pub(crate) struct ModuleTree { | ||
29 | mods: Vec<ModuleData>, | ||
30 | links: Vec<LinkData>, | ||
31 | } | ||
32 | |||
33 | impl ModuleTree { | ||
34 | pub(crate) fn modules_for_file(&self, file_id: FileId) -> Vec<ModuleId> { | ||
35 | self.mods.iter() | ||
36 | .enumerate() | ||
37 | .filter(|(_idx, it)| it.file_id == file_id).map(|(idx, _)| ModuleId(idx as u32)) | ||
38 | .collect() | ||
39 | } | ||
40 | |||
41 | pub(crate) fn any_module_for_file(&self, file_id: FileId) -> Option<ModuleId> { | ||
42 | self.modules_for_file(file_id).pop() | ||
43 | } | ||
44 | } | ||
45 | |||
46 | #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] | ||
47 | pub(crate) struct ModuleId(u32); | ||
48 | |||
49 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
50 | pub(crate) struct LinkId(u32); | ||
51 | |||
52 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | ||
53 | pub enum Problem { | ||
54 | UnresolvedModule { | ||
55 | candidate: RelativePathBuf, | ||
56 | }, | ||
57 | NotDirOwner { | ||
58 | move_to: RelativePathBuf, | ||
59 | candidate: RelativePathBuf, | ||
60 | }, | ||
61 | } | ||
62 | |||
63 | impl ModuleId { | ||
64 | pub(crate) fn file_id(self, tree: &ModuleTree) -> FileId { | ||
65 | tree.module(self).file_id | ||
66 | } | ||
67 | pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { | ||
68 | tree.module(self).parent | ||
69 | } | ||
70 | pub(crate) fn parent(self, tree: &ModuleTree) -> Option<ModuleId> { | ||
71 | let link = self.parent_link(tree)?; | ||
72 | Some(tree.link(link).owner) | ||
73 | } | ||
74 | pub(crate) fn root(self, tree: &ModuleTree) -> ModuleId { | ||
75 | let mut curr = self; | ||
76 | let mut i = 0; | ||
77 | while let Some(next) = curr.parent(tree) { | ||
78 | curr = next; | ||
79 | i += 1; | ||
80 | if i > 100 { | ||
81 | return self; | ||
82 | } | ||
83 | } | ||
84 | curr | ||
85 | } | ||
86 | pub(crate) fn child(self, tree: &ModuleTree, name: &str) -> Option<ModuleId> { | ||
87 | let link = tree.module(self) | ||
88 | .children | ||
89 | .iter() | ||
90 | .map(|&it| tree.link(it)) | ||
91 | .find(|it| it.name == name)?; | ||
92 | Some(*link.points_to.first()?) | ||
93 | } | ||
94 | pub(crate) fn problems( | ||
95 | self, | ||
96 | tree: &ModuleTree, | ||
97 | root: ast::Root, | ||
98 | ) -> Vec<(SyntaxNode, Problem)> { | ||
99 | tree.module(self) | ||
100 | .children | ||
101 | .iter() | ||
102 | .filter_map(|&it| { | ||
103 | let p = tree.link(it).problem.clone()?; | ||
104 | let s = it.bind_source(tree, root); | ||
105 | let s = s.name().unwrap().syntax().owned(); | ||
106 | Some((s, p)) | ||
107 | }) | ||
108 | .collect() | ||
109 | } | ||
110 | } | ||
111 | |||
112 | impl LinkId { | ||
113 | pub(crate) fn name(self, tree: &ModuleTree) -> SmolStr { | ||
114 | tree.link(self).name.clone() | ||
115 | } | ||
116 | pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { | ||
117 | tree.link(self).owner | ||
118 | } | ||
119 | fn points_to(self, tree: &ModuleTree) -> &[ModuleId] { | ||
120 | &tree.link(self).points_to | ||
121 | } | ||
122 | pub(crate) fn bind_source<'a>( | ||
123 | self, | ||
124 | tree: &ModuleTree, | ||
125 | root: ast::Root<'a>, | ||
126 | ) -> ast::Module<'a> { | ||
127 | imp::modules(root) | ||
128 | .find(|(name, _)| name == &tree.link(self).name) | ||
129 | .unwrap() | ||
130 | .1 | ||
131 | } | ||
132 | } | ||
133 | |||
134 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
135 | struct ModuleData { | ||
136 | file_id: FileId, | ||
137 | parent: Option<LinkId>, | ||
138 | children: Vec<LinkId>, | ||
139 | } | ||
140 | |||
141 | #[derive(Hash, Debug, PartialEq, Eq)] | ||
142 | struct LinkData { | ||
143 | owner: ModuleId, | ||
144 | name: SmolStr, | ||
145 | points_to: Vec<ModuleId>, | ||
146 | problem: Option<Problem>, | ||
147 | } | ||
148 | |||
149 | |||
150 | impl ModuleTree { | ||
151 | fn module(&self, id: ModuleId) -> &ModuleData { | ||
152 | &self.mods[id.0 as usize] | ||
153 | } | ||
154 | fn module_mut(&mut self, id: ModuleId) -> &mut ModuleData { | ||
155 | &mut self.mods[id.0 as usize] | ||
156 | } | ||
157 | fn link(&self, id: LinkId) -> &LinkData { | ||
158 | &self.links[id.0 as usize] | ||
159 | } | ||
160 | fn link_mut(&mut self, id: LinkId) -> &mut LinkData { | ||
161 | &mut self.links[id.0 as usize] | ||
162 | } | ||
163 | |||
164 | fn push_mod(&mut self, data: ModuleData) -> ModuleId { | ||
165 | let id = ModuleId(self.mods.len() as u32); | ||
166 | self.mods.push(data); | ||
167 | id | ||
168 | } | ||
169 | fn push_link(&mut self, data: LinkData) -> LinkId { | ||
170 | let id = LinkId(self.links.len() as u32); | ||
171 | self.mods[data.owner.0 as usize].children.push(id); | ||
172 | self.links.push(data); | ||
173 | id | ||
174 | } | ||
175 | } | ||
176 | |||