diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-09-15 22:11:25 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-09-15 22:11:25 +0100 |
commit | 3993bb4de95af407e5edc1fe551bec0f001a3f0f (patch) | |
tree | 31893552cd739187080048df24a629d416174305 /crates/libanalysis/src/imp.rs | |
parent | 2a56b5c4f096736d6795eecb835cc2dc14b00107 (diff) | |
parent | fcdf3a52b4b61a39474950486ea0edf5ebf33bea (diff) |
Merge #67
67: Salsa r=matklad a=matklad
The aim of this PR is to transition from rather ad-hock FileData and ModuleMap caching strategy to something resembling a general-purpose red-green engine.
Ideally, we shouldn't recompute ModuleMap at all, unless the set of mod decls or files changes.
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/libanalysis/src/imp.rs')
-rw-r--r-- | crates/libanalysis/src/imp.rs | 146 |
1 files changed, 62 insertions, 84 deletions
diff --git a/crates/libanalysis/src/imp.rs b/crates/libanalysis/src/imp.rs index 3e65ee14a..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; |
@@ -18,8 +19,8 @@ use libsyntax2::{ | |||
18 | use { | 19 | use { |
19 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, | 20 | FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit, |
20 | JobToken, CrateGraph, CrateId, | 21 | JobToken, CrateGraph, CrateId, |
21 | module_map::{ModuleMap, Problem}, | ||
22 | roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, | 22 | roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot}, |
23 | descriptors::{ModuleTreeDescriptor, Problem}, | ||
23 | }; | 24 | }; |
24 | 25 | ||
25 | 26 | ||
@@ -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() |
@@ -148,25 +146,24 @@ impl AnalysisImpl { | |||
148 | } | 146 | } |
149 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { | 147 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { |
150 | let root = self.root(file_id); | 148 | let root = self.root(file_id); |
151 | let module_map = root.module_map(); | 149 | let module_tree = root.module_tree(); |
152 | let id = module_map.file2module(file_id); | 150 | module_tree.parent_modules(file_id) |
153 | module_map | 151 | .iter() |
154 | .parent_modules(id, &|file_id| root.syntax(file_id)) | 152 | .map(|link| { |
155 | .into_iter() | 153 | let file_id = link.owner(&module_tree); |
156 | .map(|(id, name, node)| { | 154 | let syntax = root.syntax(file_id); |
157 | let id = module_map.module2file(id); | 155 | let decl = link.bind_source(&module_tree, syntax.ast()); |
158 | let sym = FileSymbol { | 156 | let sym = FileSymbol { |
159 | name, | 157 | name: link.name(&module_tree), |
160 | node_range: node.range(), | 158 | node_range: decl.syntax().range(), |
161 | kind: MODULE, | 159 | kind: MODULE, |
162 | }; | 160 | }; |
163 | (id, sym) | 161 | (file_id, sym) |
164 | }) | 162 | }) |
165 | .collect() | 163 | .collect() |
166 | } | 164 | } |
167 | |||
168 | pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> { | 165 | pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> { |
169 | let module_map = self.root(file_id).module_map(); | 166 | let module_tree = self.root(file_id).module_tree(); |
170 | let crate_graph = &self.data.crate_graph; | 167 | let crate_graph = &self.data.crate_graph; |
171 | let mut res = Vec::new(); | 168 | let mut res = Vec::new(); |
172 | let mut work = VecDeque::new(); | 169 | let mut work = VecDeque::new(); |
@@ -177,11 +174,10 @@ impl AnalysisImpl { | |||
177 | res.push(crate_id); | 174 | res.push(crate_id); |
178 | continue; | 175 | continue; |
179 | } | 176 | } |
180 | let mid = module_map.file2module(id); | 177 | let parents = module_tree |
181 | let parents = module_map | 178 | .parent_modules(id) |
182 | .parent_module_ids(mid, &|file_id| self.file_syntax(file_id)) | ||
183 | .into_iter() | 179 | .into_iter() |
184 | .map(|id| module_map.module2file(id)) | 180 | .map(|link| link.owner(&module_tree)) |
185 | .filter(|&id| visited.insert(id)); | 181 | .filter(|&id| visited.insert(id)); |
186 | work.extend(parents); | 182 | work.extend(parents); |
187 | } | 183 | } |
@@ -197,7 +193,7 @@ impl AnalysisImpl { | |||
197 | token: &JobToken, | 193 | token: &JobToken, |
198 | ) -> Vec<(FileId, FileSymbol)> { | 194 | ) -> Vec<(FileId, FileSymbol)> { |
199 | let root = self.root(file_id); | 195 | let root = self.root(file_id); |
200 | let module_map = root.module_map(); | 196 | let module_tree = root.module_tree(); |
201 | let file = root.syntax(file_id); | 197 | let file = root.syntax(file_id); |
202 | let syntax = file.syntax(); | 198 | let syntax = file.syntax(); |
203 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 199 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
@@ -206,7 +202,7 @@ impl AnalysisImpl { | |||
206 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { | 202 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { |
207 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 203 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
208 | if module.has_semi() { | 204 | if module.has_semi() { |
209 | let file_ids = self.resolve_module(module_map, file_id, module); | 205 | let file_ids = self.resolve_module(&*module_tree, file_id, module); |
210 | 206 | ||
211 | let res = file_ids.into_iter().map(|id| { | 207 | let res = file_ids.into_iter().map(|id| { |
212 | let name = module.name() | 208 | let name = module.name() |
@@ -229,7 +225,7 @@ impl AnalysisImpl { | |||
229 | 225 | ||
230 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { | 226 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { |
231 | let root = self.root(file_id); | 227 | let root = self.root(file_id); |
232 | let module_map = root.module_map(); | 228 | let module_tree = root.module_tree(); |
233 | let syntax = root.syntax(file_id); | 229 | let syntax = root.syntax(file_id); |
234 | 230 | ||
235 | let mut res = libeditor::diagnostics(&syntax) | 231 | let mut res = libeditor::diagnostics(&syntax) |
@@ -237,47 +233,43 @@ impl AnalysisImpl { | |||
237 | .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) | 233 | .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) |
238 | .collect::<Vec<_>>(); | 234 | .collect::<Vec<_>>(); |
239 | 235 | ||
240 | module_map.problems( | 236 | for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) { |
241 | file_id, | 237 | let diag = match problem { |
242 | &|file_id| self.file_syntax(file_id), | 238 | Problem::UnresolvedModule { candidate } => { |
243 | |name_node, problem| { | 239 | let create_file = FileSystemEdit::CreateFile { |
244 | let diag = match problem { | 240 | anchor: file_id, |
245 | Problem::UnresolvedModule { candidate } => { | 241 | path: candidate.clone(), |
246 | let create_file = FileSystemEdit::CreateFile { | 242 | }; |
247 | anchor: file_id, | 243 | let fix = SourceChange { |
248 | path: candidate.clone(), | 244 | label: "create module".to_string(), |
249 | }; | 245 | source_file_edits: Vec::new(), |
250 | let fix = SourceChange { | 246 | file_system_edits: vec![create_file], |
251 | label: "create module".to_string(), | 247 | cursor_position: None, |
252 | source_file_edits: Vec::new(), | 248 | }; |
253 | file_system_edits: vec![create_file], | 249 | Diagnostic { |
254 | cursor_position: None, | 250 | range: name_node.syntax().range(), |
255 | }; | 251 | message: "unresolved module".to_string(), |
256 | Diagnostic { | 252 | fix: Some(fix), |
257 | range: name_node.syntax().range(), | ||
258 | message: "unresolved module".to_string(), | ||
259 | fix: Some(fix), | ||
260 | } | ||
261 | } | 253 | } |
262 | Problem::NotDirOwner { move_to, candidate } => { | 254 | } |
263 | let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() }; | 255 | Problem::NotDirOwner { move_to, candidate } => { |
264 | let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) }; | 256 | let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() }; |
265 | let fix = SourceChange { | 257 | let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) }; |
266 | label: "move file and create module".to_string(), | 258 | let fix = SourceChange { |
267 | source_file_edits: Vec::new(), | 259 | label: "move file and create module".to_string(), |
268 | file_system_edits: vec![move_file, create_file], | 260 | source_file_edits: Vec::new(), |
269 | cursor_position: None, | 261 | file_system_edits: vec![move_file, create_file], |
270 | }; | 262 | cursor_position: None, |
271 | Diagnostic { | 263 | }; |
272 | range: name_node.syntax().range(), | 264 | Diagnostic { |
273 | message: "can't declare module at this location".to_string(), | 265 | range: name_node.syntax().range(), |
274 | fix: Some(fix), | 266 | message: "can't declare module at this location".to_string(), |
275 | } | 267 | fix: Some(fix), |
276 | } | 268 | } |
277 | }; | 269 | } |
278 | res.push(diag) | 270 | }; |
279 | } | 271 | res.push(diag) |
280 | ); | 272 | } |
281 | res | 273 | res |
282 | } | 274 | } |
283 | 275 | ||
@@ -307,26 +299,12 @@ impl AnalysisImpl { | |||
307 | self.world_symbols(query, token) | 299 | self.world_symbols(query, token) |
308 | } | 300 | } |
309 | 301 | ||
310 | fn resolve_module(&self, module_map: &ModuleMap, file_id: FileId, module: ast::Module) -> Vec<FileId> { | 302 | fn resolve_module(&self, module_tree: &ModuleTreeDescriptor, file_id: FileId, module: ast::Module) -> Vec<FileId> { |
311 | let name = match module.name() { | 303 | let name = match module.name() { |
312 | Some(name) => name.text(), | 304 | Some(name) => name.text(), |
313 | None => return Vec::new(), | 305 | None => return Vec::new(), |
314 | }; | 306 | }; |
315 | let id = module_map.file2module(file_id); | 307 | module_tree.child_module_by_name(file_id, name.as_str()) |
316 | module_map | ||
317 | .child_module_by_name( | ||
318 | id, name.as_str(), | ||
319 | &|file_id| self.file_syntax(file_id), | ||
320 | ) | ||
321 | .into_iter() | ||
322 | .map(|id| module_map.module2file(id)) | ||
323 | .collect() | ||
324 | } | ||
325 | |||
326 | fn reindex(&self) { | ||
327 | if self.needs_reindex.compare_and_swap(true, false, SeqCst) { | ||
328 | self.data.root.reindex(); | ||
329 | } | ||
330 | } | 308 | } |
331 | } | 309 | } |
332 | 310 | ||
@@ -334,7 +312,7 @@ impl AnalysisImpl { | |||
334 | struct WorldData { | 312 | struct WorldData { |
335 | file_resolver: FileResolverImp, | 313 | file_resolver: FileResolverImp, |
336 | crate_graph: CrateGraph, | 314 | crate_graph: CrateGraph, |
337 | root: WritableSourceRoot, | 315 | root: Arc<WritableSourceRoot>, |
338 | libs: Vec<Arc<ReadonlySourceRoot>>, | 316 | libs: Vec<Arc<ReadonlySourceRoot>>, |
339 | } | 317 | } |
340 | 318 | ||