diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/libanalysis/src/db/imp.rs | 3 | ||||
-rw-r--r-- | crates/libanalysis/src/db/mod.rs | 42 | ||||
-rw-r--r-- | crates/libanalysis/src/descriptors.rs | 5 | ||||
-rw-r--r-- | crates/libanalysis/src/imp.rs | 22 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 20 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map.rs | 386 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map_db/mod.rs | 159 | ||||
-rw-r--r-- | crates/libanalysis/src/queries.rs | 28 | ||||
-rw-r--r-- | crates/libanalysis/src/roots.rs | 114 |
9 files changed, 239 insertions, 540 deletions
diff --git a/crates/libanalysis/src/db/imp.rs b/crates/libanalysis/src/db/imp.rs index 1b4ee5cf3..f26be1046 100644 --- a/crates/libanalysis/src/db/imp.rs +++ b/crates/libanalysis/src/db/imp.rs | |||
@@ -122,9 +122,6 @@ impl QueryRegistry { | |||
122 | let config = config.with_query(id, q.f()); | 122 | let config = config.with_query(id, q.f()); |
123 | self.config= Some(config); | 123 | self.config= Some(config); |
124 | } | 124 | } |
125 | pub(super) fn finish(mut self) -> salsa::QueryConfig<State, Data> { | ||
126 | self.config.take().unwrap() | ||
127 | } | ||
128 | } | 125 | } |
129 | 126 | ||
130 | fn hash<T: Hash>(x: &T) -> u64 { | 127 | fn hash<T: Hash>(x: &T) -> u64 { |
diff --git a/crates/libanalysis/src/db/mod.rs b/crates/libanalysis/src/db/mod.rs index 1111a4f87..22769d112 100644 --- a/crates/libanalysis/src/db/mod.rs +++ b/crates/libanalysis/src/db/mod.rs | |||
@@ -29,6 +29,12 @@ pub(crate) struct QueryRegistry { | |||
29 | imp: imp::QueryRegistry, | 29 | imp: imp::QueryRegistry, |
30 | } | 30 | } |
31 | 31 | ||
32 | impl Default for Db { | ||
33 | fn default() -> Db { | ||
34 | Db::new() | ||
35 | } | ||
36 | } | ||
37 | |||
32 | impl Db { | 38 | impl Db { |
33 | pub(crate) fn new() -> Db { | 39 | pub(crate) fn new() -> Db { |
34 | let reg = QueryRegistry::new(); | 40 | let reg = QueryRegistry::new(); |
@@ -44,6 +50,7 @@ impl Db { | |||
44 | let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() }; | 50 | let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() }; |
45 | f(ctx) | 51 | f(ctx) |
46 | } | 52 | } |
53 | #[allow(unused)] | ||
47 | pub(crate) fn trace_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> (R, Vec<&'static str>) { | 54 | pub(crate) fn trace_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> (R, Vec<&'static str>) { |
48 | let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() }; | 55 | let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() }; |
49 | let res = f(ctx); | 56 | let res = f(ctx); |
@@ -65,42 +72,11 @@ pub(crate) fn file_text(ctx: QueryCtx, file_id: FileId) -> Arc<String> { | |||
65 | pub(crate) fn file_set(ctx: QueryCtx) -> Arc<(Vec<FileId>, FileResolverImp)> { | 72 | pub(crate) fn file_set(ctx: QueryCtx) -> Arc<(Vec<FileId>, FileResolverImp)> { |
66 | imp::file_set(ctx) | 73 | imp::file_set(ctx) |
67 | } | 74 | } |
68 | pub(crate) use self::queries::file_syntax; | ||
69 | |||
70 | mod queries { | ||
71 | use std::sync::Arc; | ||
72 | use libsyntax2::File; | ||
73 | use libeditor::LineIndex; | ||
74 | use {FileId}; | ||
75 | use super::{Query, QueryCtx, QueryRegistry, file_text}; | ||
76 | |||
77 | pub(crate) fn register_queries(reg: &mut QueryRegistry) { | ||
78 | reg.add(FILE_SYNTAX, "FILE_SYNTAX"); | ||
79 | reg.add(FILE_LINES, "FILE_LINES"); | ||
80 | } | ||
81 | |||
82 | pub(crate) fn file_syntax(ctx: QueryCtx, file_id: FileId) -> File { | ||
83 | (&*ctx.get(FILE_SYNTAX, file_id)).clone() | ||
84 | } | ||
85 | pub(crate) fn file_lines(ctx: QueryCtx, file_id: FileId) -> Arc<LineIndex> { | ||
86 | ctx.get(FILE_LINES, file_id) | ||
87 | } | ||
88 | |||
89 | pub(super) const FILE_SYNTAX: Query<FileId, File> = Query(16, |ctx, file_id: &FileId| { | ||
90 | let text = file_text(ctx, *file_id); | ||
91 | File::parse(&*text) | ||
92 | }); | ||
93 | pub(super) const FILE_LINES: Query<FileId, LineIndex> = Query(17, |ctx, file_id: &FileId| { | ||
94 | let text = file_text(ctx, *file_id); | ||
95 | LineIndex::new(&*text) | ||
96 | }); | ||
97 | } | ||
98 | |||
99 | impl QueryRegistry { | 75 | impl QueryRegistry { |
100 | fn new() -> QueryRegistry { | 76 | fn new() -> QueryRegistry { |
101 | let mut reg = QueryRegistry { imp: imp::QueryRegistry::new() }; | 77 | let mut reg = QueryRegistry { imp: imp::QueryRegistry::new() }; |
102 | queries::register_queries(&mut reg); | 78 | ::queries::register_queries(&mut reg); |
103 | ::module_map_db::register_queries(&mut reg); | 79 | ::module_map::register_queries(&mut reg); |
104 | reg | 80 | reg |
105 | } | 81 | } |
106 | pub(crate) fn add<Q: imp::EvalQuery>(&mut self, q: Q, name: &'static str) { | 82 | pub(crate) fn add<Q: imp::EvalQuery>(&mut self, q: Q, name: &'static str) { |
diff --git a/crates/libanalysis/src/descriptors.rs b/crates/libanalysis/src/descriptors.rs index 200f21576..93a4158e4 100644 --- a/crates/libanalysis/src/descriptors.rs +++ b/crates/libanalysis/src/descriptors.rs | |||
@@ -140,7 +140,7 @@ impl ModuleTreeDescriptor { | |||
140 | .links | 140 | .links |
141 | .iter() | 141 | .iter() |
142 | .filter(|it| it.name(self) == name) | 142 | .filter(|it| it.name(self) == name) |
143 | .map(|link| link.owner(self)) | 143 | .flat_map(|link| link.points_to(self).iter().map(|&node| self.node(node).file_id)) |
144 | .collect() | 144 | .collect() |
145 | } | 145 | } |
146 | pub(crate) fn problems<'a, 'b>(&'b self, file_id: FileId, root: ast::Root<'a>) -> Vec<(ast::Name<'a>, &'b Problem)> { | 146 | pub(crate) fn problems<'a, 'b>(&'b self, file_id: FileId, root: ast::Root<'a>) -> Vec<(ast::Name<'a>, &'b Problem)> { |
@@ -172,6 +172,9 @@ impl Link { | |||
172 | let owner = tree.link(self).owner; | 172 | let owner = tree.link(self).owner; |
173 | tree.node(owner).file_id | 173 | tree.node(owner).file_id |
174 | } | 174 | } |
175 | fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] { | ||
176 | &tree.link(self).points_to | ||
177 | } | ||
175 | pub(crate) fn bind_source<'a>(self, tree: &ModuleTreeDescriptor, root: ast::Root<'a>) -> ast::Module<'a> { | 178 | pub(crate) fn bind_source<'a>(self, tree: &ModuleTreeDescriptor, root: ast::Root<'a>) -> ast::Module<'a> { |
176 | modules(root) | 179 | modules(root) |
177 | .filter(|(name, _)| name == &tree.link(self).name) | 180 | .filter(|(name, _)| name == &tree.link(self).name) |
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index 8734813f4..6f3191fe7 100644 --- a/crates/libanalysis/src/imp.rs +++ b/crates/libanalysis/src/imp.rs | |||
@@ -5,6 +5,7 @@ use std::{ | |||
5 | }, | 5 | }, |
6 | fmt, | 6 | fmt, |
7 | collections::{HashSet, VecDeque}, | 7 | collections::{HashSet, VecDeque}, |
8 | iter, | ||
8 | }; | 9 | }; |
9 | 10 | ||
10 | use relative_path::RelativePath; | 11 | use relative_path::RelativePath; |
@@ -75,14 +76,12 @@ impl AnalysisHostImpl { | |||
75 | } | 76 | } |
76 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { | 77 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { |
77 | let data = self.data_mut(); | 78 | let data = self.data_mut(); |
78 | for (file_id, text) in changes { | 79 | data.root = Arc::new(data.root.apply_changes(changes, None)); |
79 | data.root.update(file_id, text); | ||
80 | } | ||
81 | } | 80 | } |
82 | pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { | 81 | pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { |
83 | let data = self.data_mut(); | 82 | let data = self.data_mut(); |
84 | data.file_resolver = resolver.clone(); | 83 | data.file_resolver = resolver.clone(); |
85 | data.root.set_file_resolver(resolver); | 84 | data.root = Arc::new(data.root.apply_changes(&mut iter::empty(), Some(resolver))); |
86 | } | 85 | } |
87 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 86 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { |
88 | let mut visited = HashSet::new(); | 87 | let mut visited = HashSet::new(); |
@@ -124,18 +123,17 @@ impl Clone for AnalysisImpl { | |||
124 | impl AnalysisImpl { | 123 | impl AnalysisImpl { |
125 | fn root(&self, file_id: FileId) -> &SourceRoot { | 124 | fn root(&self, file_id: FileId) -> &SourceRoot { |
126 | if self.data.root.contains(file_id) { | 125 | if self.data.root.contains(file_id) { |
127 | return &self.data.root; | 126 | return &*self.data.root; |
128 | } | 127 | } |
129 | &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() | 128 | &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() |
130 | } | 129 | } |
131 | pub fn file_syntax(&self, file_id: FileId) -> &File { | 130 | pub fn file_syntax(&self, file_id: FileId) -> File { |
132 | self.root(file_id).syntax(file_id) | 131 | self.root(file_id).syntax(file_id) |
133 | } | 132 | } |
134 | pub fn file_line_index(&self, file_id: FileId) -> &LineIndex { | 133 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
135 | self.root(file_id).lines(file_id) | 134 | self.root(file_id).lines(file_id) |
136 | } | 135 | } |
137 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 136 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
138 | self.reindex(); | ||
139 | let mut buf = Vec::new(); | 137 | let mut buf = Vec::new(); |
140 | if query.libs { | 138 | if query.libs { |
141 | self.data.libs.iter() | 139 | self.data.libs.iter() |
@@ -308,19 +306,13 @@ impl AnalysisImpl { | |||
308 | }; | 306 | }; |
309 | module_tree.child_module_by_name(file_id, name.as_str()) | 307 | module_tree.child_module_by_name(file_id, name.as_str()) |
310 | } | 308 | } |
311 | |||
312 | fn reindex(&self) { | ||
313 | if self.needs_reindex.compare_and_swap(true, false, SeqCst) { | ||
314 | self.data.root.reindex(); | ||
315 | } | ||
316 | } | ||
317 | } | 309 | } |
318 | 310 | ||
319 | #[derive(Default, Clone, Debug)] | 311 | #[derive(Default, Clone, Debug)] |
320 | struct WorldData { | 312 | struct WorldData { |
321 | file_resolver: FileResolverImp, | 313 | file_resolver: FileResolverImp, |
322 | crate_graph: CrateGraph, | 314 | crate_graph: CrateGraph, |
323 | root: WritableSourceRoot, | 315 | root: Arc<WritableSourceRoot>, |
324 | libs: Vec<Arc<ReadonlySourceRoot>>, | 316 | libs: Vec<Arc<ReadonlySourceRoot>>, |
325 | } | 317 | } |
326 | 318 | ||
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index ea3a28702..b4b7a6a30 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -14,11 +14,11 @@ extern crate salsa; | |||
14 | 14 | ||
15 | mod symbol_index; | 15 | mod symbol_index; |
16 | mod module_map; | 16 | mod module_map; |
17 | pub(crate) mod module_map_db; | ||
18 | mod imp; | 17 | mod imp; |
19 | mod job; | 18 | mod job; |
20 | mod roots; | 19 | mod roots; |
21 | mod db; | 20 | mod db; |
21 | mod queries; | ||
22 | mod descriptors; | 22 | mod descriptors; |
23 | 23 | ||
24 | use std::{ | 24 | use std::{ |
@@ -166,8 +166,8 @@ impl Analysis { | |||
166 | pub fn file_syntax(&self, file_id: FileId) -> File { | 166 | pub fn file_syntax(&self, file_id: FileId) -> File { |
167 | self.imp.file_syntax(file_id).clone() | 167 | self.imp.file_syntax(file_id).clone() |
168 | } | 168 | } |
169 | pub fn file_line_index(&self, file_id: FileId) -> LineIndex { | 169 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
170 | self.imp.file_line_index(file_id).clone() | 170 | self.imp.file_line_index(file_id) |
171 | } | 171 | } |
172 | pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange { | 172 | pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange { |
173 | libeditor::extend_selection(file, range).unwrap_or(range) | 173 | libeditor::extend_selection(file, range).unwrap_or(range) |
@@ -177,19 +177,19 @@ impl Analysis { | |||
177 | } | 177 | } |
178 | pub fn syntax_tree(&self, file_id: FileId) -> String { | 178 | pub fn syntax_tree(&self, file_id: FileId) -> String { |
179 | let file = self.imp.file_syntax(file_id); | 179 | let file = self.imp.file_syntax(file_id); |
180 | libeditor::syntax_tree(file) | 180 | libeditor::syntax_tree(&file) |
181 | } | 181 | } |
182 | pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange { | 182 | pub fn join_lines(&self, file_id: FileId, range: TextRange) -> SourceChange { |
183 | let file = self.imp.file_syntax(file_id); | 183 | let file = self.imp.file_syntax(file_id); |
184 | SourceChange::from_local_edit(file_id, "join lines", libeditor::join_lines(file, range)) | 184 | SourceChange::from_local_edit(file_id, "join lines", libeditor::join_lines(&file, range)) |
185 | } | 185 | } |
186 | pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { | 186 | pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { |
187 | let file = self.imp.file_syntax(file_id); | 187 | let file = self.imp.file_syntax(file_id); |
188 | Some(SourceChange::from_local_edit(file_id, "add semicolon", libeditor::on_eq_typed(file, offset)?)) | 188 | Some(SourceChange::from_local_edit(file_id, "add semicolon", libeditor::on_eq_typed(&file, offset)?)) |
189 | } | 189 | } |
190 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { | 190 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { |
191 | let file = self.imp.file_syntax(file_id); | 191 | let file = self.imp.file_syntax(file_id); |
192 | libeditor::file_structure(file) | 192 | libeditor::file_structure(&file) |
193 | } | 193 | } |
194 | pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 194 | pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { |
195 | self.imp.world_symbols(query, token) | 195 | self.imp.world_symbols(query, token) |
@@ -208,15 +208,15 @@ impl Analysis { | |||
208 | } | 208 | } |
209 | pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> { | 209 | pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> { |
210 | let file = self.imp.file_syntax(file_id); | 210 | let file = self.imp.file_syntax(file_id); |
211 | libeditor::runnables(file) | 211 | libeditor::runnables(&file) |
212 | } | 212 | } |
213 | pub fn highlight(&self, file_id: FileId) -> Vec<HighlightedRange> { | 213 | pub fn highlight(&self, file_id: FileId) -> Vec<HighlightedRange> { |
214 | let file = self.imp.file_syntax(file_id); | 214 | let file = self.imp.file_syntax(file_id); |
215 | libeditor::highlight(file) | 215 | libeditor::highlight(&file) |
216 | } | 216 | } |
217 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Option<Vec<CompletionItem>> { | 217 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Option<Vec<CompletionItem>> { |
218 | let file = self.imp.file_syntax(file_id); | 218 | let file = self.imp.file_syntax(file_id); |
219 | libeditor::scope_completion(file, offset) | 219 | libeditor::scope_completion(&file, offset) |
220 | } | 220 | } |
221 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { | 221 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { |
222 | self.imp.assists(file_id, range) | 222 | self.imp.assists(file_id, range) |
diff --git a/crates/libanalysis/src/module_map.rs b/crates/libanalysis/src/module_map.rs index 79b88cac2..a21f55fff 100644 --- a/crates/libanalysis/src/module_map.rs +++ b/crates/libanalysis/src/module_map.rs | |||
@@ -1,281 +1,157 @@ | |||
1 | use relative_path::RelativePathBuf; | 1 | use std::sync::Arc; |
2 | use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; | 2 | use { |
3 | use libsyntax2::{ | 3 | FileId, |
4 | File, | 4 | db::{ |
5 | ast::{self, AstNode, NameOwner}, | 5 | Query, QueryRegistry, QueryCtx, |
6 | SyntaxNode, SmolStr, | 6 | file_set |
7 | }, | ||
8 | queries::file_syntax, | ||
9 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | ||
7 | }; | 10 | }; |
8 | use {FileId, imp::FileResolverImp}; | ||
9 | |||
10 | type SyntaxProvider<'a> = dyn Fn(FileId) -> &'a File + 'a; | ||
11 | |||
12 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] | ||
13 | pub struct ModuleId(FileId); | ||
14 | |||
15 | #[derive(Debug, Default)] | ||
16 | pub struct ModuleMap { | ||
17 | state: RwLock<State>, | ||
18 | } | ||
19 | |||
20 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
21 | pub enum ChangeKind { | ||
22 | Delete, Insert, Update | ||
23 | } | ||
24 | |||
25 | impl Clone for ModuleMap { | ||
26 | fn clone(&self) -> ModuleMap { | ||
27 | let state = self.state.read().clone(); | ||
28 | ModuleMap { state: RwLock::new(state) } | ||
29 | } | ||
30 | } | ||
31 | |||
32 | #[derive(Clone, Debug, Default)] | ||
33 | struct State { | ||
34 | file_resolver: FileResolverImp, | ||
35 | changes: Vec<(FileId, ChangeKind)>, | ||
36 | links: Vec<Link>, | ||
37 | } | ||
38 | 11 | ||
39 | #[derive(Clone, Debug)] | 12 | pub(crate) fn register_queries(reg: &mut QueryRegistry) { |
40 | struct Link { | 13 | reg.add(MODULE_DESCR, "MODULE_DESCR"); |
41 | owner: ModuleId, | 14 | reg.add(MODULE_TREE, "MODULE_TREE"); |
42 | syntax: SyntaxNode, | ||
43 | points_to: Vec<ModuleId>, | ||
44 | problem: Option<Problem>, | ||
45 | } | 15 | } |
46 | 16 | ||
47 | #[derive(Clone, Debug)] | 17 | pub(crate) fn module_tree(ctx: QueryCtx) -> Arc<ModuleTreeDescriptor> { |
48 | pub enum Problem { | 18 | ctx.get(MODULE_TREE, ()) |
49 | UnresolvedModule { | ||
50 | candidate: RelativePathBuf, | ||
51 | }, | ||
52 | NotDirOwner { | ||
53 | move_to: RelativePathBuf, | ||
54 | candidate: RelativePathBuf, | ||
55 | } | ||
56 | } | 19 | } |
57 | 20 | ||
58 | impl ModuleMap { | 21 | const MODULE_DESCR: Query<FileId, ModuleDescriptor> = Query(30, |ctx, &file_id| { |
59 | pub fn new() -> ModuleMap { | 22 | let file = file_syntax(ctx, file_id); |
60 | Default::default() | 23 | ModuleDescriptor::new(file.ast()) |
61 | } | 24 | }); |
62 | pub fn update_file(&mut self, file_id: FileId, change_kind: ChangeKind) { | 25 | |
63 | self.state.get_mut().changes.push((file_id, change_kind)); | 26 | const MODULE_TREE: Query<(), ModuleTreeDescriptor> = Query(31, |ctx, _| { |
64 | } | 27 | let file_set = file_set(ctx); |
65 | pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { | 28 | let mut files = Vec::new(); |
66 | self.state.get_mut().file_resolver = file_resolver; | 29 | for &file_id in file_set.0.iter() { |
67 | } | 30 | let module_descr = ctx.get(MODULE_DESCR, file_id); |
68 | pub fn module2file(&self, m: ModuleId) -> FileId { | 31 | files.push((file_id, module_descr)); |
69 | m.0 | 32 | } |
70 | } | 33 | ModuleTreeDescriptor::new(files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.1) |
71 | pub fn file2module(&self, file_id: FileId) -> ModuleId { | 34 | }); |
72 | ModuleId(file_id) | 35 | |
73 | } | 36 | #[cfg(test)] |
74 | pub fn child_module_by_name<'a>( | 37 | mod tests { |
75 | &self, | 38 | use std::collections::HashMap; |
76 | parent_mod: ModuleId, | 39 | use im; |
77 | child_mod: &str, | 40 | use relative_path::{RelativePath, RelativePathBuf}; |
78 | syntax_provider: &SyntaxProvider, | 41 | use { |
79 | ) -> Vec<ModuleId> { | 42 | db::{Db}, |
80 | self.links(syntax_provider) | 43 | imp::FileResolverImp, |
81 | .links | 44 | FileId, FileResolver, |
82 | .iter() | 45 | }; |
83 | .filter(|link| link.owner == parent_mod) | 46 | use super::*; |
84 | .filter(|link| link.name() == child_mod) | 47 | |
85 | .filter_map(|it| it.points_to.first()) | 48 | #[derive(Debug)] |
86 | .map(|&it| it) | 49 | struct FileMap(im::HashMap<FileId, RelativePathBuf>); |
87 | .collect() | 50 | |
88 | } | 51 | impl FileResolver for FileMap { |
89 | 52 | fn file_stem(&self, file_id: FileId) -> String { | |
90 | pub fn parent_modules( | 53 | self.0[&file_id].file_stem().unwrap().to_string() |
91 | &self, | 54 | } |
92 | m: ModuleId, | 55 | fn resolve(&self, file_id: FileId, rel: &RelativePath) -> Option<FileId> { |
93 | syntax_provider: &SyntaxProvider, | 56 | let path = self.0[&file_id].join(rel).normalize(); |
94 | ) -> Vec<(ModuleId, SmolStr, SyntaxNode)> { | 57 | self.0.iter() |
95 | let mut res = Vec::new(); | 58 | .filter_map(|&(id, ref p)| Some(id).filter(|_| p == &path)) |
96 | self.for_each_parent_link(m, syntax_provider, |link| { | 59 | .next() |
97 | res.push( | 60 | } |
98 | (link.owner, link.name().clone(), link.syntax.clone()) | ||
99 | ) | ||
100 | }); | ||
101 | res | ||
102 | } | ||
103 | |||
104 | pub fn parent_module_ids( | ||
105 | &self, | ||
106 | m: ModuleId, | ||
107 | syntax_provider: &SyntaxProvider, | ||
108 | ) -> Vec<ModuleId> { | ||
109 | let mut res = Vec::new(); | ||
110 | self.for_each_parent_link(m, syntax_provider, |link| res.push(link.owner)); | ||
111 | res | ||
112 | } | ||
113 | |||
114 | fn for_each_parent_link( | ||
115 | &self, | ||
116 | m: ModuleId, | ||
117 | syntax_provider: &SyntaxProvider, | ||
118 | f: impl FnMut(&Link) | ||
119 | ) { | ||
120 | self.links(syntax_provider) | ||
121 | .links | ||
122 | .iter() | ||
123 | .filter(move |link| link.points_to.iter().any(|&it| it == m)) | ||
124 | .for_each(f) | ||
125 | } | 61 | } |
126 | 62 | ||
127 | pub fn problems( | 63 | struct Fixture { |
128 | &self, | 64 | next_file_id: u32, |
129 | file: FileId, | 65 | fm: im::HashMap<FileId, RelativePathBuf>, |
130 | syntax_provider: &SyntaxProvider, | 66 | db: Db, |
131 | mut cb: impl FnMut(ast::Name, &Problem), | ||
132 | ) { | ||
133 | let module = self.file2module(file); | ||
134 | let links = self.links(syntax_provider); | ||
135 | links | ||
136 | .links | ||
137 | .iter() | ||
138 | .filter(|link| link.owner == module) | ||
139 | .filter_map(|link| { | ||
140 | let problem = link.problem.as_ref()?; | ||
141 | Some((link, problem)) | ||
142 | }) | ||
143 | .for_each(|(link, problem)| cb(link.name_node(), problem)) | ||
144 | } | 67 | } |
145 | 68 | ||
146 | fn links( | 69 | impl Fixture { |
147 | &self, | 70 | fn new() -> Fixture { |
148 | syntax_provider: &SyntaxProvider, | 71 | Fixture { |
149 | ) -> RwLockReadGuard<State> { | 72 | next_file_id: 1, |
150 | { | 73 | fm: im::HashMap::new(), |
151 | let guard = self.state.read(); | 74 | db: Db::new(), |
152 | if guard.changes.is_empty() { | ||
153 | return guard; | ||
154 | } | 75 | } |
155 | } | 76 | } |
156 | let mut guard = self.state.write(); | 77 | fn add_file(&mut self, path: &str, text: &str) -> FileId { |
157 | if !guard.changes.is_empty() { | 78 | assert!(path.starts_with("/")); |
158 | guard.apply_changes(syntax_provider); | 79 | let file_id = FileId(self.next_file_id); |
80 | self.next_file_id += 1; | ||
81 | self.fm.insert(file_id, RelativePathBuf::from(&path[1..])); | ||
82 | let mut new_state = self.db.state().clone(); | ||
83 | new_state.file_map.insert(file_id, Arc::new(text.to_string())); | ||
84 | new_state.file_resolver = FileResolverImp::new( | ||
85 | Arc::new(FileMap(self.fm.clone())) | ||
86 | ); | ||
87 | self.db = self.db.with_changes(new_state, &[file_id], true); | ||
88 | file_id | ||
159 | } | 89 | } |
160 | assert!(guard.changes.is_empty()); | 90 | fn remove_file(&mut self, file_id: FileId) { |
161 | RwLockWriteGuard::downgrade(guard) | 91 | self.fm.remove(&file_id); |
162 | } | 92 | let mut new_state = self.db.state().clone(); |
163 | } | 93 | new_state.file_map.remove(&file_id); |
164 | 94 | new_state.file_resolver = FileResolverImp::new( | |
165 | impl State { | 95 | Arc::new(FileMap(self.fm.clone())) |
166 | pub fn apply_changes( | 96 | ); |
167 | &mut self, | 97 | self.db = self.db.with_changes(new_state, &[file_id], true); |
168 | syntax_provider: &SyntaxProvider, | ||
169 | ) { | ||
170 | let mut reresolve = false; | ||
171 | for (file_id, kind) in self.changes.drain(..) { | ||
172 | let mod_id = ModuleId(file_id); | ||
173 | self.links.retain(|link| link.owner != mod_id); | ||
174 | match kind { | ||
175 | ChangeKind::Delete => { | ||
176 | for link in self.links.iter_mut() { | ||
177 | link.points_to.retain(|&x| x != mod_id); | ||
178 | } | ||
179 | } | ||
180 | ChangeKind::Insert => { | ||
181 | let file = syntax_provider(file_id); | ||
182 | self.links.extend( | ||
183 | file | ||
184 | .ast() | ||
185 | .modules() | ||
186 | .filter_map(|it| Link::new(mod_id, it)) | ||
187 | ); | ||
188 | reresolve = true; | ||
189 | } | ||
190 | ChangeKind::Update => { | ||
191 | let file = syntax_provider(file_id); | ||
192 | let resolver = &self.file_resolver; | ||
193 | self.links.extend( | ||
194 | file | ||
195 | .ast() | ||
196 | .modules() | ||
197 | .filter_map(|it| Link::new(mod_id, it)) | ||
198 | .map(|mut link| { | ||
199 | link.resolve(resolver); | ||
200 | link | ||
201 | }) | ||
202 | ); | ||
203 | } | ||
204 | } | ||
205 | } | 98 | } |
206 | if reresolve { | 99 | fn change_file(&mut self, file_id: FileId, new_text: &str) { |
207 | for link in self.links.iter_mut() { | 100 | let mut new_state = self.db.state().clone(); |
208 | link.resolve(&self.file_resolver) | 101 | new_state.file_map.insert(file_id, Arc::new(new_text.to_string())); |
209 | } | 102 | self.db = self.db.with_changes(new_state, &[file_id], false); |
210 | } | 103 | } |
211 | } | 104 | fn check_parent_modules( |
212 | } | 105 | &self, |
106 | file_id: FileId, | ||
107 | expected: &[FileId], | ||
108 | queries: &[(&'static str, u64)] | ||
109 | ) { | ||
110 | let (tree, events) = self.db.trace_query(|ctx| module_tree(ctx)); | ||
111 | let actual = tree.parent_modules(file_id) | ||
112 | .into_iter() | ||
113 | .map(|link| link.owner(&tree)) | ||
114 | .collect::<Vec<_>>(); | ||
115 | assert_eq!(actual.as_slice(), expected); | ||
116 | let mut counts = HashMap::new(); | ||
117 | events.into_iter() | ||
118 | .for_each(|event| *counts.entry(event).or_insert(0) += 1); | ||
119 | for &(query_id, expected_count) in queries.iter() { | ||
120 | let actual_count = *counts.get(&query_id).unwrap_or(&0); | ||
121 | assert_eq!( | ||
122 | actual_count, | ||
123 | expected_count, | ||
124 | "counts for {} differ", | ||
125 | query_id, | ||
126 | ) | ||
127 | } | ||
213 | 128 | ||
214 | impl Link { | ||
215 | fn new(owner: ModuleId, module: ast::Module) -> Option<Link> { | ||
216 | if module.name().is_none() { | ||
217 | return None; | ||
218 | } | 129 | } |
219 | let link = Link { | ||
220 | owner, | ||
221 | syntax: module.syntax().owned(), | ||
222 | points_to: Vec::new(), | ||
223 | problem: None, | ||
224 | }; | ||
225 | Some(link) | ||
226 | } | 130 | } |
227 | 131 | ||
228 | fn name(&self) -> SmolStr { | 132 | #[test] |
229 | self.name_node().text() | 133 | fn test_parent_module() { |
230 | } | 134 | let mut f = Fixture::new(); |
135 | let foo = f.add_file("/foo.rs", ""); | ||
136 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); | ||
231 | 137 | ||
232 | fn name_node(&self) -> ast::Name { | 138 | let lib = f.add_file("/lib.rs", "mod foo;"); |
233 | self.ast().name().unwrap() | 139 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); |
234 | } | 140 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 0)]); |
235 | 141 | ||
236 | fn ast(&self) -> ast::Module { | 142 | f.change_file(lib, ""); |
237 | ast::Module::cast(self.syntax.borrowed()) | 143 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); |
238 | .unwrap() | ||
239 | } | ||
240 | 144 | ||
241 | fn resolve(&mut self, file_resolver: &FileResolverImp) { | 145 | f.change_file(lib, "mod foo;"); |
242 | if !self.ast().has_semi() { | 146 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); |
243 | self.problem = None; | ||
244 | self.points_to = Vec::new(); | ||
245 | return; | ||
246 | } | ||
247 | let (points_to, problem) = resolve_submodule(self.owner.0, &self.name(), file_resolver); | ||
248 | self.problem = problem; | ||
249 | self.points_to = points_to.into_iter().map(ModuleId).collect(); | ||
250 | } | ||
251 | } | ||
252 | 147 | ||
253 | pub(crate) fn resolve_submodule(file_id: FileId, name: &SmolStr, file_resolver: &FileResolverImp) -> (Vec<FileId>, Option<Problem>) { | 148 | f.change_file(lib, "mod bar;"); |
254 | let mod_name = file_resolver.file_stem(file_id); | 149 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); |
255 | let is_dir_owner = | ||
256 | mod_name == "mod" || mod_name == "lib" || mod_name == "main"; | ||
257 | 150 | ||
258 | let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); | 151 | f.change_file(lib, "mod foo;"); |
259 | let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); | 152 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); |
260 | let points_to: Vec<FileId>; | 153 | |
261 | let problem: Option<Problem>; | 154 | f.remove_file(lib); |
262 | if is_dir_owner { | 155 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 0)]); |
263 | points_to = [&file_mod, &dir_mod].iter() | ||
264 | .filter_map(|path| file_resolver.resolve(file_id, path)) | ||
265 | .collect(); | ||
266 | problem = if points_to.is_empty() { | ||
267 | Some(Problem::UnresolvedModule { | ||
268 | candidate: file_mod, | ||
269 | }) | ||
270 | } else { | ||
271 | None | ||
272 | } | ||
273 | } else { | ||
274 | points_to = Vec::new(); | ||
275 | problem = Some(Problem::NotDirOwner { | ||
276 | move_to: RelativePathBuf::from(format!("../{}/mod.rs", mod_name)), | ||
277 | candidate: file_mod, | ||
278 | }); | ||
279 | } | 156 | } |
280 | (points_to, problem) | ||
281 | } | 157 | } |
diff --git a/crates/libanalysis/src/module_map_db/mod.rs b/crates/libanalysis/src/module_map_db/mod.rs deleted file mode 100644 index adad943da..000000000 --- a/crates/libanalysis/src/module_map_db/mod.rs +++ /dev/null | |||
@@ -1,159 +0,0 @@ | |||
1 | use std::sync::Arc; | ||
2 | use { | ||
3 | FileId, | ||
4 | db::{ | ||
5 | Query, QueryRegistry, QueryCtx, | ||
6 | file_syntax, file_set | ||
7 | }, | ||
8 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor} | ||
9 | }; | ||
10 | |||
11 | pub(crate) fn register_queries(reg: &mut QueryRegistry) { | ||
12 | reg.add(MODULE_DESCR, "MODULE_DESCR"); | ||
13 | } | ||
14 | |||
15 | pub(crate) fn module_tree(ctx: QueryCtx) -> Arc<ModuleTreeDescriptor> { | ||
16 | ctx.get(MODULE_TREE, ()) | ||
17 | } | ||
18 | |||
19 | impl<'a> QueryCtx<'a> { | ||
20 | fn module_descr(&self, file_id: FileId) -> Arc<ModuleDescriptor> { | ||
21 | self.get(MODULE_DESCR, file_id) | ||
22 | } | ||
23 | } | ||
24 | |||
25 | const MODULE_DESCR: Query<FileId, ModuleDescriptor> = Query(30, |ctx, &file_id| { | ||
26 | let file = file_syntax(ctx, file_id); | ||
27 | ModuleDescriptor::new(file.ast()) | ||
28 | }); | ||
29 | |||
30 | const MODULE_TREE: Query<(), ModuleTreeDescriptor> = Query(31, |ctx, _| { | ||
31 | let file_set = file_set(ctx); | ||
32 | let mut files = Vec::new(); | ||
33 | for &file_id in file_set.0.iter() { | ||
34 | let module_descr = ctx.get(MODULE_DESCR, file_id); | ||
35 | files.push((file_id, module_descr)); | ||
36 | } | ||
37 | ModuleTreeDescriptor::new(files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.1) | ||
38 | }); | ||
39 | |||
40 | #[cfg(test)] | ||
41 | mod tests { | ||
42 | use std::collections::HashMap; | ||
43 | use im; | ||
44 | use relative_path::{RelativePath, RelativePathBuf}; | ||
45 | use { | ||
46 | db::{Query, Db, State}, | ||
47 | imp::FileResolverImp, | ||
48 | FileId, FileResolver, | ||
49 | }; | ||
50 | use super::*; | ||
51 | |||
52 | #[derive(Debug)] | ||
53 | struct FileMap(im::HashMap<FileId, RelativePathBuf>); | ||
54 | |||
55 | impl FileResolver for FileMap { | ||
56 | fn file_stem(&self, file_id: FileId) -> String { | ||
57 | self.0[&file_id].file_stem().unwrap().to_string() | ||
58 | } | ||
59 | fn resolve(&self, file_id: FileId, rel: &RelativePath) -> Option<FileId> { | ||
60 | let path = self.0[&file_id].join(rel).normalize(); | ||
61 | self.0.iter() | ||
62 | .filter_map(|&(id, ref p)| Some(id).filter(|_| p == &path)) | ||
63 | .next() | ||
64 | } | ||
65 | } | ||
66 | |||
67 | struct Fixture { | ||
68 | next_file_id: u32, | ||
69 | fm: im::HashMap<FileId, RelativePathBuf>, | ||
70 | db: Db, | ||
71 | } | ||
72 | |||
73 | impl Fixture { | ||
74 | fn new() -> Fixture { | ||
75 | Fixture { | ||
76 | next_file_id: 1, | ||
77 | fm: im::HashMap::new(), | ||
78 | db: Db::new(), | ||
79 | } | ||
80 | } | ||
81 | fn add_file(&mut self, path: &str, text: &str) -> FileId { | ||
82 | assert!(path.starts_with("/")); | ||
83 | let file_id = FileId(self.next_file_id); | ||
84 | self.next_file_id += 1; | ||
85 | self.fm.insert(file_id, RelativePathBuf::from(&path[1..])); | ||
86 | let mut new_state = self.db.state().clone(); | ||
87 | new_state.file_map.insert(file_id, Arc::new(text.to_string())); | ||
88 | new_state.file_resolver = FileResolverImp::new( | ||
89 | Arc::new(FileMap(self.fm.clone())) | ||
90 | ); | ||
91 | self.db = self.db.with_changes(new_state, &[file_id], true); | ||
92 | file_id | ||
93 | } | ||
94 | fn remove_file(&mut self, file_id: FileId) { | ||
95 | self.fm.remove(&file_id); | ||
96 | let mut new_state = self.db.state().clone(); | ||
97 | new_state.file_map.remove(&file_id); | ||
98 | new_state.file_resolver = FileResolverImp::new( | ||
99 | Arc::new(FileMap(self.fm.clone())) | ||
100 | ); | ||
101 | self.db = self.db.with_changes(new_state, &[file_id], true); | ||
102 | } | ||
103 | fn change_file(&mut self, file_id: FileId, new_text: &str) { | ||
104 | let mut new_state = self.db.state().clone(); | ||
105 | new_state.file_map.insert(file_id, Arc::new(new_text.to_string())); | ||
106 | self.db = self.db.with_changes(new_state, &[file_id], false); | ||
107 | } | ||
108 | fn check_parent_modules( | ||
109 | &self, | ||
110 | file_id: FileId, | ||
111 | expected: &[FileId], | ||
112 | queries: &[(&'static str, u64)] | ||
113 | ) { | ||
114 | let (actual, events) = self.db.trace_query(|ctx| { | ||
115 | ctx.get(PARENT_MODULE, file_id) | ||
116 | }); | ||
117 | assert_eq!(actual.as_slice(), expected); | ||
118 | let mut counts = HashMap::new(); | ||
119 | events.into_iter() | ||
120 | .for_each(|event| *counts.entry(event).or_insert(0) += 1); | ||
121 | for &(query_id, expected_count) in queries.iter() { | ||
122 | let actual_count = *counts.get(&query_id).unwrap_or(&0); | ||
123 | assert_eq!( | ||
124 | actual_count, | ||
125 | expected_count, | ||
126 | "counts for {} differ", | ||
127 | query_id, | ||
128 | ) | ||
129 | } | ||
130 | |||
131 | } | ||
132 | } | ||
133 | |||
134 | #[test] | ||
135 | fn test_parent_module() { | ||
136 | let mut f = Fixture::new(); | ||
137 | let foo = f.add_file("/foo.rs", ""); | ||
138 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); | ||
139 | |||
140 | let lib = f.add_file("/lib.rs", "mod foo;"); | ||
141 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); | ||
142 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 0)]); | ||
143 | |||
144 | f.change_file(lib, ""); | ||
145 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); | ||
146 | |||
147 | f.change_file(lib, "mod foo;"); | ||
148 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); | ||
149 | |||
150 | f.change_file(lib, "mod bar;"); | ||
151 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); | ||
152 | |||
153 | f.change_file(lib, "mod foo;"); | ||
154 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); | ||
155 | |||
156 | f.remove_file(lib); | ||
157 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 0)]); | ||
158 | } | ||
159 | } | ||
diff --git a/crates/libanalysis/src/queries.rs b/crates/libanalysis/src/queries.rs new file mode 100644 index 000000000..9d6754fd4 --- /dev/null +++ b/crates/libanalysis/src/queries.rs | |||
@@ -0,0 +1,28 @@ | |||
1 | use std::sync::Arc; | ||
2 | use libsyntax2::File; | ||
3 | use libeditor::LineIndex; | ||
4 | use { | ||
5 | FileId, | ||
6 | db::{Query, QueryCtx, QueryRegistry, file_text}, | ||
7 | }; | ||
8 | |||
9 | pub(crate) fn register_queries(reg: &mut QueryRegistry) { | ||
10 | reg.add(FILE_SYNTAX, "FILE_SYNTAX"); | ||
11 | reg.add(FILE_LINES, "FILE_LINES"); | ||
12 | } | ||
13 | |||
14 | pub(crate) fn file_syntax(ctx: QueryCtx, file_id: FileId) -> File { | ||
15 | (&*ctx.get(FILE_SYNTAX, file_id)).clone() | ||
16 | } | ||
17 | pub(crate) fn file_lines(ctx: QueryCtx, file_id: FileId) -> Arc<LineIndex> { | ||
18 | ctx.get(FILE_LINES, file_id) | ||
19 | } | ||
20 | |||
21 | const FILE_SYNTAX: Query<FileId, File> = Query(16, |ctx, file_id: &FileId| { | ||
22 | let text = file_text(ctx, *file_id); | ||
23 | File::parse(&*text) | ||
24 | }); | ||
25 | const FILE_LINES: Query<FileId, LineIndex> = Query(17, |ctx, file_id: &FileId| { | ||
26 | let text = file_text(ctx, *file_id); | ||
27 | LineIndex::new(&*text) | ||
28 | }); | ||
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs index e9527eeff..0e7253ba2 100644 --- a/crates/libanalysis/src/roots.rs +++ b/crates/libanalysis/src/roots.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | collections::HashMap, | 2 | collections::HashMap, |
3 | time::Instant, | ||
4 | sync::Arc, | 3 | sync::Arc, |
5 | panic, | 4 | panic, |
6 | }; | 5 | }; |
@@ -13,83 +12,74 @@ use libsyntax2::File; | |||
13 | use { | 12 | use { |
14 | FileId, | 13 | FileId, |
15 | imp::FileResolverImp, | 14 | imp::FileResolverImp, |
16 | module_map::{ModuleMap, ChangeKind}, | ||
17 | symbol_index::SymbolIndex, | 15 | symbol_index::SymbolIndex, |
18 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | 16 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, |
17 | db::Db, | ||
19 | }; | 18 | }; |
20 | 19 | ||
21 | pub(crate) trait SourceRoot { | 20 | pub(crate) trait SourceRoot { |
22 | fn contains(&self, file_id: FileId) -> bool; | 21 | fn contains(&self, file_id: FileId) -> bool; |
23 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor> { | 22 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor>; |
24 | unimplemented!() | 23 | fn lines(&self, file_id: FileId) -> Arc<LineIndex>; |
25 | } | 24 | fn syntax(&self, file_id: FileId) -> File; |
26 | // fn module_map(&self) -> &ModuleMap; | ||
27 | fn lines(&self, file_id: FileId) -> &LineIndex; | ||
28 | fn syntax(&self, file_id: FileId) -> &File; | ||
29 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>); | 25 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>); |
30 | } | 26 | } |
31 | 27 | ||
32 | #[derive(Clone, Default, Debug)] | 28 | #[derive(Default, Debug)] |
33 | pub(crate) struct WritableSourceRoot { | 29 | pub(crate) struct WritableSourceRoot { |
34 | file_map: HashMap<FileId, Arc<(FileData, OnceCell<SymbolIndex>)>>, | 30 | db: Db, |
35 | module_map: ModuleMap, | ||
36 | } | 31 | } |
37 | 32 | ||
38 | impl WritableSourceRoot { | 33 | impl WritableSourceRoot { |
39 | pub fn update(&mut self, file_id: FileId, text: Option<String>) { | 34 | pub fn apply_changes( |
40 | let change_kind = if self.file_map.remove(&file_id).is_some() { | 35 | &self, |
41 | if text.is_some() { | 36 | changes: &mut dyn Iterator<Item=(FileId, Option<String>)>, |
42 | ChangeKind::Update | 37 | file_resolver: Option<FileResolverImp>, |
43 | } else { | 38 | ) -> WritableSourceRoot { |
44 | ChangeKind::Delete | 39 | let resolver_changed = file_resolver.is_some(); |
40 | let mut changed_files = Vec::new(); | ||
41 | let mut new_state = self.db.state().clone(); | ||
42 | |||
43 | for (file_id, text) in changes { | ||
44 | changed_files.push(file_id); | ||
45 | match text { | ||
46 | Some(text) => { | ||
47 | new_state.file_map.insert(file_id, Arc::new(text)); | ||
48 | }, | ||
49 | None => { | ||
50 | new_state.file_map.remove(&file_id); | ||
51 | } | ||
45 | } | 52 | } |
46 | } else { | ||
47 | ChangeKind::Insert | ||
48 | }; | ||
49 | self.module_map.update_file(file_id, change_kind); | ||
50 | self.file_map.remove(&file_id); | ||
51 | if let Some(text) = text { | ||
52 | let file_data = FileData::new(text); | ||
53 | self.file_map.insert(file_id, Arc::new((file_data, Default::default()))); | ||
54 | } | 53 | } |
55 | } | 54 | if let Some(file_resolver) = file_resolver { |
56 | pub fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { | 55 | new_state.file_resolver = file_resolver |
57 | self.module_map.set_file_resolver(file_resolver) | 56 | } |
58 | } | 57 | WritableSourceRoot { |
59 | pub fn reindex(&self) { | 58 | db: self.db.with_changes(new_state, &changed_files, resolver_changed) |
60 | let now = Instant::now(); | ||
61 | self.file_map | ||
62 | .par_iter() | ||
63 | .for_each(|(&file_id, data)| { | ||
64 | symbols(file_id, data); | ||
65 | }); | ||
66 | info!("parallel indexing took {:?}", now.elapsed()); | ||
67 | |||
68 | } | ||
69 | fn data(&self, file_id: FileId) -> &FileData { | ||
70 | match self.file_map.get(&file_id) { | ||
71 | Some(data) => &data.0, | ||
72 | None => panic!("unknown file: {:?}", file_id), | ||
73 | } | 59 | } |
74 | } | 60 | } |
75 | } | 61 | } |
76 | 62 | ||
77 | impl SourceRoot for WritableSourceRoot { | 63 | impl SourceRoot for WritableSourceRoot { |
64 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor> { | ||
65 | self.db.make_query(::module_map::module_tree) | ||
66 | } | ||
67 | |||
78 | fn contains(&self, file_id: FileId) -> bool { | 68 | fn contains(&self, file_id: FileId) -> bool { |
79 | self.file_map.contains_key(&file_id) | 69 | self.db.state().file_map.contains_key(&file_id) |
80 | } | 70 | } |
81 | fn lines(&self, file_id: FileId) -> &LineIndex { | 71 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { |
82 | self.data(file_id).lines() | 72 | self.db.make_query(|ctx| ::queries::file_lines(ctx, file_id)) |
83 | } | 73 | } |
84 | fn syntax(&self, file_id: FileId) -> &File { | 74 | fn syntax(&self, file_id: FileId) -> File { |
85 | self.data(file_id).syntax() | 75 | self.db.make_query(|ctx| ::queries::file_syntax(ctx, file_id)) |
86 | } | 76 | } |
87 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { | 77 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { |
88 | acc.extend( | 78 | // acc.extend( |
89 | self.file_map | 79 | // self.file_map |
90 | .iter() | 80 | // .iter() |
91 | .map(|(&file_id, data)| symbols(file_id, data)) | 81 | // .map(|(&file_id, data)| symbols(file_id, data)) |
92 | ) | 82 | // ) |
93 | } | 83 | } |
94 | } | 84 | } |
95 | 85 | ||
@@ -101,7 +91,7 @@ fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<SymbolIndex>)) | |||
101 | #[derive(Debug)] | 91 | #[derive(Debug)] |
102 | struct FileData { | 92 | struct FileData { |
103 | text: String, | 93 | text: String, |
104 | lines: OnceCell<LineIndex>, | 94 | lines: OnceCell<Arc<LineIndex>>, |
105 | syntax: OnceCell<File>, | 95 | syntax: OnceCell<File>, |
106 | } | 96 | } |
107 | 97 | ||
@@ -113,8 +103,8 @@ impl FileData { | |||
113 | lines: OnceCell::new(), | 103 | lines: OnceCell::new(), |
114 | } | 104 | } |
115 | } | 105 | } |
116 | fn lines(&self) -> &LineIndex { | 106 | fn lines(&self) -> &Arc<LineIndex> { |
117 | self.lines.get_or_init(|| LineIndex::new(&self.text)) | 107 | self.lines.get_or_init(|| Arc::new(LineIndex::new(&self.text))) |
118 | } | 108 | } |
119 | fn syntax(&self) -> &File { | 109 | fn syntax(&self) -> &File { |
120 | let text = &self.text; | 110 | let text = &self.text; |
@@ -127,10 +117,6 @@ impl FileData { | |||
127 | } | 117 | } |
128 | } | 118 | } |
129 | } | 119 | } |
130 | fn syntax_transient(&self) -> File { | ||
131 | self.syntax.get().map(|s| s.clone()) | ||
132 | .unwrap_or_else(|| File::parse(&self.text)) | ||
133 | } | ||
134 | } | 120 | } |
135 | 121 | ||
136 | #[derive(Debug)] | 122 | #[derive(Debug)] |
@@ -184,11 +170,11 @@ impl SourceRoot for ReadonlySourceRoot { | |||
184 | fn contains(&self, file_id: FileId) -> bool { | 170 | fn contains(&self, file_id: FileId) -> bool { |
185 | self.file_map.contains_key(&file_id) | 171 | self.file_map.contains_key(&file_id) |
186 | } | 172 | } |
187 | fn lines(&self, file_id: FileId) -> &LineIndex { | 173 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { |
188 | self.data(file_id).lines() | 174 | Arc::clone(self.data(file_id).lines()) |
189 | } | 175 | } |
190 | fn syntax(&self, file_id: FileId) -> &File { | 176 | fn syntax(&self, file_id: FileId) -> File { |
191 | self.data(file_id).syntax() | 177 | self.data(file_id).syntax().clone() |
192 | } | 178 | } |
193 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { | 179 | fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { |
194 | acc.push(&self.symbol_index) | 180 | acc.push(&self.symbol_index) |