aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/module_tree.rs246
-rw-r--r--crates/ra_hir/src/nameres/lower.rs13
2 files changed, 117 insertions, 142 deletions
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index 47c14af35..b201bf69b 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -62,14 +62,26 @@ impl Submodule {
62 file_items: &SourceFileItems, 62 file_items: &SourceFileItems,
63 root: &impl ast::ModuleItemOwner, 63 root: &impl ast::ModuleItemOwner,
64 ) -> Vec<Submodule> { 64 ) -> Vec<Submodule> {
65 modules(root) 65 root.items()
66 .map(|(name, m)| Submodule { 66 .filter_map(|item| match item.kind() {
67 name, 67 ast::ModuleItemKind::Module(m) => Some(m),
68 is_declaration: m.has_semi(), 68 _ => None,
69 source: SourceItemId { 69 })
70 file_id, 70 .filter_map(|module| {
71 item_id: Some(file_items.id_of(file_id, m.syntax())), 71 let name = module.name()?.as_name();
72 }, 72 if !module.has_semi() && module.item_list().is_none() {
73 tested_by!(name_res_works_for_broken_modules);
74 return None;
75 }
76 let sub = Submodule {
77 name,
78 is_declaration: module.has_semi(),
79 source: SourceItemId {
80 file_id,
81 item_id: Some(file_items.id_of(file_id, module.syntax())),
82 },
83 };
84 Some(sub)
73 }) 85 })
74 .collect() 86 .collect()
75 } 87 }
@@ -119,7 +131,8 @@ impl ModuleTree {
119 source_root: SourceRootId, 131 source_root: SourceRootId,
120 ) -> Arc<ModuleTree> { 132 ) -> Arc<ModuleTree> {
121 db.check_canceled(); 133 db.check_canceled();
122 let res = create_module_tree(db, source_root); 134 let mut res = ModuleTree::default();
135 res.init(db, source_root);
123 Arc::new(res) 136 Arc::new(res)
124 } 137 }
125 138
@@ -131,6 +144,96 @@ impl ModuleTree {
131 let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?; 144 let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?;
132 Some(res) 145 Some(res)
133 } 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
227 fn alloc_mod(&mut self, data: ModuleData) -> ModuleId {
228 self.mods.alloc(data)
229 }
230
231 fn alloc_link(&mut self, data: LinkData) -> LinkId {
232 let owner = data.owner;
233 let id = self.links.alloc(data);
234 self.mods[owner].children.push(id);
235 id
236 }
134} 237}
135 238
136impl ModuleId { 239impl ModuleId {
@@ -198,131 +301,6 @@ impl LinkId {
198 } 301 }
199} 302}
200 303
201impl ModuleTree {
202 fn push_mod(&mut self, data: ModuleData) -> ModuleId {
203 self.mods.alloc(data)
204 }
205 fn push_link(&mut self, data: LinkData) -> LinkId {
206 let owner = data.owner;
207 let id = self.links.alloc(data);
208 self.mods[owner].children.push(id);
209 id
210 }
211}
212
213fn modules(root: &impl ast::ModuleItemOwner) -> impl Iterator<Item = (Name, &ast::Module)> {
214 root.items()
215 .filter_map(|item| match item.kind() {
216 ast::ModuleItemKind::Module(m) => Some(m),
217 _ => None,
218 })
219 .filter_map(|module| {
220 let name = module.name()?.as_name();
221 if !module.has_semi() && module.item_list().is_none() {
222 tested_by!(name_res_works_for_broken_modules);
223 return None;
224 }
225 Some((name, module))
226 })
227}
228
229fn create_module_tree<'a>(db: &impl HirDatabase, source_root: SourceRootId) -> ModuleTree {
230 let mut tree = ModuleTree::default();
231
232 let mut roots = FxHashMap::default();
233 let mut visited = FxHashSet::default();
234
235 let source_root = db.source_root(source_root);
236 for &file_id in source_root.files.values() {
237 let source = SourceItemId {
238 file_id: file_id.into(),
239 item_id: None,
240 };
241 if visited.contains(&source) {
242 continue; // TODO: use explicit crate_roots here
243 }
244 assert!(!roots.contains_key(&file_id));
245 let module_id = build_subtree(
246 db,
247 &source_root,
248 &mut tree,
249 &mut visited,
250 &mut roots,
251 None,
252 source,
253 );
254 roots.insert(file_id, module_id);
255 }
256 tree
257}
258
259fn build_subtree(
260 db: &impl HirDatabase,
261 source_root: &SourceRoot,
262 tree: &mut ModuleTree,
263 visited: &mut FxHashSet<SourceItemId>,
264 roots: &mut FxHashMap<FileId, ModuleId>,
265 parent: Option<LinkId>,
266 source: SourceItemId,
267) -> ModuleId {
268 visited.insert(source);
269 let id = tree.push_mod(ModuleData {
270 source,
271 parent,
272 children: Vec::new(),
273 });
274 for sub in db.submodules(source).iter() {
275 let link = tree.push_link(LinkData {
276 source: sub.source,
277 name: sub.name.clone(),
278 owner: id,
279 points_to: Vec::new(),
280 problem: None,
281 });
282
283 let (points_to, problem) = if sub.is_declaration {
284 let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name);
285 let points_to = points_to
286 .into_iter()
287 .map(|file_id| match roots.remove(&file_id) {
288 Some(module_id) => {
289 tree.mods[module_id].parent = Some(link);
290 module_id
291 }
292 None => build_subtree(
293 db,
294 source_root,
295 tree,
296 visited,
297 roots,
298 Some(link),
299 SourceItemId {
300 file_id: file_id.into(),
301 item_id: None,
302 },
303 ),
304 })
305 .collect::<Vec<_>>();
306 (points_to, problem)
307 } else {
308 let points_to = build_subtree(
309 db,
310 source_root,
311 tree,
312 visited,
313 roots,
314 Some(link),
315 sub.source,
316 );
317 (vec![points_to], None)
318 };
319
320 tree.links[link].points_to = points_to;
321 tree.links[link].problem = problem;
322 }
323 id
324}
325
326fn resolve_submodule( 304fn resolve_submodule(
327 db: &impl HirDatabase, 305 db: &impl HirDatabase,
328 file_id: HirFileId, 306 file_id: HirFileId,
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index ab6f3a9bc..921ba3c98 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -1,10 +1,10 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 SyntaxKind, AstNode, SourceFile, TreeArc, SyntaxNodePtr, 4 SyntaxKind, AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner}, 5 ast::{self, ModuleItemOwner},
6}; 6};
7use ra_db::{SourceRootId}; 7use ra_db::SourceRootId;
8use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 8use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
9 9
10use crate::{ 10use crate::{
@@ -72,13 +72,12 @@ pub struct LoweredModule {
72 72
73#[derive(Debug, Default, PartialEq, Eq)] 73#[derive(Debug, Default, PartialEq, Eq)]
74pub struct ImportSourceMap { 74pub struct ImportSourceMap {
75 map: ArenaMap<ImportId, SyntaxNodePtr>, 75 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>,
76} 76}
77 77
78impl ImportSourceMap { 78impl ImportSourceMap {
79 fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { 79 fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
80 self.map 80 self.map.insert(import, AstPtr::new(segment))
81 .insert(import, SyntaxNodePtr::new(segment.syntax()))
82 } 81 }
83 82
84 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { 83 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
@@ -87,9 +86,7 @@ impl ImportSourceMap {
87 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), 86 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
88 }; 87 };
89 88
90 ast::PathSegment::cast(self.map[import].to_node(file)) 89 self.map[import].to_node(file).to_owned()
91 .unwrap()
92 .to_owned()
93 } 90 }
94} 91}
95 92