diff options
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r-- | crates/ra_analysis/src/completion.rs | 2 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 224 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 153 | ||||
-rw-r--r-- | crates/ra_analysis/src/symbol_index.rs | 42 |
4 files changed, 203 insertions, 218 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs index b4ee092b5..739ca6ae8 100644 --- a/crates/ra_analysis/src/completion.rs +++ b/crates/ra_analysis/src/completion.rs | |||
@@ -58,6 +58,6 @@ fn check_completion(code: &str, expected_completions: &str, kind: CompletionKind | |||
58 | } else { | 58 | } else { |
59 | single_file_with_position(code) | 59 | single_file_with_position(code) |
60 | }; | 60 | }; |
61 | let completions = completions(&analysis.imp.db, position).unwrap().unwrap(); | 61 | let completions = completions(&analysis.db, position).unwrap().unwrap(); |
62 | completions.assert_match(expected_completions, kind); | 62 | completions.assert_match(expected_completions, kind); |
63 | } | 63 | } |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 8071554a7..0faf8b85d 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -1,16 +1,12 @@ | |||
1 | use std::{ | 1 | use std::sync::Arc; |
2 | fmt, | ||
3 | sync::Arc, | ||
4 | }; | ||
5 | 2 | ||
6 | use rayon::prelude::*; | 3 | use salsa::Database; |
7 | use salsa::{Database, ParallelDatabase}; | ||
8 | 4 | ||
9 | use hir::{ | 5 | use hir::{ |
10 | self, FnSignatureInfo, Problem, source_binder, | 6 | self, FnSignatureInfo, Problem, source_binder, |
11 | }; | 7 | }; |
12 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; | 8 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; |
13 | use ra_editor::{self, find_node_at_offset, LineIndex, LocalEdit, Severity}; | 9 | use ra_editor::{self, find_node_at_offset, LocalEdit, Severity}; |
14 | use ra_syntax::{ | 10 | use ra_syntax::{ |
15 | algo::find_covering_node, | 11 | algo::find_covering_node, |
16 | ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, | 12 | ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, |
@@ -22,38 +18,25 @@ use ra_syntax::{ | |||
22 | use crate::{ | 18 | use crate::{ |
23 | AnalysisChange, | 19 | AnalysisChange, |
24 | Cancelable, NavigationTarget, | 20 | Cancelable, NavigationTarget, |
25 | completion::{CompletionItem, completions}, | ||
26 | CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, | 21 | CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, |
27 | Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit, | 22 | Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit, |
28 | symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase, FileSymbol}, | 23 | symbol_index::{LibrarySymbolsQuery, FileSymbol}, |
29 | }; | 24 | }; |
30 | 25 | ||
31 | #[derive(Debug, Default)] | 26 | impl db::RootDatabase { |
32 | pub(crate) struct AnalysisHostImpl { | 27 | pub(crate) fn apply_change(&mut self, change: AnalysisChange) { |
33 | db: db::RootDatabase, | ||
34 | } | ||
35 | |||
36 | impl AnalysisHostImpl { | ||
37 | pub fn analysis(&self) -> AnalysisImpl { | ||
38 | AnalysisImpl { | ||
39 | db: self.db.snapshot(), | ||
40 | } | ||
41 | } | ||
42 | pub fn apply_change(&mut self, change: AnalysisChange) { | ||
43 | log::info!("apply_change {:?}", change); | 28 | log::info!("apply_change {:?}", change); |
44 | // self.gc_syntax_trees(); | 29 | // self.gc_syntax_trees(); |
45 | if !change.new_roots.is_empty() { | 30 | if !change.new_roots.is_empty() { |
46 | let mut local_roots = Vec::clone(&self.db.local_roots()); | 31 | let mut local_roots = Vec::clone(&self.local_roots()); |
47 | for (root_id, is_local) in change.new_roots { | 32 | for (root_id, is_local) in change.new_roots { |
48 | self.db | 33 | self.query_mut(ra_db::SourceRootQuery) |
49 | .query_mut(ra_db::SourceRootQuery) | ||
50 | .set(root_id, Default::default()); | 34 | .set(root_id, Default::default()); |
51 | if is_local { | 35 | if is_local { |
52 | local_roots.push(root_id); | 36 | local_roots.push(root_id); |
53 | } | 37 | } |
54 | } | 38 | } |
55 | self.db | 39 | self.query_mut(ra_db::LocalRootsQuery) |
56 | .query_mut(ra_db::LocalRootsQuery) | ||
57 | .set((), Arc::new(local_roots)); | 40 | .set((), Arc::new(local_roots)); |
58 | } | 41 | } |
59 | 42 | ||
@@ -61,53 +44,44 @@ impl AnalysisHostImpl { | |||
61 | self.apply_root_change(root_id, root_change); | 44 | self.apply_root_change(root_id, root_change); |
62 | } | 45 | } |
63 | for (file_id, text) in change.files_changed { | 46 | for (file_id, text) in change.files_changed { |
64 | self.db.query_mut(ra_db::FileTextQuery).set(file_id, text) | 47 | self.query_mut(ra_db::FileTextQuery).set(file_id, text) |
65 | } | 48 | } |
66 | if !change.libraries_added.is_empty() { | 49 | if !change.libraries_added.is_empty() { |
67 | let mut libraries = Vec::clone(&self.db.library_roots()); | 50 | let mut libraries = Vec::clone(&self.library_roots()); |
68 | for library in change.libraries_added { | 51 | for library in change.libraries_added { |
69 | libraries.push(library.root_id); | 52 | libraries.push(library.root_id); |
70 | self.db | 53 | self.query_mut(ra_db::SourceRootQuery) |
71 | .query_mut(ra_db::SourceRootQuery) | ||
72 | .set(library.root_id, Default::default()); | 54 | .set(library.root_id, Default::default()); |
73 | self.db | 55 | self.query_mut(LibrarySymbolsQuery) |
74 | .query_mut(LibrarySymbolsQuery) | ||
75 | .set_constant(library.root_id, Arc::new(library.symbol_index)); | 56 | .set_constant(library.root_id, Arc::new(library.symbol_index)); |
76 | self.apply_root_change(library.root_id, library.root_change); | 57 | self.apply_root_change(library.root_id, library.root_change); |
77 | } | 58 | } |
78 | self.db | 59 | self.query_mut(ra_db::LibraryRootsQuery) |
79 | .query_mut(ra_db::LibraryRootsQuery) | ||
80 | .set((), Arc::new(libraries)); | 60 | .set((), Arc::new(libraries)); |
81 | } | 61 | } |
82 | if let Some(crate_graph) = change.crate_graph { | 62 | if let Some(crate_graph) = change.crate_graph { |
83 | self.db | 63 | self.query_mut(ra_db::CrateGraphQuery) |
84 | .query_mut(ra_db::CrateGraphQuery) | ||
85 | .set((), Arc::new(crate_graph)) | 64 | .set((), Arc::new(crate_graph)) |
86 | } | 65 | } |
87 | } | 66 | } |
88 | 67 | ||
89 | fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { | 68 | fn apply_root_change(&mut self, root_id: SourceRootId, root_change: RootChange) { |
90 | let mut source_root = SourceRoot::clone(&self.db.source_root(root_id)); | 69 | let mut source_root = SourceRoot::clone(&self.source_root(root_id)); |
91 | for add_file in root_change.added { | 70 | for add_file in root_change.added { |
92 | self.db | 71 | self.query_mut(ra_db::FileTextQuery) |
93 | .query_mut(ra_db::FileTextQuery) | ||
94 | .set(add_file.file_id, add_file.text); | 72 | .set(add_file.file_id, add_file.text); |
95 | self.db | 73 | self.query_mut(ra_db::FileRelativePathQuery) |
96 | .query_mut(ra_db::FileRelativePathQuery) | ||
97 | .set(add_file.file_id, add_file.path.clone()); | 74 | .set(add_file.file_id, add_file.path.clone()); |
98 | self.db | 75 | self.query_mut(ra_db::FileSourceRootQuery) |
99 | .query_mut(ra_db::FileSourceRootQuery) | ||
100 | .set(add_file.file_id, root_id); | 76 | .set(add_file.file_id, root_id); |
101 | source_root.files.insert(add_file.path, add_file.file_id); | 77 | source_root.files.insert(add_file.path, add_file.file_id); |
102 | } | 78 | } |
103 | for remove_file in root_change.removed { | 79 | for remove_file in root_change.removed { |
104 | self.db | 80 | self.query_mut(ra_db::FileTextQuery) |
105 | .query_mut(ra_db::FileTextQuery) | ||
106 | .set(remove_file.file_id, Default::default()); | 81 | .set(remove_file.file_id, Default::default()); |
107 | source_root.files.remove(&remove_file.path); | 82 | source_root.files.remove(&remove_file.path); |
108 | } | 83 | } |
109 | self.db | 84 | self.query_mut(ra_db::SourceRootQuery) |
110 | .query_mut(ra_db::SourceRootQuery) | ||
111 | .set(root_id, Arc::new(source_root)); | 85 | .set(root_id, Arc::new(source_root)); |
112 | } | 86 | } |
113 | 87 | ||
@@ -116,74 +90,18 @@ impl AnalysisHostImpl { | |||
116 | /// syntax trees. However, if we actually do that, everything is recomputed | 90 | /// syntax trees. However, if we actually do that, everything is recomputed |
117 | /// for some reason. Needs investigation. | 91 | /// for some reason. Needs investigation. |
118 | fn gc_syntax_trees(&mut self) { | 92 | fn gc_syntax_trees(&mut self) { |
119 | self.db | 93 | self.query(ra_db::SourceFileQuery) |
120 | .query(ra_db::SourceFileQuery) | ||
121 | .sweep(salsa::SweepStrategy::default().discard_values()); | 94 | .sweep(salsa::SweepStrategy::default().discard_values()); |
122 | self.db | 95 | self.query(hir::db::SourceFileItemsQuery) |
123 | .query(hir::db::SourceFileItemsQuery) | ||
124 | .sweep(salsa::SweepStrategy::default().discard_values()); | 96 | .sweep(salsa::SweepStrategy::default().discard_values()); |
125 | self.db | 97 | self.query(hir::db::FileItemQuery) |
126 | .query(hir::db::FileItemQuery) | ||
127 | .sweep(salsa::SweepStrategy::default().discard_values()); | 98 | .sweep(salsa::SweepStrategy::default().discard_values()); |
128 | } | 99 | } |
129 | } | 100 | } |
130 | 101 | ||
131 | pub(crate) struct AnalysisImpl { | 102 | impl db::RootDatabase { |
132 | pub(crate) db: salsa::Snapshot<db::RootDatabase>, | ||
133 | } | ||
134 | |||
135 | impl fmt::Debug for AnalysisImpl { | ||
136 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
137 | let db: &db::RootDatabase = &self.db; | ||
138 | fmt.debug_struct("AnalysisImpl").field("db", db).finish() | ||
139 | } | ||
140 | } | ||
141 | |||
142 | impl AnalysisImpl { | ||
143 | pub fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
144 | self.db.file_text(file_id) | ||
145 | } | ||
146 | pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { | ||
147 | self.db.source_file(file_id) | ||
148 | } | ||
149 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { | ||
150 | self.db.file_lines(file_id) | ||
151 | } | ||
152 | pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { | ||
153 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | ||
154 | struct Snap(salsa::Snapshot<db::RootDatabase>); | ||
155 | impl Clone for Snap { | ||
156 | fn clone(&self) -> Snap { | ||
157 | Snap(self.0.snapshot()) | ||
158 | } | ||
159 | } | ||
160 | |||
161 | let buf: Vec<Arc<SymbolIndex>> = if query.libs { | ||
162 | let snap = Snap(self.db.snapshot()); | ||
163 | self.db | ||
164 | .library_roots() | ||
165 | .par_iter() | ||
166 | .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id)) | ||
167 | .collect() | ||
168 | } else { | ||
169 | let mut files = Vec::new(); | ||
170 | for &root in self.db.local_roots().iter() { | ||
171 | let sr = self.db.source_root(root); | ||
172 | files.extend(sr.files.values().map(|&it| it)) | ||
173 | } | ||
174 | |||
175 | let snap = Snap(self.db.snapshot()); | ||
176 | files | ||
177 | .par_iter() | ||
178 | .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) | ||
179 | .filter_map(|it| it.ok()) | ||
180 | .collect() | ||
181 | }; | ||
182 | Ok(query.search(&buf)) | ||
183 | } | ||
184 | |||
185 | pub(crate) fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> { | 103 | pub(crate) fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> { |
186 | let descr = match source_binder::module_from_position(&*self.db, position)? { | 104 | let descr = match source_binder::module_from_position(self, position)? { |
187 | None => return Ok(None), | 105 | None => return Ok(None), |
188 | Some(it) => it, | 106 | Some(it) => it, |
189 | }; | 107 | }; |
@@ -205,12 +123,15 @@ impl AnalysisImpl { | |||
205 | 123 | ||
206 | /// This returns `Vec` because a module may be included from several places. We | 124 | /// This returns `Vec` because a module may be included from several places. We |
207 | /// don't handle this case yet though, so the Vec has length at most one. | 125 | /// don't handle this case yet though, so the Vec has length at most one. |
208 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { | 126 | pub(crate) fn parent_module( |
209 | let descr = match source_binder::module_from_position(&*self.db, position)? { | 127 | &self, |
128 | position: FilePosition, | ||
129 | ) -> Cancelable<Vec<NavigationTarget>> { | ||
130 | let descr = match source_binder::module_from_position(self, position)? { | ||
210 | None => return Ok(Vec::new()), | 131 | None => return Ok(Vec::new()), |
211 | Some(it) => it, | 132 | Some(it) => it, |
212 | }; | 133 | }; |
213 | let (file_id, decl) = match descr.parent_link_source(&*self.db) { | 134 | let (file_id, decl) = match descr.parent_link_source(self) { |
214 | None => return Ok(Vec::new()), | 135 | None => return Ok(Vec::new()), |
215 | Some(it) => it, | 136 | Some(it) => it, |
216 | }; | 137 | }; |
@@ -224,39 +145,33 @@ impl AnalysisImpl { | |||
224 | Ok(vec![NavigationTarget { file_id, symbol }]) | 145 | Ok(vec![NavigationTarget { file_id, symbol }]) |
225 | } | 146 | } |
226 | /// Returns `Vec` for the same reason as `parent_module` | 147 | /// Returns `Vec` for the same reason as `parent_module` |
227 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 148 | pub(crate) fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
228 | let descr = match source_binder::module_from_file_id(&*self.db, file_id)? { | 149 | let descr = match source_binder::module_from_file_id(self, file_id)? { |
229 | None => return Ok(Vec::new()), | 150 | None => return Ok(Vec::new()), |
230 | Some(it) => it, | 151 | Some(it) => it, |
231 | }; | 152 | }; |
232 | let root = descr.crate_root(); | 153 | let root = descr.crate_root(); |
233 | let file_id = root.file_id(); | 154 | let file_id = root.file_id(); |
234 | 155 | ||
235 | let crate_graph = self.db.crate_graph(); | 156 | let crate_graph = self.crate_graph(); |
236 | let crate_id = crate_graph.crate_id_for_crate_root(file_id); | 157 | let crate_id = crate_graph.crate_id_for_crate_root(file_id); |
237 | Ok(crate_id.into_iter().collect()) | 158 | Ok(crate_id.into_iter().collect()) |
238 | } | 159 | } |
239 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 160 | pub(crate) fn crate_root(&self, crate_id: CrateId) -> FileId { |
240 | self.db.crate_graph().crate_root(crate_id) | 161 | self.crate_graph().crate_root(crate_id) |
241 | } | 162 | } |
242 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 163 | pub(crate) fn approximately_resolve_symbol( |
243 | let completions = completions(&self.db, position)?; | ||
244 | Ok(completions.map(|it| it.into())) | ||
245 | } | ||
246 | pub fn approximately_resolve_symbol( | ||
247 | &self, | 164 | &self, |
248 | position: FilePosition, | 165 | position: FilePosition, |
249 | ) -> Cancelable<Option<ReferenceResolution>> { | 166 | ) -> Cancelable<Option<ReferenceResolution>> { |
250 | let file = self.db.source_file(position.file_id); | 167 | let file = self.source_file(position.file_id); |
251 | let syntax = file.syntax(); | 168 | let syntax = file.syntax(); |
252 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | 169 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { |
253 | let mut rr = ReferenceResolution::new(name_ref.syntax().range()); | 170 | let mut rr = ReferenceResolution::new(name_ref.syntax().range()); |
254 | if let Some(fn_descr) = source_binder::function_from_child_node( | 171 | if let Some(fn_descr) = |
255 | &*self.db, | 172 | source_binder::function_from_child_node(self, position.file_id, name_ref.syntax())? |
256 | position.file_id, | 173 | { |
257 | name_ref.syntax(), | 174 | let scope = fn_descr.scopes(self); |
258 | )? { | ||
259 | let scope = fn_descr.scopes(&*self.db); | ||
260 | // First try to resolve the symbol locally | 175 | // First try to resolve the symbol locally |
261 | if let Some(entry) = scope.resolve_local_name(name_ref) { | 176 | if let Some(entry) = scope.resolve_local_name(name_ref) { |
262 | rr.add_resolution( | 177 | rr.add_resolution( |
@@ -281,7 +196,7 @@ impl AnalysisImpl { | |||
281 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 196 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
282 | if module.has_semi() { | 197 | if module.has_semi() { |
283 | if let Some(child_module) = | 198 | if let Some(child_module) = |
284 | source_binder::module_from_declaration(&*self.db, position.file_id, module)? | 199 | source_binder::module_from_declaration(self, position.file_id, module)? |
285 | { | 200 | { |
286 | let file_id = child_module.file_id(); | 201 | let file_id = child_module.file_id(); |
287 | let name = match child_module.name() { | 202 | let name = match child_module.name() { |
@@ -302,10 +217,13 @@ impl AnalysisImpl { | |||
302 | Ok(None) | 217 | Ok(None) |
303 | } | 218 | } |
304 | 219 | ||
305 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 220 | pub(crate) fn find_all_refs( |
306 | let file = self.db.source_file(position.file_id); | 221 | &self, |
222 | position: FilePosition, | ||
223 | ) -> Cancelable<Vec<(FileId, TextRange)>> { | ||
224 | let file = self.source_file(position.file_id); | ||
307 | // Find the binding associated with the offset | 225 | // Find the binding associated with the offset |
308 | let (binding, descr) = match find_binding(&self.db, &file, position)? { | 226 | let (binding, descr) = match find_binding(self, &file, position)? { |
309 | None => return Ok(Vec::new()), | 227 | None => return Ok(Vec::new()), |
310 | Some(it) => it, | 228 | Some(it) => it, |
311 | }; | 229 | }; |
@@ -317,7 +235,7 @@ impl AnalysisImpl { | |||
317 | .collect::<Vec<_>>(); | 235 | .collect::<Vec<_>>(); |
318 | ret.extend( | 236 | ret.extend( |
319 | descr | 237 | descr |
320 | .scopes(&*self.db) | 238 | .scopes(self) |
321 | .find_all_refs(binding) | 239 | .find_all_refs(binding) |
322 | .into_iter() | 240 | .into_iter() |
323 | .map(|ref_desc| (position.file_id, ref_desc.range)), | 241 | .map(|ref_desc| (position.file_id, ref_desc.range)), |
@@ -355,8 +273,8 @@ impl AnalysisImpl { | |||
355 | Ok(Some((binding, descr))) | 273 | Ok(Some((binding, descr))) |
356 | } | 274 | } |
357 | } | 275 | } |
358 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { | 276 | pub(crate) fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { |
359 | let file = self.db.source_file(nav.file_id); | 277 | let file = self.source_file(nav.file_id); |
360 | let result = match (nav.symbol.description(&file), nav.symbol.docs(&file)) { | 278 | let result = match (nav.symbol.description(&file), nav.symbol.docs(&file)) { |
361 | (Some(desc), Some(docs)) => { | 279 | (Some(desc), Some(docs)) => { |
362 | Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs) | 280 | Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs) |
@@ -369,8 +287,8 @@ impl AnalysisImpl { | |||
369 | Ok(result) | 287 | Ok(result) |
370 | } | 288 | } |
371 | 289 | ||
372 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 290 | pub(crate) fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
373 | let syntax = self.db.source_file(file_id); | 291 | let syntax = self.source_file(file_id); |
374 | 292 | ||
375 | let mut res = ra_editor::diagnostics(&syntax) | 293 | let mut res = ra_editor::diagnostics(&syntax) |
376 | .into_iter() | 294 | .into_iter() |
@@ -381,9 +299,9 @@ impl AnalysisImpl { | |||
381 | fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)), | 299 | fix: d.fix.map(|fix| SourceChange::from_local_edit(file_id, fix)), |
382 | }) | 300 | }) |
383 | .collect::<Vec<_>>(); | 301 | .collect::<Vec<_>>(); |
384 | if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? { | 302 | if let Some(m) = source_binder::module_from_file_id(self, file_id)? { |
385 | for (name_node, problem) in m.problems(&*self.db) { | 303 | for (name_node, problem) in m.problems(self) { |
386 | let source_root = self.db.file_source_root(file_id); | 304 | let source_root = self.file_source_root(file_id); |
387 | let diag = match problem { | 305 | let diag = match problem { |
388 | Problem::UnresolvedModule { candidate } => { | 306 | Problem::UnresolvedModule { candidate } => { |
389 | let create_file = FileSystemEdit::CreateFile { | 307 | let create_file = FileSystemEdit::CreateFile { |
@@ -433,8 +351,8 @@ impl AnalysisImpl { | |||
433 | Ok(res) | 351 | Ok(res) |
434 | } | 352 | } |
435 | 353 | ||
436 | pub fn assists(&self, frange: FileRange) -> Vec<SourceChange> { | 354 | pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> { |
437 | let file = self.file_syntax(frange.file_id); | 355 | let file = self.source_file(frange.file_id); |
438 | let offset = frange.range.start(); | 356 | let offset = frange.range.start(); |
439 | let actions = vec![ | 357 | let actions = vec![ |
440 | ra_editor::flip_comma(&file, offset).map(|f| f()), | 358 | ra_editor::flip_comma(&file, offset).map(|f| f()), |
@@ -451,11 +369,11 @@ impl AnalysisImpl { | |||
451 | .collect() | 369 | .collect() |
452 | } | 370 | } |
453 | 371 | ||
454 | pub fn resolve_callable( | 372 | pub(crate) fn resolve_callable( |
455 | &self, | 373 | &self, |
456 | position: FilePosition, | 374 | position: FilePosition, |
457 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { | 375 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { |
458 | let file = self.db.source_file(position.file_id); | 376 | let file = self.source_file(position.file_id); |
459 | let syntax = file.syntax(); | 377 | let syntax = file.syntax(); |
460 | 378 | ||
461 | // Find the calling expression and it's NameRef | 379 | // Find the calling expression and it's NameRef |
@@ -466,12 +384,12 @@ impl AnalysisImpl { | |||
466 | let file_symbols = self.index_resolve(name_ref)?; | 384 | let file_symbols = self.index_resolve(name_ref)?; |
467 | for (fn_file_id, fs) in file_symbols { | 385 | for (fn_file_id, fs) in file_symbols { |
468 | if fs.kind == FN_DEF { | 386 | if fs.kind == FN_DEF { |
469 | let fn_file = self.db.source_file(fn_file_id); | 387 | let fn_file = self.source_file(fn_file_id); |
470 | if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { | 388 | if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { |
471 | let descr = ctry!(source_binder::function_from_source( | 389 | let descr = ctry!(source_binder::function_from_source( |
472 | &*self.db, fn_file_id, fn_def | 390 | self, fn_file_id, fn_def |
473 | )?); | 391 | )?); |
474 | if let Some(descriptor) = descr.signature_info(&*self.db) { | 392 | if let Some(descriptor) = descr.signature_info(self) { |
475 | // If we have a calling expression let's find which argument we are on | 393 | // If we have a calling expression let's find which argument we are on |
476 | let mut current_parameter = None; | 394 | let mut current_parameter = None; |
477 | 395 | ||
@@ -518,20 +436,20 @@ impl AnalysisImpl { | |||
518 | Ok(None) | 436 | Ok(None) |
519 | } | 437 | } |
520 | 438 | ||
521 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { | 439 | pub(crate) fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { |
522 | let file = self.db.source_file(frange.file_id); | 440 | let file = self.source_file(frange.file_id); |
523 | let syntax = file.syntax(); | 441 | let syntax = file.syntax(); |
524 | let node = find_covering_node(syntax, frange.range); | 442 | let node = find_covering_node(syntax, frange.range); |
525 | let parent_fn = ctry!(node.ancestors().find_map(FnDef::cast)); | 443 | let parent_fn = ctry!(node.ancestors().find_map(FnDef::cast)); |
526 | let function = ctry!(source_binder::function_from_source( | 444 | let function = ctry!(source_binder::function_from_source( |
527 | &*self.db, | 445 | self, |
528 | frange.file_id, | 446 | frange.file_id, |
529 | parent_fn | 447 | parent_fn |
530 | )?); | 448 | )?); |
531 | let infer = function.infer(&*self.db)?; | 449 | let infer = function.infer(self)?; |
532 | Ok(infer.type_of_node(node).map(|t| t.to_string())) | 450 | Ok(infer.type_of_node(node).map(|t| t.to_string())) |
533 | } | 451 | } |
534 | pub fn rename( | 452 | pub(crate) fn rename( |
535 | &self, | 453 | &self, |
536 | position: FilePosition, | 454 | position: FilePosition, |
537 | new_name: &str, | 455 | new_name: &str, |
@@ -555,7 +473,7 @@ impl AnalysisImpl { | |||
555 | let mut query = Query::new(name.to_string()); | 473 | let mut query = Query::new(name.to_string()); |
556 | query.exact(); | 474 | query.exact(); |
557 | query.limit(4); | 475 | query.limit(4); |
558 | self.world_symbols(query) | 476 | crate::symbol_index::world_symbols(self, query) |
559 | } | 477 | } |
560 | } | 478 | } |
561 | 479 | ||
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 9576453ab..54eb2f4d3 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -27,11 +27,9 @@ use ra_syntax::{SourceFileNode, TextRange, TextUnit, SmolStr, SyntaxKind}; | |||
27 | use ra_text_edit::TextEdit; | 27 | use ra_text_edit::TextEdit; |
28 | use rayon::prelude::*; | 28 | use rayon::prelude::*; |
29 | use relative_path::RelativePathBuf; | 29 | use relative_path::RelativePathBuf; |
30 | use salsa::ParallelDatabase; | ||
30 | 31 | ||
31 | use crate::{ | 32 | use crate::symbol_index::{SymbolIndex, FileSymbol}; |
32 | imp::{AnalysisHostImpl, AnalysisImpl}, | ||
33 | symbol_index::{SymbolIndex, FileSymbol}, | ||
34 | }; | ||
35 | 33 | ||
36 | pub use crate::{ | 34 | pub use crate::{ |
37 | completion::{CompletionItem, CompletionItemKind, InsertText}, | 35 | completion::{CompletionItem, CompletionItemKind, InsertText}, |
@@ -44,7 +42,7 @@ pub use hir::FnSignatureInfo; | |||
44 | 42 | ||
45 | pub use ra_db::{ | 43 | pub use ra_db::{ |
46 | Canceled, Cancelable, FilePosition, FileRange, | 44 | Canceled, Cancelable, FilePosition, FileRange, |
47 | CrateGraph, CrateId, SourceRootId, FileId | 45 | CrateGraph, CrateId, SourceRootId, FileId, SyntaxDatabase, FilesDatabase |
48 | }; | 46 | }; |
49 | 47 | ||
50 | #[derive(Default)] | 48 | #[derive(Default)] |
@@ -150,27 +148,6 @@ impl AnalysisChange { | |||
150 | } | 148 | } |
151 | } | 149 | } |
152 | 150 | ||
153 | /// `AnalysisHost` stores the current state of the world. | ||
154 | #[derive(Debug, Default)] | ||
155 | pub struct AnalysisHost { | ||
156 | imp: AnalysisHostImpl, | ||
157 | } | ||
158 | |||
159 | impl AnalysisHost { | ||
160 | /// Returns a snapshot of the current state, which you can query for | ||
161 | /// semantic information. | ||
162 | pub fn analysis(&self) -> Analysis { | ||
163 | Analysis { | ||
164 | imp: self.imp.analysis(), | ||
165 | } | ||
166 | } | ||
167 | /// Applies changes to the current state of the world. If there are | ||
168 | /// outstanding snapshots, they will be canceled. | ||
169 | pub fn apply_change(&mut self, change: AnalysisChange) { | ||
170 | self.imp.apply_change(change) | ||
171 | } | ||
172 | } | ||
173 | |||
174 | #[derive(Debug)] | 151 | #[derive(Debug)] |
175 | pub struct SourceChange { | 152 | pub struct SourceChange { |
176 | pub label: String, | 153 | pub label: String, |
@@ -287,124 +264,178 @@ impl ReferenceResolution { | |||
287 | } | 264 | } |
288 | } | 265 | } |
289 | 266 | ||
267 | /// `AnalysisHost` stores the current state of the world. | ||
268 | #[derive(Debug, Default)] | ||
269 | pub struct AnalysisHost { | ||
270 | db: db::RootDatabase, | ||
271 | } | ||
272 | |||
273 | impl AnalysisHost { | ||
274 | /// Returns a snapshot of the current state, which you can query for | ||
275 | /// semantic information. | ||
276 | pub fn analysis(&self) -> Analysis { | ||
277 | Analysis { | ||
278 | db: self.db.snapshot(), | ||
279 | } | ||
280 | } | ||
281 | /// Applies changes to the current state of the world. If there are | ||
282 | /// outstanding snapshots, they will be canceled. | ||
283 | pub fn apply_change(&mut self, change: AnalysisChange) { | ||
284 | self.db.apply_change(change) | ||
285 | } | ||
286 | } | ||
287 | |||
290 | /// Analysis is a snapshot of a world state at a moment in time. It is the main | 288 | /// Analysis is a snapshot of a world state at a moment in time. It is the main |
291 | /// entry point for asking semantic information about the world. When the world | 289 | /// entry point for asking semantic information about the world. When the world |
292 | /// state is advanced using `AnalysisHost::apply_change` method, all existing | 290 | /// state is advanced using `AnalysisHost::apply_change` method, all existing |
293 | /// `Analysis` are canceled (most method return `Err(Canceled)`). | 291 | /// `Analysis` are canceled (most method return `Err(Canceled)`). |
294 | #[derive(Debug)] | 292 | #[derive(Debug)] |
295 | pub struct Analysis { | 293 | pub struct Analysis { |
296 | pub(crate) imp: AnalysisImpl, | 294 | db: salsa::Snapshot<db::RootDatabase>, |
297 | } | 295 | } |
298 | 296 | ||
299 | impl Analysis { | 297 | impl Analysis { |
298 | /// Gets the text of the source file. | ||
300 | pub fn file_text(&self, file_id: FileId) -> Arc<String> { | 299 | pub fn file_text(&self, file_id: FileId) -> Arc<String> { |
301 | self.imp.file_text(file_id) | 300 | self.db.file_text(file_id) |
302 | } | 301 | } |
302 | /// Gets the syntax tree of the file. | ||
303 | pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { | 303 | pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { |
304 | self.imp.file_syntax(file_id).clone() | 304 | self.db.source_file(file_id).clone() |
305 | } | 305 | } |
306 | /// Gets the file's `LineIndex`: data structure to convert between absolute | ||
307 | /// offsets and line/column representation. | ||
306 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { | 308 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
307 | self.imp.file_line_index(file_id) | 309 | self.db.file_lines(file_id) |
308 | } | 310 | } |
311 | /// Selects the next syntactic nodes encopasing the range. | ||
309 | pub fn extend_selection(&self, frange: FileRange) -> TextRange { | 312 | pub fn extend_selection(&self, frange: FileRange) -> TextRange { |
310 | extend_selection::extend_selection(&self.imp.db, frange) | 313 | extend_selection::extend_selection(&self.db, frange) |
311 | } | 314 | } |
315 | /// Returns position of the mathcing brace (all types of braces are | ||
316 | /// supported). | ||
312 | pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> { | 317 | pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> { |
313 | ra_editor::matching_brace(file, offset) | 318 | ra_editor::matching_brace(file, offset) |
314 | } | 319 | } |
320 | /// Returns a syntax tree represented as `String`, for debug purposes. | ||
321 | // FIXME: use a better name here. | ||
315 | pub fn syntax_tree(&self, file_id: FileId) -> String { | 322 | pub fn syntax_tree(&self, file_id: FileId) -> String { |
316 | let file = self.imp.file_syntax(file_id); | 323 | let file = self.db.source_file(file_id); |
317 | ra_editor::syntax_tree(&file) | 324 | ra_editor::syntax_tree(&file) |
318 | } | 325 | } |
326 | /// Returns an edit to remove all newlines in the range, cleaning up minor | ||
327 | /// stuff like trailing commas. | ||
319 | pub fn join_lines(&self, frange: FileRange) -> SourceChange { | 328 | pub fn join_lines(&self, frange: FileRange) -> SourceChange { |
320 | let file = self.imp.file_syntax(frange.file_id); | 329 | let file = self.db.source_file(frange.file_id); |
321 | SourceChange::from_local_edit(frange.file_id, ra_editor::join_lines(&file, frange.range)) | 330 | SourceChange::from_local_edit(frange.file_id, ra_editor::join_lines(&file, frange.range)) |
322 | } | 331 | } |
332 | /// Returns an edit which should be applied when opening a new line, fixing | ||
333 | /// up minor stuff like continuing the comment. | ||
323 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { | 334 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { |
324 | let file = self.imp.file_syntax(position.file_id); | 335 | let file = self.db.source_file(position.file_id); |
325 | let edit = ra_editor::on_enter(&file, position.offset)?; | 336 | let edit = ra_editor::on_enter(&file, position.offset)?; |
326 | let res = SourceChange::from_local_edit(position.file_id, edit); | 337 | Some(SourceChange::from_local_edit(position.file_id, edit)) |
327 | Some(res) | ||
328 | } | 338 | } |
339 | /// Returns an edit which should be applied after `=` was typed. Primaraly, | ||
340 | /// this works when adding `let =`. | ||
341 | // FIXME: use a snippet completion instead of this hack here. | ||
329 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { | 342 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { |
330 | let file = self.imp.file_syntax(position.file_id); | 343 | let file = self.db.source_file(position.file_id); |
331 | Some(SourceChange::from_local_edit( | 344 | let edit = ra_editor::on_eq_typed(&file, position.offset)?; |
332 | position.file_id, | 345 | Some(SourceChange::from_local_edit(position.file_id, edit)) |
333 | ra_editor::on_eq_typed(&file, position.offset)?, | ||
334 | )) | ||
335 | } | 346 | } |
347 | /// Returns a tree representation of symbols in the file. Useful to draw a | ||
348 | /// file outline. | ||
336 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { | 349 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { |
337 | let file = self.imp.file_syntax(file_id); | 350 | let file = self.db.source_file(file_id); |
338 | ra_editor::file_structure(&file) | 351 | ra_editor::file_structure(&file) |
339 | } | 352 | } |
353 | /// Returns the set of folding ranges. | ||
340 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { | 354 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { |
341 | let file = self.imp.file_syntax(file_id); | 355 | let file = self.db.source_file(file_id); |
342 | ra_editor::folding_ranges(&file) | 356 | ra_editor::folding_ranges(&file) |
343 | } | 357 | } |
358 | /// Fuzzy searches for a symbol. | ||
344 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { | 359 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { |
345 | let res = self | 360 | let res = symbol_index::world_symbols(&*self.db, query)? |
346 | .imp | ||
347 | .world_symbols(query)? | ||
348 | .into_iter() | 361 | .into_iter() |
349 | .map(|(file_id, symbol)| NavigationTarget { file_id, symbol }) | 362 | .map(|(file_id, symbol)| NavigationTarget { file_id, symbol }) |
350 | .collect(); | 363 | .collect(); |
351 | Ok(res) | 364 | Ok(res) |
352 | } | 365 | } |
366 | /// Resolves reference to definition, but does not gurantee correctness. | ||
353 | pub fn approximately_resolve_symbol( | 367 | pub fn approximately_resolve_symbol( |
354 | &self, | 368 | &self, |
355 | position: FilePosition, | 369 | position: FilePosition, |
356 | ) -> Cancelable<Option<ReferenceResolution>> { | 370 | ) -> Cancelable<Option<ReferenceResolution>> { |
357 | self.imp.approximately_resolve_symbol(position) | 371 | self.db.approximately_resolve_symbol(position) |
358 | } | 372 | } |
373 | /// Finds all usages of the reference at point. | ||
359 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 374 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
360 | self.imp.find_all_refs(position) | 375 | self.db.find_all_refs(position) |
361 | } | 376 | } |
377 | /// Returns documentation string for a given target. | ||
362 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { | 378 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { |
363 | self.imp.doc_text_for(nav) | 379 | self.db.doc_text_for(nav) |
364 | } | 380 | } |
381 | /// Returns a `mod name;` declaration whihc created the current module. | ||
365 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { | 382 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { |
366 | self.imp.parent_module(position) | 383 | self.db.parent_module(position) |
367 | } | 384 | } |
385 | /// Returns `::` separated path to the current module from the crate root. | ||
368 | pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> { | 386 | pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> { |
369 | self.imp.module_path(position) | 387 | self.db.module_path(position) |
370 | } | 388 | } |
389 | /// Returns crates this file belongs too. | ||
371 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 390 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
372 | self.imp.crate_for(file_id) | 391 | self.db.crate_for(file_id) |
373 | } | 392 | } |
393 | /// Returns the root file of the given crate. | ||
374 | pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { | 394 | pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { |
375 | Ok(self.imp.crate_root(crate_id)) | 395 | Ok(self.db.crate_root(crate_id)) |
376 | } | 396 | } |
397 | /// Returns the set of possible targets to run for the current file. | ||
377 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { | 398 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { |
378 | let file = self.imp.file_syntax(file_id); | 399 | let file = self.db.source_file(file_id); |
379 | Ok(runnables::runnables(self, &file, file_id)) | 400 | Ok(runnables::runnables(self, &file, file_id)) |
380 | } | 401 | } |
402 | /// Computes syntax highlighting for the given file. | ||
381 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 403 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { |
382 | syntax_highlighting::highlight(&*self.imp.db, file_id) | 404 | syntax_highlighting::highlight(&*self.db, file_id) |
383 | } | 405 | } |
406 | /// Computes completions at the given position. | ||
384 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 407 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { |
385 | self.imp.completions(position) | 408 | let completions = completion::completions(&self.db, position)?; |
409 | Ok(completions.map(|it| it.into())) | ||
386 | } | 410 | } |
411 | /// Computes assists (aks code actons aka intentions) for the given | ||
412 | /// position. | ||
387 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { | 413 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { |
388 | Ok(self.imp.assists(frange)) | 414 | Ok(self.db.assists(frange)) |
389 | } | 415 | } |
416 | /// Computes the set of diagnostics for the given file. | ||
390 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 417 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
391 | self.imp.diagnostics(file_id) | 418 | self.db.diagnostics(file_id) |
392 | } | 419 | } |
420 | /// Computes parameter information for the given call expression. | ||
393 | pub fn resolve_callable( | 421 | pub fn resolve_callable( |
394 | &self, | 422 | &self, |
395 | position: FilePosition, | 423 | position: FilePosition, |
396 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { | 424 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { |
397 | self.imp.resolve_callable(position) | 425 | self.db.resolve_callable(position) |
398 | } | 426 | } |
427 | /// Computes the type of the expression at the given position. | ||
399 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { | 428 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { |
400 | self.imp.type_of(frange) | 429 | self.db.type_of(frange) |
401 | } | 430 | } |
431 | /// Returns the edit required to rename reference at the position to the new | ||
432 | /// name. | ||
402 | pub fn rename( | 433 | pub fn rename( |
403 | &self, | 434 | &self, |
404 | position: FilePosition, | 435 | position: FilePosition, |
405 | new_name: &str, | 436 | new_name: &str, |
406 | ) -> Cancelable<Vec<SourceFileEdit>> { | 437 | ) -> Cancelable<Vec<SourceFileEdit>> { |
407 | self.imp.rename(position, new_name) | 438 | self.db.rename(position, new_name) |
408 | } | 439 | } |
409 | } | 440 | } |
410 | 441 | ||
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 56a84a850..ddcf3d052 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs | |||
@@ -10,12 +10,13 @@ use ra_syntax::{ | |||
10 | SyntaxKind::{self, *}, | 10 | SyntaxKind::{self, *}, |
11 | ast::{self, NameOwner, DocCommentsOwner}, | 11 | ast::{self, NameOwner, DocCommentsOwner}, |
12 | }; | 12 | }; |
13 | use ra_db::{SyntaxDatabase, SourceRootId}; | 13 | use ra_db::{SyntaxDatabase, SourceRootId, FilesDatabase}; |
14 | use salsa::ParallelDatabase; | ||
14 | use rayon::prelude::*; | 15 | use rayon::prelude::*; |
15 | 16 | ||
16 | use crate::{ | 17 | use crate::{ |
17 | Cancelable, | 18 | Cancelable, FileId, Query, |
18 | FileId, Query, | 19 | db::RootDatabase, |
19 | }; | 20 | }; |
20 | 21 | ||
21 | salsa::query_group! { | 22 | salsa::query_group! { |
@@ -36,6 +37,41 @@ fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<Sym | |||
36 | Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) | 37 | Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) |
37 | } | 38 | } |
38 | 39 | ||
40 | pub(crate) fn world_symbols( | ||
41 | db: &RootDatabase, | ||
42 | query: Query, | ||
43 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { | ||
44 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | ||
45 | struct Snap(salsa::Snapshot<RootDatabase>); | ||
46 | impl Clone for Snap { | ||
47 | fn clone(&self) -> Snap { | ||
48 | Snap(self.0.snapshot()) | ||
49 | } | ||
50 | } | ||
51 | |||
52 | let buf: Vec<Arc<SymbolIndex>> = if query.libs { | ||
53 | let snap = Snap(db.snapshot()); | ||
54 | db.library_roots() | ||
55 | .par_iter() | ||
56 | .map_with(snap, |db, &lib_id| db.0.library_symbols(lib_id)) | ||
57 | .collect() | ||
58 | } else { | ||
59 | let mut files = Vec::new(); | ||
60 | for &root in db.local_roots().iter() { | ||
61 | let sr = db.source_root(root); | ||
62 | files.extend(sr.files.values().map(|&it| it)) | ||
63 | } | ||
64 | |||
65 | let snap = Snap(db.snapshot()); | ||
66 | files | ||
67 | .par_iter() | ||
68 | .map_with(snap, |db, &file_id| db.0.file_symbols(file_id)) | ||
69 | .filter_map(|it| it.ok()) | ||
70 | .collect() | ||
71 | }; | ||
72 | Ok(query.search(&buf)) | ||
73 | } | ||
74 | |||
39 | #[derive(Default, Debug)] | 75 | #[derive(Default, Debug)] |
40 | pub(crate) struct SymbolIndex { | 76 | pub(crate) struct SymbolIndex { |
41 | symbols: Vec<(FileId, FileSymbol)>, | 77 | symbols: Vec<(FileId, FileSymbol)>, |