aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/module_tree.rs179
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
224fn 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
254fn 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
321fn resolve_submodule( 304fn resolve_submodule(
322 db: &impl HirDatabase, 305 db: &impl HirDatabase,
323 file_id: HirFileId, 306 file_id: HirFileId,