aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/module_tree.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-06 16:58:10 +0000
committerAleksey Kladov <[email protected]>2019-01-06 17:01:26 +0000
commit8a3b489c2f57bdf8f6241e69276efa48b5ed4a98 (patch)
tree2032c28d8a72b162abe9f7b8dddffef7f036b91d /crates/ra_hir/src/module_tree.rs
parentcf0ce14351af03c620aca784ee2c03aad86b866e (diff)
kill module source
Diffstat (limited to 'crates/ra_hir/src/module_tree.rs')
-rw-r--r--crates/ra_hir/src/module_tree.rs245
1 files changed, 102 insertions, 143 deletions
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs
index b7912ba5e..c7a442319 100644
--- a/crates/ra_hir/src/module_tree.rs
+++ b/crates/ra_hir/src/module_tree.rs
@@ -11,55 +11,70 @@ use ra_syntax::{
11}; 11};
12use ra_arena::{Arena, RawId, impl_arena_id}; 12use ra_arena::{Arena, RawId, impl_arena_id};
13 13
14use crate::{Name, AsName, HirDatabase, SourceItemId, SourceFileItemId, HirFileId, Problem}; 14use crate::{Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource};
15
16impl ModuleSource {
17 pub fn from_source_item_id(
18 db: &impl HirDatabase,
19 source_item_id: SourceItemId,
20 ) -> ModuleSource {
21 let module_syntax = db.file_item(source_item_id);
22 let module_syntax = module_syntax.borrowed();
23 if let Some(source_file) = ast::SourceFile::cast(module_syntax) {
24 ModuleSource::SourceFile(source_file.owned())
25 } else if let Some(module) = ast::Module::cast(module_syntax) {
26 assert!(module.item_list().is_some(), "expected inline module");
27 ModuleSource::Module(module.owned())
28 } else {
29 panic!("expected file or inline module")
30 }
31 }
32}
15 33
16#[derive(Clone, Hash, PartialEq, Eq, Debug)] 34#[derive(Clone, Hash, PartialEq, Eq, Debug)]
17pub enum Submodule { 35pub struct Submodule {
18 Declaration(Name), 36 name: Name,
19 Definition(Name, ModuleSource), 37 is_declaration: bool,
38 source: SourceItemId,
20} 39}
21 40
22impl Submodule { 41impl Submodule {
23 pub(crate) fn submodules_query( 42 pub(crate) fn submodules_query(
24 db: &impl HirDatabase, 43 db: &impl HirDatabase,
25 source: ModuleSource, 44 source: SourceItemId,
26 ) -> Cancelable<Arc<Vec<Submodule>>> { 45 ) -> Cancelable<Arc<Vec<Submodule>>> {
27 db.check_canceled()?; 46 db.check_canceled()?;
28 let file_id = source.file_id(); 47 let file_id = source.file_id;
29 let submodules = match source.resolve(db) { 48 let file_items = db.file_items(file_id);
30 ModuleSourceNode::SourceFile(it) => collect_submodules(db, file_id, it.borrowed()), 49 let module_source = ModuleSource::from_source_item_id(db, source);
31 ModuleSourceNode::Module(it) => it 50 let submodules = match module_source {
32 .borrowed() 51 ModuleSource::SourceFile(source_file) => {
33 .item_list() 52 collect_submodules(file_id, &file_items, source_file.borrowed())
34 .map(|it| collect_submodules(db, file_id, it)) 53 }
35 .unwrap_or_else(Vec::new), 54 ModuleSource::Module(module) => {
55 let module = module.borrowed();
56 collect_submodules(file_id, &file_items, module.item_list().unwrap())
57 }
36 }; 58 };
37 return Ok(Arc::new(submodules)); 59 return Ok(Arc::new(submodules));
38 60
39 fn collect_submodules<'a>( 61 fn collect_submodules<'a>(
40 db: &impl HirDatabase,
41 file_id: HirFileId, 62 file_id: HirFileId,
63 file_items: &SourceFileItems,
42 root: impl ast::ModuleItemOwner<'a>, 64 root: impl ast::ModuleItemOwner<'a>,
43 ) -> Vec<Submodule> { 65 ) -> Vec<Submodule> {
44 modules(root) 66 modules(root)
45 .map(|(name, m)| { 67 .map(|(name, m)| Submodule {
46 if m.has_semi() { 68 name,
47 Submodule::Declaration(name) 69 is_declaration: m.has_semi(),
48 } else { 70 source: SourceItemId {
49 let src = ModuleSource::new_inline(db, file_id, m); 71 file_id,
50 Submodule::Definition(name, src) 72 item_id: Some(file_items.id_of(file_id, m.syntax())),
51 } 73 },
52 }) 74 })
53 .collect() 75 .collect()
54 } 76 }
55 } 77 }
56
57 fn name(&self) -> &Name {
58 match self {
59 Submodule::Declaration(name) => name,
60 Submodule::Definition(name, _) => name,
61 }
62 }
63} 78}
64 79
65#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 80#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -85,13 +100,14 @@ pub struct ModuleTree {
85 100
86#[derive(Debug, PartialEq, Eq, Hash)] 101#[derive(Debug, PartialEq, Eq, Hash)]
87pub struct ModuleData { 102pub struct ModuleData {
88 source: ModuleSource, 103 source: SourceItemId,
89 parent: Option<LinkId>, 104 parent: Option<LinkId>,
90 children: Vec<LinkId>, 105 children: Vec<LinkId>,
91} 106}
92 107
93#[derive(Hash, Debug, PartialEq, Eq)] 108#[derive(Hash, Debug, PartialEq, Eq)]
94struct LinkData { 109struct LinkData {
110 source: SourceItemId,
95 owner: ModuleId, 111 owner: ModuleId,
96 name: Name, 112 name: Name,
97 points_to: Vec<ModuleId>, 113 points_to: Vec<ModuleId>,
@@ -112,27 +128,14 @@ impl ModuleTree {
112 self.mods.iter().map(|(id, _)| id) 128 self.mods.iter().map(|(id, _)| id)
113 } 129 }
114 130
115 pub(crate) fn modules_with_sources<'a>( 131 pub(crate) fn find_module_by_source(&self, source: SourceItemId) -> Option<ModuleId> {
116 &'a self, 132 let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?;
117 ) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a { 133 Some(res)
118 self.mods.iter().map(|(id, m)| (id, m.source))
119 } 134 }
120} 135}
121 136
122/// `ModuleSource` is the syntax tree element that produced this module:
123/// either a file, or an inlinde module.
124#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
125pub struct ModuleSource(pub(crate) SourceItemId);
126
127/// An owned syntax node for a module. Unlike `ModuleSource`,
128/// this holds onto the AST for the whole file.
129pub(crate) enum ModuleSourceNode {
130 SourceFile(ast::SourceFileNode),
131 Module(ast::ModuleNode),
132}
133
134impl ModuleId { 137impl ModuleId {
135 pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { 138 pub(crate) fn source(self, tree: &ModuleTree) -> SourceItemId {
136 tree.mods[self].source 139 tree.mods[self].source
137 } 140 }
138 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { 141 pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> {
@@ -173,9 +176,9 @@ impl ModuleId {
173 tree.mods[self] 176 tree.mods[self]
174 .children 177 .children
175 .iter() 178 .iter()
176 .filter_map(|&it| { 179 .filter_map(|&link| {
177 let p = tree.links[it].problem.clone()?; 180 let p = tree.links[link].problem.clone()?;
178 let s = it.bind_source(tree, db); 181 let s = link.source(tree, db);
179 let s = s.borrowed().name().unwrap().syntax().owned(); 182 let s = s.borrowed().name().unwrap().syntax().owned();
180 Some((s, p)) 183 Some((s, p))
181 }) 184 })
@@ -190,59 +193,11 @@ impl LinkId {
190 pub(crate) fn name(self, tree: &ModuleTree) -> &Name { 193 pub(crate) fn name(self, tree: &ModuleTree) -> &Name {
191 &tree.links[self].name 194 &tree.links[self].name
192 } 195 }
193 pub(crate) fn bind_source<'a>( 196 pub(crate) fn source(self, tree: &ModuleTree, db: &impl HirDatabase) -> ast::ModuleNode {
194 self, 197 let syntax_node = db.file_item(tree.links[self].source);
195 tree: &ModuleTree, 198 ast::ModuleNode::cast(syntax_node.borrowed())
196 db: &impl HirDatabase, 199 .unwrap()
197 ) -> ast::ModuleNode { 200 .owned()
198 let owner = self.owner(tree);
199 match owner.source(tree).resolve(db) {
200 ModuleSourceNode::SourceFile(root) => {
201 let ast = modules(root.borrowed())
202 .find(|(name, _)| name == &tree.links[self].name)
203 .unwrap()
204 .1;
205 ast.owned()
206 }
207 ModuleSourceNode::Module(it) => it,
208 }
209 }
210}
211
212impl ModuleSource {
213 // precondition: item_id **must** point to module
214 fn new(file_id: HirFileId, item_id: Option<SourceFileItemId>) -> ModuleSource {
215 let source_item_id = SourceItemId { file_id, item_id };
216 ModuleSource(source_item_id)
217 }
218
219 pub(crate) fn new_file(file_id: HirFileId) -> ModuleSource {
220 ModuleSource::new(file_id, None)
221 }
222
223 pub(crate) fn new_inline(
224 db: &impl HirDatabase,
225 file_id: HirFileId,
226 m: ast::Module,
227 ) -> ModuleSource {
228 assert!(!m.has_semi());
229 let file_items = db.file_items(file_id);
230 let item_id = file_items.id_of(file_id, m.syntax());
231 ModuleSource::new(file_id, Some(item_id))
232 }
233
234 pub(crate) fn file_id(self) -> HirFileId {
235 self.0.file_id
236 }
237
238 pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
239 let syntax_node = db.file_item(self.0);
240 let syntax_node = syntax_node.borrowed();
241 if let Some(file) = ast::SourceFile::cast(syntax_node) {
242 return ModuleSourceNode::SourceFile(file.owned());
243 }
244 let module = ast::Module::cast(syntax_node).unwrap();
245 ModuleSourceNode::Module(module.owned())
246 } 201 }
247} 202}
248 203
@@ -283,7 +238,10 @@ fn create_module_tree<'a>(
283 238
284 let source_root = db.source_root(source_root); 239 let source_root = db.source_root(source_root);
285 for &file_id in source_root.files.values() { 240 for &file_id in source_root.files.values() {
286 let source = ModuleSource::new_file(file_id.into()); 241 let source = SourceItemId {
242 file_id: file_id.into(),
243 item_id: None,
244 };
287 if visited.contains(&source) { 245 if visited.contains(&source) {
288 continue; // TODO: use explicit crate_roots here 246 continue; // TODO: use explicit crate_roots here
289 } 247 }
@@ -306,10 +264,10 @@ fn build_subtree(
306 db: &impl HirDatabase, 264 db: &impl HirDatabase,
307 source_root: &SourceRoot, 265 source_root: &SourceRoot,
308 tree: &mut ModuleTree, 266 tree: &mut ModuleTree,
309 visited: &mut FxHashSet<ModuleSource>, 267 visited: &mut FxHashSet<SourceItemId>,
310 roots: &mut FxHashMap<FileId, ModuleId>, 268 roots: &mut FxHashMap<FileId, ModuleId>,
311 parent: Option<LinkId>, 269 parent: Option<LinkId>,
312 source: ModuleSource, 270 source: SourceItemId,
313) -> Cancelable<ModuleId> { 271) -> Cancelable<ModuleId> {
314 visited.insert(source); 272 visited.insert(source);
315 let id = tree.push_mod(ModuleData { 273 let id = tree.push_mod(ModuleData {
@@ -319,47 +277,48 @@ fn build_subtree(
319 }); 277 });
320 for sub in db.submodules(source)?.iter() { 278 for sub in db.submodules(source)?.iter() {
321 let link = tree.push_link(LinkData { 279 let link = tree.push_link(LinkData {
322 name: sub.name().clone(), 280 source: sub.source,
281 name: sub.name.clone(),
323 owner: id, 282 owner: id,
324 points_to: Vec::new(), 283 points_to: Vec::new(),
325 problem: None, 284 problem: None,
326 }); 285 });
327 286
328 let (points_to, problem) = match sub { 287 let (points_to, problem) = if sub.is_declaration {
329 Submodule::Declaration(name) => { 288 let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name);
330 let (points_to, problem) = resolve_submodule(db, source, &name); 289 let points_to = points_to
331 let points_to = points_to 290 .into_iter()
332 .into_iter() 291 .map(|file_id| match roots.remove(&file_id) {
333 .map(|file_id| match roots.remove(&file_id) { 292 Some(module_id) => {
334 Some(module_id) => { 293 tree.mods[module_id].parent = Some(link);
335 tree.mods[module_id].parent = Some(link); 294 Ok(module_id)
336 Ok(module_id) 295 }
337 } 296 None => build_subtree(
338 None => build_subtree( 297 db,
339 db, 298 source_root,
340 source_root, 299 tree,
341 tree, 300 visited,
342 visited, 301 roots,
343 roots, 302 Some(link),
344 Some(link), 303 SourceItemId {
345 ModuleSource::new_file(file_id.into()), 304 file_id: file_id.into(),
346 ), 305 item_id: None,
347 }) 306 },
348 .collect::<Cancelable<Vec<_>>>()?; 307 ),
349 (points_to, problem) 308 })
350 } 309 .collect::<Cancelable<Vec<_>>>()?;
351 Submodule::Definition(_name, submodule_source) => { 310 (points_to, problem)
352 let points_to = build_subtree( 311 } else {
353 db, 312 let points_to = build_subtree(
354 source_root, 313 db,
355 tree, 314 source_root,
356 visited, 315 tree,
357 roots, 316 visited,
358 Some(link), 317 roots,
359 *submodule_source, 318 Some(link),
360 )?; 319 sub.source,
361 (vec![points_to], None) 320 )?;
362 } 321 (vec![points_to], None)
363 }; 322 };
364 323
365 tree.links[link].points_to = points_to; 324 tree.links[link].points_to = points_to;
@@ -370,11 +329,11 @@ fn build_subtree(
370 329
371fn resolve_submodule( 330fn resolve_submodule(
372 db: &impl HirDatabase, 331 db: &impl HirDatabase,
373 source: ModuleSource, 332 file_id: HirFileId,
374 name: &Name, 333 name: &Name,
375) -> (Vec<FileId>, Option<Problem>) { 334) -> (Vec<FileId>, Option<Problem>) {
376 // FIXME: handle submodules of inline modules properly 335 // FIXME: handle submodules of inline modules properly
377 let file_id = source.file_id().original_file(db); 336 let file_id = file_id.original_file(db);
378 let source_root_id = db.file_source_root(file_id); 337 let source_root_id = db.file_source_root(file_id);
379 let path = db.file_relative_path(file_id); 338 let path = db.file_relative_path(file_id);
380 let root = RelativePathBuf::default(); 339 let root = RelativePathBuf::default();