diff options
Diffstat (limited to 'crates/libanalysis/src/module_map.rs')
-rw-r--r-- | crates/libanalysis/src/module_map.rs | 117 |
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 @@ | |||
1 | use std::{ | ||
2 | path::{PathBuf}, | ||
3 | }; | ||
4 | |||
5 | use libsyntax2::{ | ||
6 | ast::{self, AstNode, NameOwner}, | ||
7 | SyntaxNode, ParsedFile, SmolStr, | ||
8 | }; | ||
9 | use {FileId, FileResolver}; | ||
10 | |||
11 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
12 | pub struct ModuleId(FileId); | ||
13 | |||
14 | #[derive(Clone, Debug, Default)] | ||
15 | pub struct ModuleMap { | ||
16 | links: Vec<Link>, | ||
17 | } | ||
18 | |||
19 | #[derive(Clone, Debug)] | ||
20 | struct Link { | ||
21 | owner: ModuleId, | ||
22 | syntax: SyntaxNode, | ||
23 | points_to: Vec<ModuleId>, | ||
24 | } | ||
25 | |||
26 | impl 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 | |||
82 | impl 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 | } | ||