diff options
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/ra_analysis/src/db.rs | 40 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors.rs | 5 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 108 | ||||
-rw-r--r-- | crates/ra_analysis/src/job.rs | 53 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 76 | ||||
-rw-r--r-- | crates/ra_analysis/src/module_map.rs | 24 | ||||
-rw-r--r-- | crates/ra_analysis/src/roots.rs | 36 | ||||
-rw-r--r-- | crates/ra_analysis/src/symbol_index.rs | 14 | ||||
-rw-r--r-- | crates/ra_analysis/tests/tests.rs | 65 |
10 files changed, 237 insertions, 188 deletions
diff --git a/crates/ra_analysis/Cargo.toml b/crates/ra_analysis/Cargo.toml index 17b04182f..f5e742159 100644 --- a/crates/ra_analysis/Cargo.toml +++ b/crates/ra_analysis/Cargo.toml | |||
@@ -7,15 +7,13 @@ authors = ["Aleksey Kladov <[email protected]>"] | |||
7 | [dependencies] | 7 | [dependencies] |
8 | relative-path = "0.3.7" | 8 | relative-path = "0.3.7" |
9 | log = "0.4.2" | 9 | log = "0.4.2" |
10 | crossbeam-channel = "0.2.4" | ||
11 | parking_lot = "0.6.3" | 10 | parking_lot = "0.6.3" |
12 | once_cell = "0.1.5" | 11 | once_cell = "0.1.5" |
13 | rayon = "1.0.2" | 12 | rayon = "1.0.2" |
14 | fst = "0.3.1" | 13 | fst = "0.3.1" |
15 | im = "12.0.0" | ||
16 | ra_syntax = { path = "../ra_syntax" } | 14 | ra_syntax = { path = "../ra_syntax" } |
17 | ra_editor = { path = "../ra_editor" } | 15 | ra_editor = { path = "../ra_editor" } |
18 | salsa = "0.5.0" | 16 | salsa = "0.6.0" |
19 | rustc-hash = "1.0" | 17 | rustc-hash = "1.0" |
20 | 18 | ||
21 | [dev-dependencies] | 19 | [dev-dependencies] |
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index 99d40a269..956cbe162 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -1,22 +1,25 @@ | |||
1 | use crate::{ | 1 | use std::{ |
2 | module_map::{ModuleDescriptorQuery, ModuleTreeQuery, ModulesDatabase}, | 2 | fmt, |
3 | symbol_index::SymbolIndex, | 3 | hash::{Hash, Hasher}, |
4 | FileId, FileResolverImp, | 4 | sync::Arc, |
5 | }; | 5 | }; |
6 | |||
6 | use ra_editor::LineIndex; | 7 | use ra_editor::LineIndex; |
7 | use ra_syntax::File; | 8 | use ra_syntax::File; |
8 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
9 | use salsa; | 10 | use salsa; |
10 | 11 | ||
11 | use std::{ | 12 | use crate::{ |
12 | fmt, | 13 | db, |
13 | hash::{Hash, Hasher}, | 14 | Cancelable, Canceled, |
14 | sync::Arc, | 15 | module_map::{ModuleDescriptorQuery, ModuleTreeQuery, ModulesDatabase}, |
16 | symbol_index::SymbolIndex, | ||
17 | FileId, FileResolverImp, | ||
15 | }; | 18 | }; |
16 | 19 | ||
17 | #[derive(Default)] | 20 | #[derive(Default)] |
18 | pub(crate) struct RootDatabase { | 21 | pub(crate) struct RootDatabase { |
19 | runtime: salsa::runtime::Runtime<RootDatabase>, | 22 | runtime: salsa::Runtime<RootDatabase>, |
20 | } | 23 | } |
21 | 24 | ||
22 | impl fmt::Debug for RootDatabase { | 25 | impl fmt::Debug for RootDatabase { |
@@ -26,11 +29,19 @@ impl fmt::Debug for RootDatabase { | |||
26 | } | 29 | } |
27 | 30 | ||
28 | impl salsa::Database for RootDatabase { | 31 | impl salsa::Database for RootDatabase { |
29 | fn salsa_runtime(&self) -> &salsa::runtime::Runtime<RootDatabase> { | 32 | fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> { |
30 | &self.runtime | 33 | &self.runtime |
31 | } | 34 | } |
32 | } | 35 | } |
33 | 36 | ||
37 | pub(crate) fn check_canceled(db: &impl salsa::Database) -> Cancelable<()> { | ||
38 | if db.salsa_runtime().is_current_revision_canceled() { | ||
39 | Err(Canceled) | ||
40 | } else { | ||
41 | Ok(()) | ||
42 | } | ||
43 | } | ||
44 | |||
34 | impl salsa::ParallelDatabase for RootDatabase { | 45 | impl salsa::ParallelDatabase for RootDatabase { |
35 | fn fork(&self) -> Self { | 46 | fn fork(&self) -> Self { |
36 | RootDatabase { | 47 | RootDatabase { |
@@ -69,7 +80,7 @@ salsa::query_group! { | |||
69 | type FileTextQuery; | 80 | type FileTextQuery; |
70 | storage input; | 81 | storage input; |
71 | } | 82 | } |
72 | fn file_set(key: ()) -> Arc<FileSet> { | 83 | fn file_set() -> Arc<FileSet> { |
73 | type FileSetQuery; | 84 | type FileSetQuery; |
74 | storage input; | 85 | storage input; |
75 | } | 86 | } |
@@ -104,7 +115,7 @@ salsa::query_group! { | |||
104 | fn file_lines(file_id: FileId) -> Arc<LineIndex> { | 115 | fn file_lines(file_id: FileId) -> Arc<LineIndex> { |
105 | type FileLinesQuery; | 116 | type FileLinesQuery; |
106 | } | 117 | } |
107 | fn file_symbols(file_id: FileId) -> Arc<SymbolIndex> { | 118 | fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { |
108 | type FileSymbolsQuery; | 119 | type FileSymbolsQuery; |
109 | } | 120 | } |
110 | } | 121 | } |
@@ -118,7 +129,8 @@ fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> { | |||
118 | let text = db.file_text(file_id); | 129 | let text = db.file_text(file_id); |
119 | Arc::new(LineIndex::new(&*text)) | 130 | Arc::new(LineIndex::new(&*text)) |
120 | } | 131 | } |
121 | fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<SymbolIndex> { | 132 | fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { |
133 | db::check_canceled(db)?; | ||
122 | let syntax = db.file_syntax(file_id); | 134 | let syntax = db.file_syntax(file_id); |
123 | Arc::new(SymbolIndex::for_file(file_id, syntax)) | 135 | Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) |
124 | } | 136 | } |
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs index 3fca3e581..92da26493 100644 --- a/crates/ra_analysis/src/descriptors.rs +++ b/crates/ra_analysis/src/descriptors.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use crate::{imp::FileResolverImp, FileId}; | 1 | use std::collections::BTreeMap; |
2 | |||
2 | use ra_syntax::{ | 3 | use ra_syntax::{ |
3 | ast::{self, AstNode, NameOwner}, | 4 | ast::{self, AstNode, NameOwner}, |
4 | text_utils::is_subrange, | 5 | text_utils::is_subrange, |
@@ -6,7 +7,7 @@ use ra_syntax::{ | |||
6 | }; | 7 | }; |
7 | use relative_path::RelativePathBuf; | 8 | use relative_path::RelativePathBuf; |
8 | 9 | ||
9 | use std::collections::BTreeMap; | 10 | use crate::{imp::FileResolverImp, FileId}; |
10 | 11 | ||
11 | #[derive(Debug, PartialEq, Eq, Hash)] | 12 | #[derive(Debug, PartialEq, Eq, Hash)] |
12 | pub struct ModuleDescriptor { | 13 | pub struct ModuleDescriptor { |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 2ed6694ba..196627539 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -19,8 +19,8 @@ use rustc_hash::FxHashSet; | |||
19 | use crate::{ | 19 | use crate::{ |
20 | descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem}, | 20 | descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem}, |
21 | roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot}, | 21 | roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot}, |
22 | CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, JobToken, Position, | 22 | CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position, |
23 | Query, SourceChange, SourceFileEdit, | 23 | Query, SourceChange, SourceFileEdit, Cancelable, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | #[derive(Clone, Debug)] | 26 | #[derive(Clone, Debug)] |
@@ -148,19 +148,21 @@ impl AnalysisImpl { | |||
148 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { | 148 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
149 | self.root(file_id).lines(file_id) | 149 | self.root(file_id).lines(file_id) |
150 | } | 150 | } |
151 | pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 151 | pub fn world_symbols(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
152 | let mut buf = Vec::new(); | 152 | let mut buf = Vec::new(); |
153 | if query.libs { | 153 | if query.libs { |
154 | self.data.libs.iter().for_each(|it| it.symbols(&mut buf)); | 154 | for lib in self.data.libs.iter() { |
155 | lib.symbols(&mut buf)?; | ||
156 | } | ||
155 | } else { | 157 | } else { |
156 | self.data.root.symbols(&mut buf); | 158 | self.data.root.symbols(&mut buf)?; |
157 | } | 159 | } |
158 | query.search(&buf, token) | 160 | Ok(query.search(&buf)) |
159 | } | 161 | } |
160 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { | 162 | pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
161 | let root = self.root(file_id); | 163 | let root = self.root(file_id); |
162 | let module_tree = root.module_tree(); | 164 | let module_tree = root.module_tree()?; |
163 | module_tree | 165 | let res = module_tree |
164 | .parent_modules(file_id) | 166 | .parent_modules(file_id) |
165 | .iter() | 167 | .iter() |
166 | .map(|link| { | 168 | .map(|link| { |
@@ -174,10 +176,11 @@ impl AnalysisImpl { | |||
174 | }; | 176 | }; |
175 | (file_id, sym) | 177 | (file_id, sym) |
176 | }) | 178 | }) |
177 | .collect() | 179 | .collect(); |
180 | Ok(res) | ||
178 | } | 181 | } |
179 | pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> { | 182 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
180 | let module_tree = self.root(file_id).module_tree(); | 183 | let module_tree = self.root(file_id).module_tree()?; |
181 | let crate_graph = &self.data.crate_graph; | 184 | let crate_graph = &self.data.crate_graph; |
182 | let mut res = Vec::new(); | 185 | let mut res = Vec::new(); |
183 | let mut work = VecDeque::new(); | 186 | let mut work = VecDeque::new(); |
@@ -195,7 +198,7 @@ impl AnalysisImpl { | |||
195 | .filter(|&id| visited.insert(id)); | 198 | .filter(|&id| visited.insert(id)); |
196 | work.extend(parents); | 199 | work.extend(parents); |
197 | } | 200 | } |
198 | res | 201 | Ok(res) |
199 | } | 202 | } |
200 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 203 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { |
201 | self.data.crate_graph.crate_roots[&crate_id] | 204 | self.data.crate_graph.crate_roots[&crate_id] |
@@ -204,15 +207,14 @@ impl AnalysisImpl { | |||
204 | &self, | 207 | &self, |
205 | file_id: FileId, | 208 | file_id: FileId, |
206 | offset: TextUnit, | 209 | offset: TextUnit, |
207 | token: &JobToken, | 210 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
208 | ) -> Vec<(FileId, FileSymbol)> { | ||
209 | let root = self.root(file_id); | 211 | let root = self.root(file_id); |
210 | let module_tree = root.module_tree(); | 212 | let module_tree = root.module_tree()?; |
211 | let file = root.syntax(file_id); | 213 | let file = root.syntax(file_id); |
212 | let syntax = file.syntax(); | 214 | let syntax = file.syntax(); |
213 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | 215 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { |
214 | // First try to resolve the symbol locally | 216 | // First try to resolve the symbol locally |
215 | if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { | 217 | return if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { |
216 | let mut vec = vec![]; | 218 | let mut vec = vec![]; |
217 | vec.push(( | 219 | vec.push(( |
218 | file_id, | 220 | file_id, |
@@ -222,12 +224,11 @@ impl AnalysisImpl { | |||
222 | kind: NAME, | 224 | kind: NAME, |
223 | }, | 225 | }, |
224 | )); | 226 | )); |
225 | 227 | Ok(vec) | |
226 | return vec; | ||
227 | } else { | 228 | } else { |
228 | // If that fails try the index based approach. | 229 | // If that fails try the index based approach. |
229 | return self.index_resolve(name_ref, token); | 230 | self.index_resolve(name_ref) |
230 | } | 231 | }; |
231 | } | 232 | } |
232 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { | 233 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { |
233 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 234 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
@@ -250,16 +251,48 @@ impl AnalysisImpl { | |||
250 | }) | 251 | }) |
251 | .collect(); | 252 | .collect(); |
252 | 253 | ||
253 | return res; | 254 | return Ok(res); |
254 | } | 255 | } |
255 | } | 256 | } |
256 | } | 257 | } |
257 | vec![] | 258 | Ok(vec![]) |
258 | } | 259 | } |
259 | 260 | ||
260 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { | 261 | pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, TextRange)> { |
261 | let root = self.root(file_id); | 262 | let root = self.root(file_id); |
262 | let module_tree = root.module_tree(); | 263 | let file = root.syntax(file_id); |
264 | let syntax = file.syntax(); | ||
265 | |||
266 | let mut ret = vec![]; | ||
267 | |||
268 | // Find the symbol we are looking for | ||
269 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { | ||
270 | |||
271 | // We are only handing local references for now | ||
272 | if let Some(resolved) = resolve_local_name(&file, offset, name_ref) { | ||
273 | |||
274 | ret.push((file_id, resolved.1)); | ||
275 | |||
276 | if let Some(fn_def) = find_node_at_offset::<ast::FnDef>(syntax, offset) { | ||
277 | |||
278 | let refs : Vec<_> = fn_def.syntax().descendants() | ||
279 | .filter_map(ast::NameRef::cast) | ||
280 | .filter(|n: &ast::NameRef| resolve_local_name(&file, n.syntax().range().start(), *n) == Some(resolved.clone())) | ||
281 | .collect(); | ||
282 | |||
283 | for r in refs { | ||
284 | ret.push((file_id, r.syntax().range())); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | |||
290 | ret | ||
291 | } | ||
292 | |||
293 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | ||
294 | let root = self.root(file_id); | ||
295 | let module_tree = root.module_tree()?; | ||
263 | let syntax = root.syntax(file_id); | 296 | let syntax = root.syntax(file_id); |
264 | 297 | ||
265 | let mut res = ra_editor::diagnostics(&syntax) | 298 | let mut res = ra_editor::diagnostics(&syntax) |
@@ -314,7 +347,7 @@ impl AnalysisImpl { | |||
314 | }; | 347 | }; |
315 | res.push(diag) | 348 | res.push(diag) |
316 | } | 349 | } |
317 | res | 350 | Ok(res) |
318 | } | 351 | } |
319 | 352 | ||
320 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { | 353 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { |
@@ -347,18 +380,23 @@ impl AnalysisImpl { | |||
347 | &self, | 380 | &self, |
348 | file_id: FileId, | 381 | file_id: FileId, |
349 | offset: TextUnit, | 382 | offset: TextUnit, |
350 | token: &JobToken, | 383 | ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { |
351 | ) -> Option<(FnDescriptor, Option<usize>)> { | ||
352 | let root = self.root(file_id); | 384 | let root = self.root(file_id); |
353 | let file = root.syntax(file_id); | 385 | let file = root.syntax(file_id); |
354 | let syntax = file.syntax(); | 386 | let syntax = file.syntax(); |
355 | 387 | ||
356 | // Find the calling expression and it's NameRef | 388 | // Find the calling expression and it's NameRef |
357 | let calling_node = FnCallNode::with_node(syntax, offset)?; | 389 | let calling_node = match FnCallNode::with_node(syntax, offset) { |
358 | let name_ref = calling_node.name_ref()?; | 390 | Some(node) => node, |
391 | None => return Ok(None), | ||
392 | }; | ||
393 | let name_ref = match calling_node.name_ref() { | ||
394 | Some(name) => name, | ||
395 | None => return Ok(None), | ||
396 | }; | ||
359 | 397 | ||
360 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). | 398 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). |
361 | let file_symbols = self.index_resolve(name_ref, token); | 399 | let file_symbols = self.index_resolve(name_ref)?; |
362 | for (_, fs) in file_symbols { | 400 | for (_, fs) in file_symbols { |
363 | if fs.kind == FN_DEF { | 401 | if fs.kind == FN_DEF { |
364 | if let Some(fn_def) = find_node_at_offset(syntax, fs.node_range.start()) { | 402 | if let Some(fn_def) = find_node_at_offset(syntax, fs.node_range.start()) { |
@@ -400,21 +438,21 @@ impl AnalysisImpl { | |||
400 | } | 438 | } |
401 | } | 439 | } |
402 | 440 | ||
403 | return Some((descriptor, current_parameter)); | 441 | return Ok(Some((descriptor, current_parameter))); |
404 | } | 442 | } |
405 | } | 443 | } |
406 | } | 444 | } |
407 | } | 445 | } |
408 | 446 | ||
409 | None | 447 | Ok(None) |
410 | } | 448 | } |
411 | 449 | ||
412 | fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 450 | fn index_resolve(&self, name_ref: ast::NameRef) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
413 | let name = name_ref.text(); | 451 | let name = name_ref.text(); |
414 | let mut query = Query::new(name.to_string()); | 452 | let mut query = Query::new(name.to_string()); |
415 | query.exact(); | 453 | query.exact(); |
416 | query.limit(4); | 454 | query.limit(4); |
417 | self.world_symbols(query, token) | 455 | self.world_symbols(query) |
418 | } | 456 | } |
419 | 457 | ||
420 | fn resolve_module( | 458 | fn resolve_module( |
diff --git a/crates/ra_analysis/src/job.rs b/crates/ra_analysis/src/job.rs deleted file mode 100644 index 2871f9839..000000000 --- a/crates/ra_analysis/src/job.rs +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | use crossbeam_channel::{bounded, Receiver, Sender}; | ||
2 | |||
3 | pub struct JobHandle { | ||
4 | job_alive: Receiver<Never>, | ||
5 | _job_canceled: Sender<Never>, | ||
6 | } | ||
7 | |||
8 | pub struct JobToken { | ||
9 | _job_alive: Sender<Never>, | ||
10 | job_canceled: Receiver<Never>, | ||
11 | } | ||
12 | |||
13 | impl JobHandle { | ||
14 | pub fn new() -> (JobHandle, JobToken) { | ||
15 | let (sender_alive, receiver_alive) = bounded(0); | ||
16 | let (sender_canceled, receiver_canceled) = bounded(0); | ||
17 | let token = JobToken { | ||
18 | _job_alive: sender_alive, | ||
19 | job_canceled: receiver_canceled, | ||
20 | }; | ||
21 | let handle = JobHandle { | ||
22 | job_alive: receiver_alive, | ||
23 | _job_canceled: sender_canceled, | ||
24 | }; | ||
25 | (handle, token) | ||
26 | } | ||
27 | pub fn has_completed(&self) -> bool { | ||
28 | is_closed(&self.job_alive) | ||
29 | } | ||
30 | pub fn cancel(self) {} | ||
31 | } | ||
32 | |||
33 | impl JobToken { | ||
34 | pub fn is_canceled(&self) -> bool { | ||
35 | is_closed(&self.job_canceled) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | // We don't actually send messages through the channels, | ||
40 | // and instead just check if the channel is closed, | ||
41 | // so we use uninhabited enum as a message type | ||
42 | enum Never {} | ||
43 | |||
44 | /// Nonblocking | ||
45 | fn is_closed(chan: &Receiver<Never>) -> bool { | ||
46 | select! { | ||
47 | recv(chan, msg) => match msg { | ||
48 | None => true, | ||
49 | Some(never) => match never {} | ||
50 | } | ||
51 | default => false, | ||
52 | } | ||
53 | } | ||
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 2eeacaabe..38585f6e9 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -7,36 +7,46 @@ extern crate ra_editor; | |||
7 | extern crate ra_syntax; | 7 | extern crate ra_syntax; |
8 | extern crate rayon; | 8 | extern crate rayon; |
9 | extern crate relative_path; | 9 | extern crate relative_path; |
10 | #[macro_use] | ||
11 | extern crate crossbeam_channel; | ||
12 | extern crate im; | ||
13 | extern crate rustc_hash; | 10 | extern crate rustc_hash; |
14 | extern crate salsa; | 11 | extern crate salsa; |
15 | 12 | ||
16 | mod db; | 13 | mod db; |
17 | mod descriptors; | 14 | mod descriptors; |
18 | mod imp; | 15 | mod imp; |
19 | mod job; | ||
20 | mod module_map; | 16 | mod module_map; |
21 | mod roots; | 17 | mod roots; |
22 | mod symbol_index; | 18 | mod symbol_index; |
23 | 19 | ||
24 | use std::{fmt::Debug, sync::Arc}; | 20 | use std::{fmt::Debug, sync::Arc}; |
25 | 21 | ||
26 | use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}; | ||
27 | use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; | 22 | use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; |
28 | use relative_path::{RelativePath, RelativePathBuf}; | 23 | use relative_path::{RelativePath, RelativePathBuf}; |
29 | use rustc_hash::FxHashMap; | 24 | use rustc_hash::FxHashMap; |
30 | 25 | ||
26 | use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}; | ||
27 | |||
31 | pub use crate::{ | 28 | pub use crate::{ |
32 | descriptors::FnDescriptor, | 29 | descriptors::FnDescriptor, |
33 | job::{JobHandle, JobToken}, | ||
34 | }; | 30 | }; |
35 | pub use ra_editor::{ | 31 | pub use ra_editor::{ |
36 | CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, | 32 | CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, |
37 | RunnableKind, StructureNode, | 33 | RunnableKind, StructureNode, |
38 | }; | 34 | }; |
39 | 35 | ||
36 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
37 | pub struct Canceled; | ||
38 | |||
39 | pub type Cancelable<T> = Result<T, Canceled>; | ||
40 | |||
41 | impl std::fmt::Display for Canceled { | ||
42 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
43 | fmt.write_str("Canceled") | ||
44 | } | ||
45 | } | ||
46 | |||
47 | impl std::error::Error for Canceled { | ||
48 | } | ||
49 | |||
40 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 50 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
41 | pub struct FileId(pub u32); | 51 | pub struct FileId(pub u32); |
42 | 52 | ||
@@ -205,57 +215,57 @@ impl Analysis { | |||
205 | let file = self.imp.file_syntax(file_id); | 215 | let file = self.imp.file_syntax(file_id); |
206 | ra_editor::file_structure(&file) | 216 | ra_editor::file_structure(&file) |
207 | } | 217 | } |
208 | pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { | 218 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { |
209 | self.imp.world_symbols(query, token) | 219 | let file = self.imp.file_syntax(file_id); |
220 | ra_editor::folding_ranges(&file) | ||
221 | } | ||
222 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { | ||
223 | self.imp.world_symbols(query) | ||
210 | } | 224 | } |
211 | pub fn approximately_resolve_symbol( | 225 | pub fn approximately_resolve_symbol( |
212 | &self, | 226 | &self, |
213 | file_id: FileId, | 227 | file_id: FileId, |
214 | offset: TextUnit, | 228 | offset: TextUnit |
215 | token: &JobToken, | 229 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
216 | ) -> Vec<(FileId, FileSymbol)> { | ||
217 | self.imp | 230 | self.imp |
218 | .approximately_resolve_symbol(file_id, offset, token) | 231 | .approximately_resolve_symbol(file_id, offset) |
232 | } | ||
233 | pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, ) -> Cancelable<Vec<(FileId, TextRange)>> { | ||
234 | Ok(self.imp.find_all_refs(file_id, offset)) | ||
219 | } | 235 | } |
220 | pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { | 236 | pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
221 | self.imp.parent_module(file_id) | 237 | self.imp.parent_module(file_id) |
222 | } | 238 | } |
223 | pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> { | 239 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
224 | self.imp.crate_for(file_id) | 240 | self.imp.crate_for(file_id) |
225 | } | 241 | } |
226 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 242 | pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { |
227 | self.imp.crate_root(crate_id) | 243 | Ok(self.imp.crate_root(crate_id)) |
228 | } | 244 | } |
229 | pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> { | 245 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { |
230 | let file = self.imp.file_syntax(file_id); | 246 | let file = self.imp.file_syntax(file_id); |
231 | ra_editor::runnables(&file) | 247 | Ok(ra_editor::runnables(&file)) |
232 | } | 248 | } |
233 | pub fn highlight(&self, file_id: FileId) -> Vec<HighlightedRange> { | 249 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { |
234 | let file = self.imp.file_syntax(file_id); | 250 | let file = self.imp.file_syntax(file_id); |
235 | ra_editor::highlight(&file) | 251 | Ok(ra_editor::highlight(&file)) |
236 | } | 252 | } |
237 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Option<Vec<CompletionItem>> { | 253 | pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> { |
238 | let file = self.imp.file_syntax(file_id); | 254 | let file = self.imp.file_syntax(file_id); |
239 | ra_editor::scope_completion(&file, offset) | 255 | Ok(ra_editor::scope_completion(&file, offset)) |
240 | } | 256 | } |
241 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { | 257 | pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> { |
242 | self.imp.assists(file_id, range) | 258 | Ok(self.imp.assists(file_id, range)) |
243 | } | 259 | } |
244 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { | 260 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
245 | self.imp.diagnostics(file_id) | 261 | self.imp.diagnostics(file_id) |
246 | } | 262 | } |
247 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { | ||
248 | let file = self.imp.file_syntax(file_id); | ||
249 | ra_editor::folding_ranges(&file) | ||
250 | } | ||
251 | |||
252 | pub fn resolve_callable( | 263 | pub fn resolve_callable( |
253 | &self, | 264 | &self, |
254 | file_id: FileId, | 265 | file_id: FileId, |
255 | offset: TextUnit, | 266 | offset: TextUnit, |
256 | token: &JobToken, | 267 | ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> { |
257 | ) -> Option<(FnDescriptor, Option<usize>)> { | 268 | self.imp.resolve_callable(file_id, offset) |
258 | self.imp.resolve_callable(file_id, offset, token) | ||
259 | } | 269 | } |
260 | } | 270 | } |
261 | 271 | ||
diff --git a/crates/ra_analysis/src/module_map.rs b/crates/ra_analysis/src/module_map.rs index ff0ec3cc7..3c800265a 100644 --- a/crates/ra_analysis/src/module_map.rs +++ b/crates/ra_analysis/src/module_map.rs | |||
@@ -1,37 +1,41 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
1 | use crate::{ | 3 | use crate::{ |
4 | db, | ||
5 | Cancelable, | ||
2 | db::SyntaxDatabase, | 6 | db::SyntaxDatabase, |
3 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | 7 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, |
4 | FileId, | 8 | FileId, |
5 | }; | 9 | }; |
6 | 10 | ||
7 | use std::sync::Arc; | ||
8 | |||
9 | salsa::query_group! { | 11 | salsa::query_group! { |
10 | pub(crate) trait ModulesDatabase: SyntaxDatabase { | 12 | pub(crate) trait ModulesDatabase: SyntaxDatabase { |
11 | fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> { | 13 | fn module_tree() -> Cancelable<Arc<ModuleTreeDescriptor>> { |
12 | type ModuleTreeQuery; | 14 | type ModuleTreeQuery; |
13 | } | 15 | } |
14 | fn module_descriptor(file_id: FileId) -> Arc<ModuleDescriptor> { | 16 | fn module_descriptor(file_id: FileId) -> Cancelable<Arc<ModuleDescriptor>> { |
15 | type ModuleDescriptorQuery; | 17 | type ModuleDescriptorQuery; |
16 | } | 18 | } |
17 | } | 19 | } |
18 | } | 20 | } |
19 | 21 | ||
20 | fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { | 22 | fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Cancelable<Arc<ModuleDescriptor>> { |
23 | db::check_canceled(db)?; | ||
21 | let file = db.file_syntax(file_id); | 24 | let file = db.file_syntax(file_id); |
22 | Arc::new(ModuleDescriptor::new(file.ast())) | 25 | Ok(Arc::new(ModuleDescriptor::new(file.ast()))) |
23 | } | 26 | } |
24 | 27 | ||
25 | fn module_tree(db: &impl ModulesDatabase, (): ()) -> Arc<ModuleTreeDescriptor> { | 28 | fn module_tree(db: &impl ModulesDatabase) -> Cancelable<Arc<ModuleTreeDescriptor>> { |
26 | let file_set = db.file_set(()); | 29 | db::check_canceled(db)?; |
30 | let file_set = db.file_set(); | ||
27 | let mut files = Vec::new(); | 31 | let mut files = Vec::new(); |
28 | for &file_id in file_set.files.iter() { | 32 | for &file_id in file_set.files.iter() { |
29 | let module_descr = db.module_descriptor(file_id); | 33 | let module_descr = db.module_descriptor(file_id)?; |
30 | files.push((file_id, module_descr)); | 34 | files.push((file_id, module_descr)); |
31 | } | 35 | } |
32 | let res = ModuleTreeDescriptor::new( | 36 | let res = ModuleTreeDescriptor::new( |
33 | files.iter().map(|(file_id, descr)| (*file_id, &**descr)), | 37 | files.iter().map(|(file_id, descr)| (*file_id, &**descr)), |
34 | &file_set.resolver, | 38 | &file_set.resolver, |
35 | ); | 39 | ); |
36 | Arc::new(res) | 40 | Ok(Arc::new(res)) |
37 | } | 41 | } |
diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs index 1f2b21b27..123c4acfa 100644 --- a/crates/ra_analysis/src/roots.rs +++ b/crates/ra_analysis/src/roots.rs | |||
@@ -8,6 +8,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
8 | use salsa::Database; | 8 | use salsa::Database; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | Cancelable, | ||
11 | db::{self, FilesDatabase, SyntaxDatabase}, | 12 | db::{self, FilesDatabase, SyntaxDatabase}, |
12 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | 13 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, |
13 | imp::FileResolverImp, | 14 | imp::FileResolverImp, |
@@ -18,10 +19,10 @@ use crate::{ | |||
18 | 19 | ||
19 | pub(crate) trait SourceRoot { | 20 | pub(crate) trait SourceRoot { |
20 | fn contains(&self, file_id: FileId) -> bool; | 21 | fn contains(&self, file_id: FileId) -> bool; |
21 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor>; | 22 | fn module_tree(&self) -> Cancelable<Arc<ModuleTreeDescriptor>>; |
22 | fn lines(&self, file_id: FileId) -> Arc<LineIndex>; | 23 | fn lines(&self, file_id: FileId) -> Arc<LineIndex>; |
23 | fn syntax(&self, file_id: FileId) -> File; | 24 | fn syntax(&self, file_id: FileId) -> File; |
24 | fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>); | 25 | fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>) -> Cancelable<()>; |
25 | } | 26 | } |
26 | 27 | ||
27 | #[derive(Default, Debug, Clone)] | 28 | #[derive(Default, Debug, Clone)] |
@@ -50,7 +51,7 @@ impl WritableSourceRoot { | |||
50 | } | 51 | } |
51 | } | 52 | } |
52 | } | 53 | } |
53 | let file_set = self.db.file_set(()); | 54 | let file_set = self.db.file_set(); |
54 | let mut files: FxHashSet<FileId> = file_set.files.clone(); | 55 | let mut files: FxHashSet<FileId> = file_set.files.clone(); |
55 | for file_id in removed { | 56 | for file_id in removed { |
56 | files.remove(&file_id); | 57 | files.remove(&file_id); |
@@ -64,11 +65,11 @@ impl WritableSourceRoot { | |||
64 | } | 65 | } |
65 | 66 | ||
66 | impl SourceRoot for WritableSourceRoot { | 67 | impl SourceRoot for WritableSourceRoot { |
67 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor> { | 68 | fn module_tree(&self) -> Cancelable<Arc<ModuleTreeDescriptor>> { |
68 | self.db.module_tree(()) | 69 | self.db.module_tree() |
69 | } | 70 | } |
70 | fn contains(&self, file_id: FileId) -> bool { | 71 | fn contains(&self, file_id: FileId) -> bool { |
71 | self.db.file_set(()).files.contains(&file_id) | 72 | self.db.file_set().files.contains(&file_id) |
72 | } | 73 | } |
73 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { | 74 | fn lines(&self, file_id: FileId) -> Arc<LineIndex> { |
74 | self.db.file_lines(file_id) | 75 | self.db.file_lines(file_id) |
@@ -76,14 +77,12 @@ impl SourceRoot for WritableSourceRoot { | |||
76 | fn syntax(&self, file_id: FileId) -> File { | 77 | fn syntax(&self, file_id: FileId) -> File { |
77 | self.db.file_syntax(file_id) | 78 | self.db.file_syntax(file_id) |
78 | } | 79 | } |
79 | fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) { | 80 | fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) -> Cancelable<()> { |
80 | let db = &self.db; | 81 | for &file_id in self.db.file_set().files.iter() { |
81 | let symbols = db.file_set(()); | 82 | let symbols = self.db.file_symbols(file_id)?; |
82 | let symbols = symbols | 83 | acc.push(symbols) |
83 | .files | 84 | } |
84 | .iter() | 85 | Ok(()) |
85 | .map(|&file_id| db.file_symbols(file_id)); | ||
86 | acc.extend(symbols); | ||
87 | } | 86 | } |
88 | } | 87 | } |
89 | 88 | ||
@@ -167,8 +166,8 @@ impl ReadonlySourceRoot { | |||
167 | } | 166 | } |
168 | 167 | ||
169 | impl SourceRoot for ReadonlySourceRoot { | 168 | impl SourceRoot for ReadonlySourceRoot { |
170 | fn module_tree(&self) -> Arc<ModuleTreeDescriptor> { | 169 | fn module_tree(&self) -> Cancelable<Arc<ModuleTreeDescriptor>> { |
171 | Arc::clone(&self.module_tree) | 170 | Ok(Arc::clone(&self.module_tree)) |
172 | } | 171 | } |
173 | fn contains(&self, file_id: FileId) -> bool { | 172 | fn contains(&self, file_id: FileId) -> bool { |
174 | self.file_map.contains_key(&file_id) | 173 | self.file_map.contains_key(&file_id) |
@@ -179,7 +178,8 @@ impl SourceRoot for ReadonlySourceRoot { | |||
179 | fn syntax(&self, file_id: FileId) -> File { | 178 | fn syntax(&self, file_id: FileId) -> File { |
180 | self.data(file_id).syntax().clone() | 179 | self.data(file_id).syntax().clone() |
181 | } | 180 | } |
182 | fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>) { | 181 | fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>) -> Cancelable<()> { |
183 | acc.push(Arc::clone(&self.symbol_index)) | 182 | acc.push(Arc::clone(&self.symbol_index)); |
183 | Ok(()) | ||
184 | } | 184 | } |
185 | } | 185 | } |
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 51eef8170..a0f3c0437 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs | |||
@@ -1,4 +1,8 @@ | |||
1 | use crate::{FileId, JobToken, Query}; | 1 | use std::{ |
2 | hash::{Hash, Hasher}, | ||
3 | sync::Arc, | ||
4 | }; | ||
5 | |||
2 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
3 | use ra_editor::{file_symbols, FileSymbol}; | 7 | use ra_editor::{file_symbols, FileSymbol}; |
4 | use ra_syntax::{ | 8 | use ra_syntax::{ |
@@ -7,10 +11,7 @@ use ra_syntax::{ | |||
7 | }; | 11 | }; |
8 | use rayon::prelude::*; | 12 | use rayon::prelude::*; |
9 | 13 | ||
10 | use std::{ | 14 | use crate::{FileId, Query}; |
11 | hash::{Hash, Hasher}, | ||
12 | sync::Arc, | ||
13 | }; | ||
14 | 15 | ||
15 | #[derive(Debug)] | 16 | #[derive(Debug)] |
16 | pub(crate) struct SymbolIndex { | 17 | pub(crate) struct SymbolIndex { |
@@ -59,7 +60,6 @@ impl Query { | |||
59 | pub(crate) fn search( | 60 | pub(crate) fn search( |
60 | self, | 61 | self, |
61 | indices: &[Arc<SymbolIndex>], | 62 | indices: &[Arc<SymbolIndex>], |
62 | token: &JobToken, | ||
63 | ) -> Vec<(FileId, FileSymbol)> { | 63 | ) -> Vec<(FileId, FileSymbol)> { |
64 | let mut op = fst::map::OpBuilder::new(); | 64 | let mut op = fst::map::OpBuilder::new(); |
65 | for file_symbols in indices.iter() { | 65 | for file_symbols in indices.iter() { |
@@ -69,7 +69,7 @@ impl Query { | |||
69 | let mut stream = op.union(); | 69 | let mut stream = op.union(); |
70 | let mut res = Vec::new(); | 70 | let mut res = Vec::new(); |
71 | while let Some((_, indexed_values)) = stream.next() { | 71 | while let Some((_, indexed_values)) = stream.next() { |
72 | if res.len() >= self.limit || token.is_canceled() { | 72 | if res.len() >= self.limit { |
73 | break; | 73 | break; |
74 | } | 74 | } |
75 | for indexed_value in indexed_values { | 75 | for indexed_value in indexed_values { |
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index e0c637d65..7ae3d0eeb 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs | |||
@@ -7,13 +7,15 @@ extern crate test_utils; | |||
7 | 7 | ||
8 | use std::sync::Arc; | 8 | use std::sync::Arc; |
9 | 9 | ||
10 | use ra_analysis::{ | 10 | use ra_syntax::TextRange; |
11 | Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle, | ||
12 | }; | ||
13 | use relative_path::{RelativePath, RelativePathBuf}; | 11 | use relative_path::{RelativePath, RelativePathBuf}; |
14 | use rustc_hash::FxHashMap; | 12 | use rustc_hash::FxHashMap; |
15 | use test_utils::{assert_eq_dbg, extract_offset}; | 13 | use test_utils::{assert_eq_dbg, extract_offset}; |
16 | 14 | ||
15 | use ra_analysis::{ | ||
16 | Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, | ||
17 | }; | ||
18 | |||
17 | #[derive(Debug)] | 19 | #[derive(Debug)] |
18 | struct FileMap(Vec<(FileId, RelativePathBuf)>); | 20 | struct FileMap(Vec<(FileId, RelativePathBuf)>); |
19 | 21 | ||
@@ -62,24 +64,22 @@ fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) { | |||
62 | let (offset, code) = extract_offset(text); | 64 | let (offset, code) = extract_offset(text); |
63 | let code = code.as_str(); | 65 | let code = code.as_str(); |
64 | 66 | ||
65 | let (_handle, token) = JobHandle::new(); | ||
66 | let snap = analysis(&[("/lib.rs", code)]); | 67 | let snap = analysis(&[("/lib.rs", code)]); |
67 | 68 | ||
68 | snap.resolve_callable(FileId(1), offset, &token).unwrap() | 69 | snap.resolve_callable(FileId(1), offset).unwrap().unwrap() |
69 | } | 70 | } |
70 | 71 | ||
71 | #[test] | 72 | #[test] |
72 | fn test_resolve_module() { | 73 | fn test_resolve_module() { |
73 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); | 74 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); |
74 | let (_handle, token) = JobHandle::new(); | 75 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()).unwrap(); |
75 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); | ||
76 | assert_eq_dbg( | 76 | assert_eq_dbg( |
77 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, | 77 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, |
78 | &symbols, | 78 | &symbols, |
79 | ); | 79 | ); |
80 | 80 | ||
81 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]); | 81 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]); |
82 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); | 82 | let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()).unwrap(); |
83 | assert_eq_dbg( | 83 | assert_eq_dbg( |
84 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, | 84 | r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, |
85 | &symbols, | 85 | &symbols, |
@@ -89,7 +89,7 @@ fn test_resolve_module() { | |||
89 | #[test] | 89 | #[test] |
90 | fn test_unresolved_module_diagnostic() { | 90 | fn test_unresolved_module_diagnostic() { |
91 | let snap = analysis(&[("/lib.rs", "mod foo;")]); | 91 | let snap = analysis(&[("/lib.rs", "mod foo;")]); |
92 | let diagnostics = snap.diagnostics(FileId(1)); | 92 | let diagnostics = snap.diagnostics(FileId(1)).unwrap(); |
93 | assert_eq_dbg( | 93 | assert_eq_dbg( |
94 | r#"[Diagnostic { | 94 | r#"[Diagnostic { |
95 | message: "unresolved module", | 95 | message: "unresolved module", |
@@ -106,14 +106,14 @@ fn test_unresolved_module_diagnostic() { | |||
106 | #[test] | 106 | #[test] |
107 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { | 107 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { |
108 | let snap = analysis(&[("/lib.rs", "mod foo {}")]); | 108 | let snap = analysis(&[("/lib.rs", "mod foo {}")]); |
109 | let diagnostics = snap.diagnostics(FileId(1)); | 109 | let diagnostics = snap.diagnostics(FileId(1)).unwrap(); |
110 | assert_eq_dbg(r#"[]"#, &diagnostics); | 110 | assert_eq_dbg(r#"[]"#, &diagnostics); |
111 | } | 111 | } |
112 | 112 | ||
113 | #[test] | 113 | #[test] |
114 | fn test_resolve_parent_module() { | 114 | fn test_resolve_parent_module() { |
115 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); | 115 | let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); |
116 | let symbols = snap.parent_module(FileId(2)); | 116 | let symbols = snap.parent_module(FileId(2)).unwrap(); |
117 | assert_eq_dbg( | 117 | assert_eq_dbg( |
118 | r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, | 118 | r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, |
119 | &symbols, | 119 | &symbols, |
@@ -124,7 +124,7 @@ fn test_resolve_parent_module() { | |||
124 | fn test_resolve_crate_root() { | 124 | fn test_resolve_crate_root() { |
125 | let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); | 125 | let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); |
126 | let snap = host.analysis(); | 126 | let snap = host.analysis(); |
127 | assert!(snap.crate_for(FileId(2)).is_empty()); | 127 | assert!(snap.crate_for(FileId(2)).unwrap().is_empty()); |
128 | 128 | ||
129 | let crate_graph = CrateGraph { | 129 | let crate_graph = CrateGraph { |
130 | crate_roots: { | 130 | crate_roots: { |
@@ -136,7 +136,7 @@ fn test_resolve_crate_root() { | |||
136 | host.set_crate_graph(crate_graph); | 136 | host.set_crate_graph(crate_graph); |
137 | let snap = host.analysis(); | 137 | let snap = host.analysis(); |
138 | 138 | ||
139 | assert_eq!(snap.crate_for(FileId(2)), vec![CrateId(1)],); | 139 | assert_eq!(snap.crate_for(FileId(2)).unwrap(), vec![CrateId(1)],); |
140 | } | 140 | } |
141 | 141 | ||
142 | #[test] | 142 | #[test] |
@@ -225,3 +225,42 @@ fn bar() { | |||
225 | assert_eq!(desc.ret_type, None); | 225 | assert_eq!(desc.ret_type, None); |
226 | assert_eq!(param, Some(1)); | 226 | assert_eq!(param, Some(1)); |
227 | } | 227 | } |
228 | |||
229 | fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> { | ||
230 | let (offset, code) = extract_offset(text); | ||
231 | let code = code.as_str(); | ||
232 | |||
233 | let snap = analysis(&[("/lib.rs", code)]); | ||
234 | |||
235 | snap.find_all_refs(FileId(1), offset).unwrap() | ||
236 | } | ||
237 | |||
238 | #[test] | ||
239 | fn test_find_all_refs_for_local() { | ||
240 | let code = r#" | ||
241 | fn main() { | ||
242 | let mut i = 1; | ||
243 | let j = 1; | ||
244 | i = i<|> + j; | ||
245 | |||
246 | { | ||
247 | i = 0; | ||
248 | } | ||
249 | |||
250 | i = 5; | ||
251 | }"#; | ||
252 | |||
253 | let refs = get_all_refs(code); | ||
254 | assert_eq!(refs.len(), 5); | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn test_find_all_refs_for_param_inside() { | ||
259 | let code = r#" | ||
260 | fn foo(i : u32) -> u32 { | ||
261 | i<|> | ||
262 | }"#; | ||
263 | |||
264 | let refs = get_all_refs(code); | ||
265 | assert_eq!(refs.len(), 2); | ||
266 | } | ||