aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-10-20 21:04:06 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-10-20 21:04:06 +0100
commitfd336d1134d405d833b762101a25c00076bc7fd2 (patch)
tree040ab6dc1286ab9fe5da0002d29ae4eb7a37850a /crates/ra_analysis
parent73dd870da2dcc991b0fdcdde8bee91f05cb9e182 (diff)
parent0102a01f76c855da447e25eb81191047a3ca79b8 (diff)
Merge #147
147: Cancelation r=matklad a=matklad This series of commits switch cancellation strategy from `JobToken` (which are cancellation tokens, explicitly controlled by the called) to salsa built-in auto cancellation. "Auto" means that, as soon as we advance the revision, all pending queries are cancelled automatically, and this looks like a semantic we actually want. "client-side" cancellation is a rare event, and it's ok to just punt on it. Automatic cancellation after the user types something in happens all the time. Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/Cargo.toml1
-rw-r--r--crates/ra_analysis/src/db.rs34
-rw-r--r--crates/ra_analysis/src/descriptors.rs5
-rw-r--r--crates/ra_analysis/src/imp.rs78
-rw-r--r--crates/ra_analysis/src/job.rs53
-rw-r--r--crates/ra_analysis/src/lib.rs76
-rw-r--r--crates/ra_analysis/src/module_map.rs22
-rw-r--r--crates/ra_analysis/src/roots.rs30
-rw-r--r--crates/ra_analysis/src/symbol_index.rs14
-rw-r--r--crates/ra_analysis/tests/tests.rs31
10 files changed, 159 insertions, 185 deletions
diff --git a/crates/ra_analysis/Cargo.toml b/crates/ra_analysis/Cargo.toml
index dd4ec8375..d7ac69fe8 100644
--- a/crates/ra_analysis/Cargo.toml
+++ b/crates/ra_analysis/Cargo.toml
@@ -7,7 +7,6 @@ authors = ["Aleksey Kladov <[email protected]>"]
7[dependencies] 7[dependencies]
8relative-path = "0.3.7" 8relative-path = "0.3.7"
9log = "0.4.2" 9log = "0.4.2"
10crossbeam-channel = "0.2.4"
11parking_lot = "0.6.3" 10parking_lot = "0.6.3"
12once_cell = "0.1.5" 11once_cell = "0.1.5"
13rayon = "1.0.2" 12rayon = "1.0.2"
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index cce959669..09d74b9e7 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,17 +1,20 @@
1use crate::{ 1use 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
6use ra_editor::LineIndex; 7use ra_editor::LineIndex;
7use ra_syntax::File; 8use ra_syntax::File;
8use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
9use salsa; 10use salsa;
10 11
11use std::{ 12use 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)]
@@ -31,6 +34,14 @@ impl salsa::Database for RootDatabase {
31 } 34 }
32} 35}
33 36
37pub(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
34impl salsa::ParallelDatabase for RootDatabase { 45impl salsa::ParallelDatabase for RootDatabase {
35 fn fork(&self) -> Self { 46 fn fork(&self) -> Self {
36 RootDatabase { 47 RootDatabase {
@@ -98,7 +109,7 @@ salsa::query_group! {
98 fn file_lines(file_id: FileId) -> Arc<LineIndex> { 109 fn file_lines(file_id: FileId) -> Arc<LineIndex> {
99 type FileLinesQuery; 110 type FileLinesQuery;
100 } 111 }
101 fn file_symbols(file_id: FileId) -> Arc<SymbolIndex> { 112 fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> {
102 type FileSymbolsQuery; 113 type FileSymbolsQuery;
103 } 114 }
104 } 115 }
@@ -112,7 +123,8 @@ fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> {
112 let text = db.file_text(file_id); 123 let text = db.file_text(file_id);
113 Arc::new(LineIndex::new(&*text)) 124 Arc::new(LineIndex::new(&*text))
114} 125}
115fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<SymbolIndex> { 126fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> {
127 db::check_canceled(db)?;
116 let syntax = db.file_syntax(file_id); 128 let syntax = db.file_syntax(file_id);
117 Arc::new(SymbolIndex::for_file(file_id, syntax)) 129 Ok(Arc::new(SymbolIndex::for_file(file_id, syntax)))
118} 130}
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs
index 6f26f9935..310bf1585 100644
--- a/crates/ra_analysis/src/descriptors.rs
+++ b/crates/ra_analysis/src/descriptors.rs
@@ -1,4 +1,5 @@
1use crate::{imp::FileResolverImp, FileId}; 1use std::collections::BTreeMap;
2
2use ra_syntax::{ 3use 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};
7use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
8 9
9use std::collections::BTreeMap; 10use crate::{imp::FileResolverImp, FileId};
10 11
11#[derive(Debug, PartialEq, Eq, Hash)] 12#[derive(Debug, PartialEq, Eq, Hash)]
12pub struct ModuleDescriptor { 13pub struct ModuleDescriptor {
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index a67b1717a..32e9bb6d7 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -19,8 +19,8 @@ use rustc_hash::FxHashSet;
19use crate::{ 19use 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,14 +251,14 @@ 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 find_all_refs(&self, file_id: FileId, offset: TextUnit, _token: &JobToken) -> Vec<(FileId, TextRange)> { 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 file = root.syntax(file_id); 263 let file = root.syntax(file_id);
263 let syntax = file.syntax(); 264 let syntax = file.syntax();
@@ -289,9 +290,9 @@ impl AnalysisImpl {
289 ret 290 ret
290 } 291 }
291 292
292 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 293 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
293 let root = self.root(file_id); 294 let root = self.root(file_id);
294 let module_tree = root.module_tree(); 295 let module_tree = root.module_tree()?;
295 let syntax = root.syntax(file_id); 296 let syntax = root.syntax(file_id);
296 297
297 let mut res = ra_editor::diagnostics(&syntax) 298 let mut res = ra_editor::diagnostics(&syntax)
@@ -346,7 +347,7 @@ impl AnalysisImpl {
346 }; 347 };
347 res.push(diag) 348 res.push(diag)
348 } 349 }
349 res 350 Ok(res)
350 } 351 }
351 352
352 pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { 353 pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> {
@@ -379,18 +380,23 @@ impl AnalysisImpl {
379 &self, 380 &self,
380 file_id: FileId, 381 file_id: FileId,
381 offset: TextUnit, 382 offset: TextUnit,
382 token: &JobToken, 383 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> {
383 ) -> Option<(FnDescriptor, Option<usize>)> {
384 let root = self.root(file_id); 384 let root = self.root(file_id);
385 let file = root.syntax(file_id); 385 let file = root.syntax(file_id);
386 let syntax = file.syntax(); 386 let syntax = file.syntax();
387 387
388 // Find the calling expression and it's NameRef 388 // Find the calling expression and it's NameRef
389 let calling_node = FnCallNode::with_node(syntax, offset)?; 389 let calling_node = match FnCallNode::with_node(syntax, offset) {
390 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 };
391 397
392 // Resolve the function's NameRef (NOTE: this isn't entirely accurate). 398 // Resolve the function's NameRef (NOTE: this isn't entirely accurate).
393 let file_symbols = self.index_resolve(name_ref, token); 399 let file_symbols = self.index_resolve(name_ref)?;
394 for (_, fs) in file_symbols { 400 for (_, fs) in file_symbols {
395 if fs.kind == FN_DEF { 401 if fs.kind == FN_DEF {
396 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()) {
@@ -432,21 +438,21 @@ impl AnalysisImpl {
432 } 438 }
433 } 439 }
434 440
435 return Some((descriptor, current_parameter)); 441 return Ok(Some((descriptor, current_parameter)));
436 } 442 }
437 } 443 }
438 } 444 }
439 } 445 }
440 446
441 None 447 Ok(None)
442 } 448 }
443 449
444 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)>> {
445 let name = name_ref.text(); 451 let name = name_ref.text();
446 let mut query = Query::new(name.to_string()); 452 let mut query = Query::new(name.to_string());
447 query.exact(); 453 query.exact();
448 query.limit(4); 454 query.limit(4);
449 self.world_symbols(query, token) 455 self.world_symbols(query)
450 } 456 }
451 457
452 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 @@
1use crossbeam_channel::{bounded, Receiver, Sender};
2
3pub struct JobHandle {
4 job_alive: Receiver<Never>,
5 _job_canceled: Sender<Never>,
6}
7
8pub struct JobToken {
9 _job_alive: Sender<Never>,
10 job_canceled: Receiver<Never>,
11}
12
13impl 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
33impl 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
42enum Never {}
43
44/// Nonblocking
45fn 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 46cc0722b..28e0a12b2 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -7,8 +7,6 @@ extern crate ra_editor;
7extern crate ra_syntax; 7extern crate ra_syntax;
8extern crate rayon; 8extern crate rayon;
9extern crate relative_path; 9extern crate relative_path;
10#[macro_use]
11extern crate crossbeam_channel;
12extern crate im; 10extern crate im;
13extern crate rustc_hash; 11extern crate rustc_hash;
14extern crate salsa; 12extern crate salsa;
@@ -16,27 +14,40 @@ extern crate salsa;
16mod db; 14mod db;
17mod descriptors; 15mod descriptors;
18mod imp; 16mod imp;
19mod job;
20mod module_map; 17mod module_map;
21mod roots; 18mod roots;
22mod symbol_index; 19mod symbol_index;
23 20
24use std::{fmt::Debug, sync::Arc}; 21use std::{fmt::Debug, sync::Arc};
25 22
26use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp};
27use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; 23use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
28use relative_path::{RelativePath, RelativePathBuf}; 24use relative_path::{RelativePath, RelativePathBuf};
29use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
30 26
27use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp};
28
31pub use crate::{ 29pub use crate::{
32 descriptors::FnDescriptor, 30 descriptors::FnDescriptor,
33 job::{JobHandle, JobToken},
34}; 31};
35pub use ra_editor::{ 32pub use ra_editor::{
36 CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, 33 CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable,
37 RunnableKind, StructureNode, 34 RunnableKind, StructureNode,
38}; 35};
39 36
37#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
38pub struct Canceled;
39
40pub type Cancelable<T> = Result<T, Canceled>;
41
42impl std::fmt::Display for Canceled {
43 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 fmt.write_str("Canceled")
45 }
46}
47
48impl std::error::Error for Canceled {
49}
50
40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 51#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub struct FileId(pub u32); 52pub struct FileId(pub u32);
42 53
@@ -205,60 +216,57 @@ impl Analysis {
205 let file = self.imp.file_syntax(file_id); 216 let file = self.imp.file_syntax(file_id);
206 ra_editor::file_structure(&file) 217 ra_editor::file_structure(&file)
207 } 218 }
208 pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 219 pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> {
209 self.imp.world_symbols(query, token) 220 let file = self.imp.file_syntax(file_id);
221 ra_editor::folding_ranges(&file)
222 }
223 pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> {
224 self.imp.world_symbols(query)
210 } 225 }
211 pub fn approximately_resolve_symbol( 226 pub fn approximately_resolve_symbol(
212 &self, 227 &self,
213 file_id: FileId, 228 file_id: FileId,
214 offset: TextUnit, 229 offset: TextUnit
215 token: &JobToken, 230 ) -> Cancelable<Vec<(FileId, FileSymbol)>> {
216 ) -> Vec<(FileId, FileSymbol)> {
217 self.imp 231 self.imp
218 .approximately_resolve_symbol(file_id, offset, token) 232 .approximately_resolve_symbol(file_id, offset)
219 } 233 }
220 pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, TextRange)> { 234 pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, ) -> Cancelable<Vec<(FileId, TextRange)>> {
221 self.imp.find_all_refs(file_id, offset, token) 235 Ok(self.imp.find_all_refs(file_id, offset))
222 } 236 }
223 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { 237 pub fn parent_module(&self, file_id: FileId) -> Cancelable<Vec<(FileId, FileSymbol)>> {
224 self.imp.parent_module(file_id) 238 self.imp.parent_module(file_id)
225 } 239 }
226 pub fn crate_for(&self, file_id: FileId) -> Vec<CrateId> { 240 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
227 self.imp.crate_for(file_id) 241 self.imp.crate_for(file_id)
228 } 242 }
229 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 243 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
230 self.imp.crate_root(crate_id) 244 Ok(self.imp.crate_root(crate_id))
231 } 245 }
232 pub fn runnables(&self, file_id: FileId) -> Vec<Runnable> { 246 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
233 let file = self.imp.file_syntax(file_id); 247 let file = self.imp.file_syntax(file_id);
234 ra_editor::runnables(&file) 248 Ok(ra_editor::runnables(&file))
235 } 249 }
236 pub fn highlight(&self, file_id: FileId) -> Vec<HighlightedRange> { 250 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> {
237 let file = self.imp.file_syntax(file_id); 251 let file = self.imp.file_syntax(file_id);
238 ra_editor::highlight(&file) 252 Ok(ra_editor::highlight(&file))
239 } 253 }
240 pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Option<Vec<CompletionItem>> { 254 pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable<Option<Vec<CompletionItem>>> {
241 let file = self.imp.file_syntax(file_id); 255 let file = self.imp.file_syntax(file_id);
242 ra_editor::scope_completion(&file, offset) 256 Ok(ra_editor::scope_completion(&file, offset))
243 } 257 }
244 pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec<SourceChange> { 258 pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable<Vec<SourceChange>> {
245 self.imp.assists(file_id, range) 259 Ok(self.imp.assists(file_id, range))
246 } 260 }
247 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 261 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
248 self.imp.diagnostics(file_id) 262 self.imp.diagnostics(file_id)
249 } 263 }
250 pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> {
251 let file = self.imp.file_syntax(file_id);
252 ra_editor::folding_ranges(&file)
253 }
254
255 pub fn resolve_callable( 264 pub fn resolve_callable(
256 &self, 265 &self,
257 file_id: FileId, 266 file_id: FileId,
258 offset: TextUnit, 267 offset: TextUnit,
259 token: &JobToken, 268 ) -> Cancelable<Option<(FnDescriptor, Option<usize>)>> {
260 ) -> Option<(FnDescriptor, Option<usize>)> { 269 self.imp.resolve_callable(file_id, offset)
261 self.imp.resolve_callable(file_id, offset, token)
262 } 270 }
263} 271}
264 272
diff --git a/crates/ra_analysis/src/module_map.rs b/crates/ra_analysis/src/module_map.rs
index b15432498..3c800265a 100644
--- a/crates/ra_analysis/src/module_map.rs
+++ b/crates/ra_analysis/src/module_map.rs
@@ -1,37 +1,41 @@
1use std::sync::Arc;
2
1use crate::{ 3use 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
7use std::sync::Arc;
8
9salsa::query_group! { 11salsa::query_group! {
10 pub(crate) trait ModulesDatabase: SyntaxDatabase { 12 pub(crate) trait ModulesDatabase: SyntaxDatabase {
11 fn module_tree() -> 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
20fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { 22fn 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
25fn module_tree(db: &impl ModulesDatabase) -> Arc<ModuleTreeDescriptor> { 28fn module_tree(db: &impl ModulesDatabase) -> Cancelable<Arc<ModuleTreeDescriptor>> {
29 db::check_canceled(db)?;
26 let file_set = db.file_set(); 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 19c84df65..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};
8use salsa::Database; 8use salsa::Database;
9 9
10use crate::{ 10use 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
19pub(crate) trait SourceRoot { 20pub(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)]
@@ -64,7 +65,7 @@ impl WritableSourceRoot {
64} 65}
65 66
66impl SourceRoot for WritableSourceRoot { 67impl 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 {
@@ -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
169impl SourceRoot for ReadonlySourceRoot { 168impl 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 @@
1use crate::{FileId, JobToken, Query}; 1use std::{
2 hash::{Hash, Hasher},
3 sync::Arc,
4};
5
2use fst::{self, Streamer}; 6use fst::{self, Streamer};
3use ra_editor::{file_symbols, FileSymbol}; 7use ra_editor::{file_symbols, FileSymbol};
4use ra_syntax::{ 8use ra_syntax::{
@@ -7,10 +11,7 @@ use ra_syntax::{
7}; 11};
8use rayon::prelude::*; 12use rayon::prelude::*;
9 13
10use std::{ 14use crate::{FileId, Query};
11 hash::{Hash, Hasher},
12 sync::Arc,
13};
14 15
15#[derive(Debug)] 16#[derive(Debug)]
16pub(crate) struct SymbolIndex { 17pub(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 0c2c69ea0..7ae3d0eeb 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -7,15 +7,15 @@ extern crate test_utils;
7 7
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use ra_analysis::{
11 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle,
12};
13use ra_syntax::TextRange; 10use ra_syntax::TextRange;
14
15use relative_path::{RelativePath, RelativePathBuf}; 11use relative_path::{RelativePath, RelativePathBuf};
16use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
17use test_utils::{assert_eq_dbg, extract_offset}; 13use test_utils::{assert_eq_dbg, extract_offset};
18 14
15use ra_analysis::{
16 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor,
17};
18
19#[derive(Debug)] 19#[derive(Debug)]
20struct FileMap(Vec<(FileId, RelativePathBuf)>); 20struct FileMap(Vec<(FileId, RelativePathBuf)>);
21 21
@@ -64,24 +64,22 @@ fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
64 let (offset, code) = extract_offset(text); 64 let (offset, code) = extract_offset(text);
65 let code = code.as_str(); 65 let code = code.as_str();
66 66
67 let (_handle, token) = JobHandle::new();
68 let snap = analysis(&[("/lib.rs", code)]); 67 let snap = analysis(&[("/lib.rs", code)]);
69 68
70 snap.resolve_callable(FileId(1), offset, &token).unwrap() 69 snap.resolve_callable(FileId(1), offset).unwrap().unwrap()
71} 70}
72 71
73#[test] 72#[test]
74fn test_resolve_module() { 73fn test_resolve_module() {
75 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); 74 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
76 let (_handle, token) = JobHandle::new(); 75 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()).unwrap();
77 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
78 assert_eq_dbg( 76 assert_eq_dbg(
79 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 })]"#,
80 &symbols, 78 &symbols,
81 ); 79 );
82 80
83 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]); 81 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]);
84 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); 82 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()).unwrap();
85 assert_eq_dbg( 83 assert_eq_dbg(
86 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 })]"#,
87 &symbols, 85 &symbols,
@@ -91,7 +89,7 @@ fn test_resolve_module() {
91#[test] 89#[test]
92fn test_unresolved_module_diagnostic() { 90fn test_unresolved_module_diagnostic() {
93 let snap = analysis(&[("/lib.rs", "mod foo;")]); 91 let snap = analysis(&[("/lib.rs", "mod foo;")]);
94 let diagnostics = snap.diagnostics(FileId(1)); 92 let diagnostics = snap.diagnostics(FileId(1)).unwrap();
95 assert_eq_dbg( 93 assert_eq_dbg(
96 r#"[Diagnostic { 94 r#"[Diagnostic {
97 message: "unresolved module", 95 message: "unresolved module",
@@ -108,14 +106,14 @@ fn test_unresolved_module_diagnostic() {
108#[test] 106#[test]
109fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 107fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
110 let snap = analysis(&[("/lib.rs", "mod foo {}")]); 108 let snap = analysis(&[("/lib.rs", "mod foo {}")]);
111 let diagnostics = snap.diagnostics(FileId(1)); 109 let diagnostics = snap.diagnostics(FileId(1)).unwrap();
112 assert_eq_dbg(r#"[]"#, &diagnostics); 110 assert_eq_dbg(r#"[]"#, &diagnostics);
113} 111}
114 112
115#[test] 113#[test]
116fn test_resolve_parent_module() { 114fn test_resolve_parent_module() {
117 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); 115 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
118 let symbols = snap.parent_module(FileId(2)); 116 let symbols = snap.parent_module(FileId(2)).unwrap();
119 assert_eq_dbg( 117 assert_eq_dbg(
120 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 })]"#,
121 &symbols, 119 &symbols,
@@ -126,7 +124,7 @@ fn test_resolve_parent_module() {
126fn test_resolve_crate_root() { 124fn test_resolve_crate_root() {
127 let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); 125 let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
128 let snap = host.analysis(); 126 let snap = host.analysis();
129 assert!(snap.crate_for(FileId(2)).is_empty()); 127 assert!(snap.crate_for(FileId(2)).unwrap().is_empty());
130 128
131 let crate_graph = CrateGraph { 129 let crate_graph = CrateGraph {
132 crate_roots: { 130 crate_roots: {
@@ -138,7 +136,7 @@ fn test_resolve_crate_root() {
138 host.set_crate_graph(crate_graph); 136 host.set_crate_graph(crate_graph);
139 let snap = host.analysis(); 137 let snap = host.analysis();
140 138
141 assert_eq!(snap.crate_for(FileId(2)), vec![CrateId(1)],); 139 assert_eq!(snap.crate_for(FileId(2)).unwrap(), vec![CrateId(1)],);
142} 140}
143 141
144#[test] 142#[test]
@@ -232,10 +230,9 @@ fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
232 let (offset, code) = extract_offset(text); 230 let (offset, code) = extract_offset(text);
233 let code = code.as_str(); 231 let code = code.as_str();
234 232
235 let (_handle, token) = JobHandle::new();
236 let snap = analysis(&[("/lib.rs", code)]); 233 let snap = analysis(&[("/lib.rs", code)]);
237 234
238 snap.find_all_refs(FileId(1), offset, &token) 235 snap.find_all_refs(FileId(1), offset).unwrap()
239} 236}
240 237
241#[test] 238#[test]
@@ -266,4 +263,4 @@ fn test_find_all_refs_for_param_inside() {
266 263
267 let refs = get_all_refs(code); 264 let refs = get_all_refs(code);
268 assert_eq!(refs.len(), 2); 265 assert_eq!(refs.len(), 2);
269} \ No newline at end of file 266}