aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/module_map_db.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libanalysis/src/module_map_db.rs')
-rw-r--r--crates/libanalysis/src/module_map_db.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/crates/libanalysis/src/module_map_db.rs b/crates/libanalysis/src/module_map_db.rs
new file mode 100644
index 000000000..1ef87ab3f
--- /dev/null
+++ b/crates/libanalysis/src/module_map_db.rs
@@ -0,0 +1,189 @@
1use std::sync::Arc;
2use {
3 FileId,
4 db::{Query, Eval, QueryCtx, FileSyntax, Files},
5 module_map::resolve_submodule,
6};
7
8enum ModuleDescr {}
9impl Query for ModuleDescr {
10 const ID: u32 = 30;
11 type Params = FileId;
12 type Output = Arc<descr::ModuleDescr>;
13}
14
15enum ResolveSubmodule {}
16impl Query for ResolveSubmodule {
17 const ID: u32 = 31;
18 type Params = (FileId, descr::Submodule);
19 type Output = Arc<Vec<FileId>>;
20}
21
22enum ParentModule {}
23impl Query for ParentModule {
24 const ID: u32 = 40;
25 type Params = FileId;
26 type Output = Arc<Vec<FileId>>;
27}
28
29impl Eval for ModuleDescr {
30 fn eval(ctx: &QueryCtx, file_id: &FileId) -> Arc<descr::ModuleDescr> {
31 let file = ctx.get::<FileSyntax>(file_id);
32 Arc::new(descr::ModuleDescr::new(file.ast()))
33 }
34}
35
36impl Eval for ResolveSubmodule {
37 fn eval(ctx: &QueryCtx, &(file_id, ref submodule): &(FileId, descr::Submodule)) -> Arc<Vec<FileId>> {
38 let files = ctx.get::<Files>(&());
39 let res = resolve_submodule(file_id, &submodule.name, &files.file_resolver()).0;
40 Arc::new(res)
41 }
42}
43
44impl Eval for ParentModule {
45 fn eval(ctx: &QueryCtx, file_id: &FileId) -> Arc<Vec<FileId>> {
46 let files = ctx.get::<Files>(&());
47 let res = files.iter()
48 .map(|parent_id| (parent_id, ctx.get::<ModuleDescr>(&parent_id)))
49 .filter(|(parent_id, descr)| {
50 descr.submodules.iter()
51 .any(|subm| {
52 ctx.get::<ResolveSubmodule>(&(*parent_id, subm.clone()))
53 .iter()
54 .any(|it| it == file_id)
55 })
56 })
57 .map(|(id, _)| id)
58 .collect();
59 Arc::new(res)
60 }
61}
62
63mod descr {
64 use libsyntax2::{
65 SmolStr,
66 ast::{self, NameOwner},
67 };
68
69 pub struct ModuleDescr {
70 pub submodules: Vec<Submodule>
71 }
72
73 impl ModuleDescr {
74 pub fn new(root: ast::Root) -> ModuleDescr {
75 let submodules = root
76 .modules()
77 .filter_map(|module| {
78 let name = module.name()?.text();
79 if !module.has_semi() {
80 return None;
81 }
82 Some(Submodule { name })
83 }).collect();
84
85 ModuleDescr { submodules } }
86 }
87
88 #[derive(Clone, Hash)]
89 pub struct Submodule {
90 pub name: SmolStr,
91 }
92
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use im;
99 use relative_path::{RelativePath, RelativePathBuf};
100 use {
101 db::Db,
102 imp::FileResolverImp,
103 FileId, FileResolver,
104 };
105
106 #[derive(Debug)]
107 struct FileMap(im::HashMap<FileId, RelativePathBuf>);
108
109 impl FileResolver for FileMap {
110 fn file_stem(&self, file_id: FileId) -> String {
111 self.0[&file_id].file_stem().unwrap().to_string()
112 }
113 fn resolve(&self, file_id: FileId, rel: &RelativePath) -> Option<FileId> {
114 let path = self.0[&file_id].join(rel).normalize();
115 self.0.iter()
116 .filter_map(|&(id, ref p)| Some(id).filter(|_| p == &path))
117 .next()
118 }
119 }
120
121 struct Fixture {
122 next_file_id: u32,
123 fm: im::HashMap<FileId, RelativePathBuf>,
124 db: Db,
125 }
126
127 impl Fixture {
128 fn new() -> Fixture {
129 Fixture {
130 next_file_id: 1,
131 fm: im::HashMap::new(),
132 db: Db::new(),
133 }
134 }
135 fn add_file(&mut self, path: &str, text: &str) -> FileId {
136 assert!(path.starts_with("/"));
137 let file_id = FileId(self.next_file_id);
138 self.next_file_id += 1;
139 self.fm.insert(file_id, RelativePathBuf::from(&path[1..]));
140 self.db.change_file(file_id, Some(text.to_string()));
141 self.db.set_file_resolver(FileResolverImp::new(
142 Arc::new(FileMap(self.fm.clone()))
143 ));
144
145 file_id
146 }
147 fn remove_file(&mut self, file_id: FileId) {
148 self.fm.remove(&file_id);
149 self.db.change_file(file_id, None);
150 self.db.set_file_resolver(FileResolverImp::new(
151 Arc::new(FileMap(self.fm.clone()))
152 ))
153 }
154 fn change_file(&mut self, file_id: FileId, new_text: &str) {
155 self.db.change_file(file_id, Some(new_text.to_string()));
156 }
157 fn check_parent_modules(&self, file_id: FileId, expected: &[FileId]) {
158 let ctx = self.db.query_ctx();
159 let actual = ctx.get::<ParentModule>(&file_id);
160 assert_eq!(actual.as_slice(), expected);
161 }
162 }
163
164 #[test]
165 fn test_parent_module() {
166 let mut f = Fixture::new();
167 let foo = f.add_file("/foo.rs", "");
168 f.check_parent_modules(foo, &[]);
169
170 let lib = f.add_file("/lib.rs", "mod foo;");
171 f.check_parent_modules(foo, &[lib]);
172
173 f.change_file(lib, "");
174 f.check_parent_modules(foo, &[]);
175
176 f.change_file(lib, "mod foo;");
177 f.check_parent_modules(foo, &[lib]);
178
179 f.change_file(lib, "mod bar;");
180 f.check_parent_modules(foo, &[]);
181
182 f.change_file(lib, "mod foo;");
183 f.check_parent_modules(foo, &[lib]);
184
185 f.remove_file(lib);
186 f.check_parent_modules(foo, &[]);
187 }
188
189}