diff options
Diffstat (limited to 'crates/ra_analysis/src/imp.rs')
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 184 |
1 files changed, 104 insertions, 80 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index f3e5b2887..5a6e2450d 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -1,7 +1,5 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | fmt, | ||
3 | hash::{Hash, Hasher}, | 2 | hash::{Hash, Hasher}, |
4 | iter, | ||
5 | sync::Arc, | 3 | sync::Arc, |
6 | }; | 4 | }; |
7 | 5 | ||
@@ -14,12 +12,17 @@ use ra_syntax::{ | |||
14 | }; | 12 | }; |
15 | use relative_path::RelativePath; | 13 | use relative_path::RelativePath; |
16 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
15 | use salsa::{ParallelDatabase, Database}; | ||
17 | 16 | ||
18 | use crate::{ | 17 | use crate::{ |
19 | db::SyntaxDatabase, | 18 | AnalysisChange, |
19 | db::{ | ||
20 | self, SyntaxDatabase, | ||
21 | |||
22 | }, | ||
23 | input::{SourceRootId, FilesDatabase, SourceRoot, WORKSPACE}, | ||
20 | descriptors::module::{ModulesDatabase, ModuleTree, Problem}, | 24 | descriptors::module::{ModulesDatabase, ModuleTree, Problem}, |
21 | descriptors::{FnDescriptor}, | 25 | descriptors::{FnDescriptor}, |
22 | roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot}, | ||
23 | CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position, | 26 | CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position, |
24 | Query, SourceChange, SourceFileEdit, Cancelable, | 27 | Query, SourceChange, SourceFileEdit, Cancelable, |
25 | }; | 28 | }; |
@@ -80,96 +83,128 @@ impl Default for FileResolverImp { | |||
80 | } | 83 | } |
81 | } | 84 | } |
82 | 85 | ||
83 | #[derive(Debug)] | 86 | #[derive(Debug, Default)] |
84 | pub(crate) struct AnalysisHostImpl { | 87 | pub(crate) struct AnalysisHostImpl { |
85 | data: WorldData, | 88 | db: db::RootDatabase, |
86 | } | 89 | } |
87 | 90 | ||
91 | |||
88 | impl AnalysisHostImpl { | 92 | impl AnalysisHostImpl { |
89 | pub fn new() -> AnalysisHostImpl { | 93 | pub fn new() -> AnalysisHostImpl { |
90 | AnalysisHostImpl { | 94 | AnalysisHostImpl::default() |
91 | data: WorldData::default(), | ||
92 | } | ||
93 | } | 95 | } |
94 | pub fn analysis(&self) -> AnalysisImpl { | 96 | pub fn analysis(&self) -> AnalysisImpl { |
95 | AnalysisImpl { | 97 | AnalysisImpl { |
96 | data: self.data.clone(), | 98 | db: self.db.fork() // freeze revision here |
97 | } | 99 | } |
98 | } | 100 | } |
99 | pub fn change_files(&mut self, changes: &mut dyn Iterator<Item = (FileId, Option<String>)>) { | 101 | pub fn apply_change(&mut self, change: AnalysisChange) { |
100 | self.data_mut().root.apply_changes(changes, None); | 102 | log::info!("apply_change {:?}", change); |
101 | } | 103 | |
102 | pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { | 104 | for (file_id, text) in change.files_changed { |
103 | self.data_mut() | 105 | self.db |
104 | .root | 106 | .query(crate::input::FileTextQuery) |
105 | .apply_changes(&mut iter::empty(), Some(resolver)); | 107 | .set(file_id, Arc::new(text)) |
106 | } | 108 | } |
107 | pub fn set_crate_graph(&mut self, graph: CrateGraph) { | 109 | if !(change.files_added.is_empty() && change.files_removed.is_empty()) { |
108 | let mut visited = FxHashSet::default(); | 110 | let file_resolver = change.file_resolver |
109 | for &file_id in graph.crate_roots.values() { | 111 | .expect("change resolver when changing set of files"); |
110 | if !visited.insert(file_id) { | 112 | let mut source_root = SourceRoot::clone(&self.db.source_root(WORKSPACE)); |
111 | panic!("duplicate crate root: {:?}", file_id); | 113 | for (file_id, text) in change.files_added { |
114 | self.db | ||
115 | .query(crate::input::FileTextQuery) | ||
116 | .set(file_id, Arc::new(text)); | ||
117 | self.db | ||
118 | .query(crate::input::FileSourceRootQuery) | ||
119 | .set(file_id, crate::input::WORKSPACE); | ||
120 | source_root.files.insert(file_id); | ||
121 | } | ||
122 | for file_id in change.files_removed { | ||
123 | self.db | ||
124 | .query(crate::input::FileTextQuery) | ||
125 | .set(file_id, Arc::new(String::new())); | ||
126 | source_root.files.remove(&file_id); | ||
112 | } | 127 | } |
128 | source_root.file_resolver = file_resolver; | ||
129 | self.db | ||
130 | .query(crate::input::SourceRootQuery) | ||
131 | .set(WORKSPACE, Arc::new(source_root)) | ||
132 | } | ||
133 | if !change.libraries_added.is_empty() { | ||
134 | let mut libraries = Vec::clone(&self.db.libraries()); | ||
135 | for library in change.libraries_added { | ||
136 | let source_root_id = SourceRootId(1 + libraries.len() as u32); | ||
137 | libraries.push(source_root_id); | ||
138 | let mut files = FxHashSet::default(); | ||
139 | for (file_id, text) in library.files { | ||
140 | files.insert(file_id); | ||
141 | self.db | ||
142 | .query(crate::input::FileSourceRootQuery) | ||
143 | .set_constant(file_id, source_root_id); | ||
144 | self.db | ||
145 | .query(crate::input::FileTextQuery) | ||
146 | .set_constant(file_id, Arc::new(text)); | ||
147 | } | ||
148 | let source_root = SourceRoot { | ||
149 | files, | ||
150 | file_resolver: library.file_resolver, | ||
151 | }; | ||
152 | self.db | ||
153 | .query(crate::input::SourceRootQuery) | ||
154 | .set(source_root_id, Arc::new(source_root)); | ||
155 | self.db | ||
156 | .query(crate::input::LibrarySymbolsQuery) | ||
157 | .set(source_root_id, Arc::new(library.symbol_index)); | ||
158 | } | ||
159 | self.db | ||
160 | .query(crate::input::LibrarieseQuery) | ||
161 | .set((), Arc::new(libraries)); | ||
162 | } | ||
163 | if let Some(crate_graph) = change.crate_graph { | ||
164 | self.db.query(crate::input::CrateGraphQuery) | ||
165 | .set((), Arc::new(crate_graph)) | ||
113 | } | 166 | } |
114 | self.data_mut().crate_graph = graph; | ||
115 | } | ||
116 | pub fn add_library(&mut self, root: ReadonlySourceRoot) { | ||
117 | self.data_mut().libs.push(root); | ||
118 | } | ||
119 | fn data_mut(&mut self) -> &mut WorldData { | ||
120 | &mut self.data | ||
121 | } | 167 | } |
122 | } | 168 | } |
123 | 169 | ||
170 | #[derive(Debug)] | ||
124 | pub(crate) struct AnalysisImpl { | 171 | pub(crate) struct AnalysisImpl { |
125 | data: WorldData, | 172 | db: db::RootDatabase, |
126 | } | ||
127 | |||
128 | impl fmt::Debug for AnalysisImpl { | ||
129 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
130 | self.data.fmt(f) | ||
131 | } | ||
132 | } | 173 | } |
133 | 174 | ||
134 | impl AnalysisImpl { | 175 | impl AnalysisImpl { |
135 | fn root(&self, file_id: FileId) -> &SourceRoot { | ||
136 | if self.data.root.contains(file_id) { | ||
137 | return &self.data.root; | ||
138 | } | ||
139 | self | ||
140 | .data | ||
141 | .libs | ||
142 | .iter() | ||
143 | .find(|it| it.contains(file_id)) | ||
144 | .unwrap() | ||
145 | } | ||
146 | pub fn file_syntax(&self, file_id: FileId) -> File { | 176 | pub fn file_syntax(&self, file_id: FileId) -> File { |
147 | self.root(file_id).db().file_syntax(file_id) | 177 | self.db.file_syntax(file_id) |
148 | } | 178 | } |
149 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { | 179 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
150 | self.root(file_id).db().file_lines(file_id) | 180 | self.db.file_lines(file_id) |
151 | } | 181 | } |
152 | pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 182 | pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
153 | let mut buf = Vec::new(); | 183 | let mut buf = Vec::new(); |
154 | if query.libs { | 184 | if query.libs { |
155 | for lib in self.data.libs.iter() { | 185 | for &lib_id in self.db.libraries().iter() { |
156 | lib.symbols(&mut buf)?; | 186 | buf.push(self.db.library_symbols(lib_id)); |
157 | } | 187 | } |
158 | } else { | 188 | } else { |
159 | self.data.root.symbols(&mut buf)?; | 189 | for &file_id in self.db.source_root(WORKSPACE).files.iter() { |
190 | buf.push(self.db.file_symbols(file_id)?); | ||
191 | } | ||
160 | } | 192 | } |
161 | Ok(query.search(&buf)) | 193 | Ok(query.search(&buf)) |
162 | } | 194 | } |
195 | fn module_tree(&self, file_id: FileId) -> Cancelable<Arc<ModuleTree>> { | ||
196 | let source_root = self.db.file_source_root(file_id); | ||
197 | self.db.module_tree(source_root) | ||
198 | } | ||
163 | pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 199 | pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
164 | let root = self.root(file_id); | 200 | let module_tree = self.module_tree(file_id)?; |
165 | let module_tree = root.db().module_tree()?; | ||
166 | 201 | ||
167 | let res = module_tree.modules_for_file(file_id) | 202 | let res = module_tree.modules_for_file(file_id) |
168 | .into_iter() | 203 | .into_iter() |
169 | .filter_map(|module_id| { | 204 | .filter_map(|module_id| { |
170 | let link = module_id.parent_link(&module_tree)?; | 205 | let link = module_id.parent_link(&module_tree)?; |
171 | let file_id = link.owner(&module_tree).file_id(&module_tree); | 206 | let file_id = link.owner(&module_tree).file_id(&module_tree); |
172 | let syntax = root.db().file_syntax(file_id); | 207 | let syntax = self.db.file_syntax(file_id); |
173 | let decl = link.bind_source(&module_tree, syntax.ast()); | 208 | let decl = link.bind_source(&module_tree, syntax.ast()); |
174 | 209 | ||
175 | let sym = FileSymbol { | 210 | let sym = FileSymbol { |
@@ -183,8 +218,8 @@ impl AnalysisImpl { | |||
183 | Ok(res) | 218 | Ok(res) |
184 | } | 219 | } |
185 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 220 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
186 | let module_tree = self.root(file_id).db().module_tree()?; | 221 | let module_tree = self.module_tree(file_id)?; |
187 | let crate_graph = &self.data.crate_graph; | 222 | let crate_graph = self.db.crate_graph(); |
188 | let res = module_tree.modules_for_file(file_id) | 223 | let res = module_tree.modules_for_file(file_id) |
189 | .into_iter() | 224 | .into_iter() |
190 | .map(|it| it.root(&module_tree)) | 225 | .map(|it| it.root(&module_tree)) |
@@ -195,7 +230,7 @@ impl AnalysisImpl { | |||
195 | Ok(res) | 230 | Ok(res) |
196 | } | 231 | } |
197 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 232 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { |
198 | self.data.crate_graph.crate_roots[&crate_id] | 233 | self.db.crate_graph().crate_roots[&crate_id] |
199 | } | 234 | } |
200 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { | 235 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { |
201 | let mut res = Vec::new(); | 236 | let mut res = Vec::new(); |
@@ -205,8 +240,7 @@ impl AnalysisImpl { | |||
205 | res.extend(scope_based); | 240 | res.extend(scope_based); |
206 | has_completions = true; | 241 | has_completions = true; |
207 | } | 242 | } |
208 | let root = self.root(file_id); | 243 | if let Some(scope_based) = crate::completion::resolve_based_completion(&self.db, file_id, offset)? { |
209 | if let Some(scope_based) = crate::completion::resolve_based_completion(root.db(), file_id, offset)? { | ||
210 | res.extend(scope_based); | 244 | res.extend(scope_based); |
211 | has_completions = true; | 245 | has_completions = true; |
212 | } | 246 | } |
@@ -222,9 +256,8 @@ impl AnalysisImpl { | |||
222 | file_id: FileId, | 256 | file_id: FileId, |
223 | offset: TextUnit, | 257 | offset: TextUnit, |
224 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 258 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
225 | let root = self.root(file_id); | 259 | let module_tree = self.module_tree(file_id)?; |
226 | let module_tree = root.db().module_tree()?; | 260 | let file = self.db.file_syntax(file_id); |
227 | let file = root.db().file_syntax(file_id); | ||
228 | let syntax = file.syntax(); | 261 | let syntax = file.syntax(); |
229 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 262 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
230 | // First try to resolve the symbol locally | 263 | // First try to resolve the symbol locally |
@@ -273,8 +306,7 @@ impl AnalysisImpl { | |||
273 | } | 306 | } |
274 | 307 | ||
275 | pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, TextRange)> { | 308 | pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, TextRange)> { |
276 | let root = self.root(file_id); | 309 | let file = self.db.file_syntax(file_id); |
277 | let file = root.db().file_syntax(file_id); | ||
278 | let syntax = file.syntax(); | 310 | let syntax = file.syntax(); |
279 | 311 | ||
280 | let mut ret = vec![]; | 312 | let mut ret = vec![]; |
@@ -305,9 +337,8 @@ impl AnalysisImpl { | |||
305 | } | 337 | } |
306 | 338 | ||
307 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 339 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
308 | let root = self.root(file_id); | 340 | let module_tree = self.module_tree(file_id)?; |
309 | let module_tree = root.db().module_tree()?; | 341 | let syntax = self.db.file_syntax(file_id); |
310 | let syntax = root.db().file_syntax(file_id); | ||
311 | 342 | ||
312 | let mut res = ra_editor::diagnostics(&syntax) | 343 | let mut res = ra_editor::diagnostics(&syntax) |
313 | .into_iter() | 344 | .into_iter() |
@@ -396,8 +427,7 @@ impl AnalysisImpl { | |||
396 | file_id: FileId, | 427 | file_id: FileId, |
397 | offset: TextUnit, | 428 | offset: TextUnit, |
398 | ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { | 429 | ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { |
399 | let root = self.root(file_id); | 430 | let file = self.db.file_syntax(file_id); |
400 | let file = root.db().file_syntax(file_id); | ||
401 | let syntax = file.syntax(); | 431 | let syntax = file.syntax(); |
402 | 432 | ||
403 | // Find the calling expression and it's NameRef | 433 | // Find the calling expression and it's NameRef |
@@ -412,9 +442,10 @@ impl AnalysisImpl { | |||
412 | 442 | ||
413 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). | 443 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). |
414 | let file_symbols = self.index_resolve(name_ref)?; | 444 | let file_symbols = self.index_resolve(name_ref)?; |
415 | for (_, fs) in file_symbols { | 445 | for (fn_fiel_id, fs) in file_symbols { |
416 | if fs.kind == FN_DEF { | 446 | if fs.kind == FN_DEF { |
417 | if let Some(fn_def) = find_node_at_offset(syntax, fs.node_range.start()) { | 447 | let fn_file = self.db.file_syntax(fn_fiel_id); |
448 | if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { | ||
418 | if let Some(descriptor) = FnDescriptor::new(fn_def) { | 449 | if let Some(descriptor) = FnDescriptor::new(fn_def) { |
419 | // If we have a calling expression let's find which argument we are on | 450 | // If we have a calling expression let's find which argument we are on |
420 | let mut current_parameter = None; | 451 | let mut current_parameter = None; |
@@ -491,13 +522,6 @@ impl AnalysisImpl { | |||
491 | } | 522 | } |
492 | } | 523 | } |
493 | 524 | ||
494 | #[derive(Default, Clone, Debug)] | ||
495 | struct WorldData { | ||
496 | crate_graph: CrateGraph, | ||
497 | root: WritableSourceRoot, | ||
498 | libs: Vec<ReadonlySourceRoot>, | ||
499 | } | ||
500 | |||
501 | impl SourceChange { | 525 | impl SourceChange { |
502 | pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange { | 526 | pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange { |
503 | let file_edit = SourceFileEdit { | 527 | let file_edit = SourceFileEdit { |