diff options
-rw-r--r-- | crates/ra_hir/src/module_tree.rs | 179 |
1 files changed, 81 insertions, 98 deletions
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs index dd3aa6d73..b201bf69b 100644 --- a/crates/ra_hir/src/module_tree.rs +++ b/crates/ra_hir/src/module_tree.rs | |||
@@ -131,7 +131,8 @@ impl ModuleTree { | |||
131 | source_root: SourceRootId, | 131 | source_root: SourceRootId, |
132 | ) -> Arc<ModuleTree> { | 132 | ) -> Arc<ModuleTree> { |
133 | db.check_canceled(); | 133 | db.check_canceled(); |
134 | let res = create_module_tree(db, source_root); | 134 | let mut res = ModuleTree::default(); |
135 | res.init(db, source_root); | ||
135 | Arc::new(res) | 136 | Arc::new(res) |
136 | } | 137 | } |
137 | 138 | ||
@@ -144,6 +145,85 @@ impl ModuleTree { | |||
144 | Some(res) | 145 | Some(res) |
145 | } | 146 | } |
146 | 147 | ||
148 | fn init(&mut self, db: &impl HirDatabase, source_root: SourceRootId) { | ||
149 | let mut roots = FxHashMap::default(); | ||
150 | let mut visited = FxHashSet::default(); | ||
151 | |||
152 | let source_root = db.source_root(source_root); | ||
153 | for &file_id in source_root.files.values() { | ||
154 | let source = SourceItemId { | ||
155 | file_id: file_id.into(), | ||
156 | item_id: None, | ||
157 | }; | ||
158 | if visited.contains(&source) { | ||
159 | continue; // TODO: use explicit crate_roots here | ||
160 | } | ||
161 | assert!(!roots.contains_key(&file_id)); | ||
162 | let module_id = | ||
163 | self.init_subtree(db, &source_root, &mut visited, &mut roots, None, source); | ||
164 | roots.insert(file_id, module_id); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | fn init_subtree( | ||
169 | &mut self, | ||
170 | db: &impl HirDatabase, | ||
171 | source_root: &SourceRoot, | ||
172 | visited: &mut FxHashSet<SourceItemId>, | ||
173 | roots: &mut FxHashMap<FileId, ModuleId>, | ||
174 | parent: Option<LinkId>, | ||
175 | source: SourceItemId, | ||
176 | ) -> ModuleId { | ||
177 | visited.insert(source); | ||
178 | let id = self.alloc_mod(ModuleData { | ||
179 | source, | ||
180 | parent, | ||
181 | children: Vec::new(), | ||
182 | }); | ||
183 | for sub in db.submodules(source).iter() { | ||
184 | let link = self.alloc_link(LinkData { | ||
185 | source: sub.source, | ||
186 | name: sub.name.clone(), | ||
187 | owner: id, | ||
188 | points_to: Vec::new(), | ||
189 | problem: None, | ||
190 | }); | ||
191 | |||
192 | let (points_to, problem) = if sub.is_declaration { | ||
193 | let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name); | ||
194 | let points_to = points_to | ||
195 | .into_iter() | ||
196 | .map(|file_id| match roots.remove(&file_id) { | ||
197 | Some(module_id) => { | ||
198 | self.mods[module_id].parent = Some(link); | ||
199 | module_id | ||
200 | } | ||
201 | None => self.init_subtree( | ||
202 | db, | ||
203 | source_root, | ||
204 | visited, | ||
205 | roots, | ||
206 | Some(link), | ||
207 | SourceItemId { | ||
208 | file_id: file_id.into(), | ||
209 | item_id: None, | ||
210 | }, | ||
211 | ), | ||
212 | }) | ||
213 | .collect::<Vec<_>>(); | ||
214 | (points_to, problem) | ||
215 | } else { | ||
216 | let points_to = | ||
217 | self.init_subtree(db, source_root, visited, roots, Some(link), sub.source); | ||
218 | (vec![points_to], None) | ||
219 | }; | ||
220 | |||
221 | self.links[link].points_to = points_to; | ||
222 | self.links[link].problem = problem; | ||
223 | } | ||
224 | id | ||
225 | } | ||
226 | |||
147 | fn alloc_mod(&mut self, data: ModuleData) -> ModuleId { | 227 | fn alloc_mod(&mut self, data: ModuleData) -> ModuleId { |
148 | self.mods.alloc(data) | 228 | self.mods.alloc(data) |
149 | } | 229 | } |
@@ -221,103 +301,6 @@ impl LinkId { | |||
221 | } | 301 | } |
222 | } | 302 | } |
223 | 303 | ||
224 | fn create_module_tree<'a>(db: &impl HirDatabase, source_root: SourceRootId) -> ModuleTree { | ||
225 | let mut tree = ModuleTree::default(); | ||
226 | |||
227 | let mut roots = FxHashMap::default(); | ||
228 | let mut visited = FxHashSet::default(); | ||
229 | |||
230 | let source_root = db.source_root(source_root); | ||
231 | for &file_id in source_root.files.values() { | ||
232 | let source = SourceItemId { | ||
233 | file_id: file_id.into(), | ||
234 | item_id: None, | ||
235 | }; | ||
236 | if visited.contains(&source) { | ||
237 | continue; // TODO: use explicit crate_roots here | ||
238 | } | ||
239 | assert!(!roots.contains_key(&file_id)); | ||
240 | let module_id = build_subtree( | ||
241 | db, | ||
242 | &source_root, | ||
243 | &mut tree, | ||
244 | &mut visited, | ||
245 | &mut roots, | ||
246 | None, | ||
247 | source, | ||
248 | ); | ||
249 | roots.insert(file_id, module_id); | ||
250 | } | ||
251 | tree | ||
252 | } | ||
253 | |||
254 | fn build_subtree( | ||
255 | db: &impl HirDatabase, | ||
256 | source_root: &SourceRoot, | ||
257 | tree: &mut ModuleTree, | ||
258 | visited: &mut FxHashSet<SourceItemId>, | ||
259 | roots: &mut FxHashMap<FileId, ModuleId>, | ||
260 | parent: Option<LinkId>, | ||
261 | source: SourceItemId, | ||
262 | ) -> ModuleId { | ||
263 | visited.insert(source); | ||
264 | let id = tree.alloc_mod(ModuleData { | ||
265 | source, | ||
266 | parent, | ||
267 | children: Vec::new(), | ||
268 | }); | ||
269 | for sub in db.submodules(source).iter() { | ||
270 | let link = tree.alloc_link(LinkData { | ||
271 | source: sub.source, | ||
272 | name: sub.name.clone(), | ||
273 | owner: id, | ||
274 | points_to: Vec::new(), | ||
275 | problem: None, | ||
276 | }); | ||
277 | |||
278 | let (points_to, problem) = if sub.is_declaration { | ||
279 | let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name); | ||
280 | let points_to = points_to | ||
281 | .into_iter() | ||
282 | .map(|file_id| match roots.remove(&file_id) { | ||
283 | Some(module_id) => { | ||
284 | tree.mods[module_id].parent = Some(link); | ||
285 | module_id | ||
286 | } | ||
287 | None => build_subtree( | ||
288 | db, | ||
289 | source_root, | ||
290 | tree, | ||
291 | visited, | ||
292 | roots, | ||
293 | Some(link), | ||
294 | SourceItemId { | ||
295 | file_id: file_id.into(), | ||
296 | item_id: None, | ||
297 | }, | ||
298 | ), | ||
299 | }) | ||
300 | .collect::<Vec<_>>(); | ||
301 | (points_to, problem) | ||
302 | } else { | ||
303 | let points_to = build_subtree( | ||
304 | db, | ||
305 | source_root, | ||
306 | tree, | ||
307 | visited, | ||
308 | roots, | ||
309 | Some(link), | ||
310 | sub.source, | ||
311 | ); | ||
312 | (vec![points_to], None) | ||
313 | }; | ||
314 | |||
315 | tree.links[link].points_to = points_to; | ||
316 | tree.links[link].problem = problem; | ||
317 | } | ||
318 | id | ||
319 | } | ||
320 | |||
321 | fn resolve_submodule( | 304 | fn resolve_submodule( |
322 | db: &impl HirDatabase, | 305 | db: &impl HirDatabase, |
323 | file_id: HirFileId, | 306 | file_id: HirFileId, |