aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/module_map.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libanalysis/src/module_map.rs')
-rw-r--r--crates/libanalysis/src/module_map.rs117
1 files changed, 117 insertions, 0 deletions
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs
new file mode 100644
index 000000000..9b4c778b6
--- /dev/null
+++ b/crates/libanalysis/src/module_map.rs
@@ -0,0 +1,117 @@
1use std::{
2 path::{PathBuf},
3};
4
5use libsyntax2::{
6 ast::{self, AstNode, NameOwner},
7 SyntaxNode, ParsedFile, SmolStr,
8};
9use {FileId, FileResolver};
10
11#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
12pub struct ModuleId(FileId);
13
14#[derive(Clone, Debug, Default)]
15pub struct ModuleMap {
16 links: Vec<Link>,
17}
18
19#[derive(Clone, Debug)]
20struct Link {
21 owner: ModuleId,
22 syntax: SyntaxNode,
23 points_to: Vec<ModuleId>,
24}
25
26impl ModuleMap {
27 pub fn update_file(
28 &mut self,
29 file_id: FileId,
30 syntax: Option<&ParsedFile>,
31 file_resolver: &FileResolver,
32 ) {
33 let mod_id = ModuleId(file_id);
34 self.links.retain(|link| link.owner != mod_id);
35 match syntax {
36 None => {
37 for link in self.links.iter_mut() {
38 link.points_to.retain(|&x| x != mod_id);
39 }
40 }
41 Some(syntax) => {
42 self.links.extend(
43 syntax.ast().modules().filter_map(|it| {
44 Link::new(mod_id, it)
45 })
46 )
47 }
48 }
49 self.links.iter_mut().for_each(|link| {
50 link.resolve(file_resolver)
51 })
52 }
53
54 pub fn module2file(&self, m: ModuleId) -> FileId {
55 m.0
56 }
57
58 pub fn file2module(&self, file_id: FileId) -> ModuleId {
59 ModuleId(file_id)
60 }
61
62 pub fn child_module_by_name(&self, parent_mod: ModuleId, child_mod: &str) -> Vec<ModuleId> {
63 self.links
64 .iter()
65 .filter(|link| link.owner == parent_mod)
66 .filter(|link| link.name() == child_mod)
67 .filter_map(|it| it.points_to.first())
68 .map(|&it| it)
69 .collect()
70 }
71
72 pub fn parent_modules<'a>(&'a self, m: ModuleId) -> impl Iterator<Item=(ModuleId, ast::Module<'a>)> + 'a {
73 self.links
74 .iter()
75 .filter(move |link| link.points_to.iter().any(|&it| it == m))
76 .map(|link| {
77 (link.owner, link.ast())
78 })
79 }
80}
81
82impl Link {
83 fn new(owner: ModuleId, module: ast::Module) -> Option<Link> {
84 if module.name().is_none() {
85 return None;
86 }
87 let link = Link {
88 owner,
89 syntax: module.syntax().owned(),
90 points_to: Vec::new(),
91 };
92 Some(link)
93 }
94
95 fn name(&self) -> SmolStr {
96 self.ast().name()
97 .unwrap()
98 .text()
99 }
100
101 fn ast(&self) -> ast::Module {
102 ast::Module::cast(self.syntax.borrowed())
103 .unwrap()
104 }
105
106 fn resolve(&mut self, file_resolver: &FileResolver) {
107 let name = self.name();
108 let paths = &[
109 PathBuf::from(format!("../{}.rs", name)),
110 PathBuf::from(format!("../{}/mod.rs", name)),
111 ];
112 self.points_to = paths.iter()
113 .filter_map(|path| file_resolver(self.owner.0, path))
114 .map(ModuleId)
115 .collect();
116 }
117}