aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/Cargo.toml4
-rw-r--r--crates/ra_analysis/src/db.rs40
-rw-r--r--crates/ra_analysis/src/descriptors.rs5
-rw-r--r--crates/ra_analysis/src/imp.rs108
-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.rs24
-rw-r--r--crates/ra_analysis/src/roots.rs36
-rw-r--r--crates/ra_analysis/src/symbol_index.rs14
-rw-r--r--crates/ra_analysis/tests/tests.rs65
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs1
-rw-r--r--crates/ra_lsp_server/src/caps.rs8
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs140
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs41
-rw-r--r--crates/ra_lsp_server/src/path_map.rs4
-rw-r--r--crates/ra_lsp_server/src/project_model.rs4
-rw-r--r--crates/ra_lsp_server/src/req.rs2
-rw-r--r--crates/ra_lsp_server/src/thread_watcher.rs5
18 files changed, 369 insertions, 261 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]
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"
14fst = "0.3.1" 13fst = "0.3.1"
15im = "12.0.0"
16ra_syntax = { path = "../ra_syntax" } 14ra_syntax = { path = "../ra_syntax" }
17ra_editor = { path = "../ra_editor" } 15ra_editor = { path = "../ra_editor" }
18salsa = "0.5.0" 16salsa = "0.6.0"
19rustc-hash = "1.0" 17rustc-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 @@
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)]
18pub(crate) struct RootDatabase { 21pub(crate) struct RootDatabase {
19 runtime: salsa::runtime::Runtime<RootDatabase>, 22 runtime: salsa::Runtime<RootDatabase>,
20} 23}
21 24
22impl fmt::Debug for RootDatabase { 25impl fmt::Debug for RootDatabase {
@@ -26,11 +29,19 @@ impl fmt::Debug for RootDatabase {
26} 29}
27 30
28impl salsa::Database for RootDatabase { 31impl 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
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 {
@@ -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}
121fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<SymbolIndex> { 132fn 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 @@
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 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;
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,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 @@
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 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;
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;
13extern crate rustc_hash; 10extern crate rustc_hash;
14extern crate salsa; 11extern crate salsa;
15 12
16mod db; 13mod db;
17mod descriptors; 14mod descriptors;
18mod imp; 15mod imp;
19mod job;
20mod module_map; 16mod module_map;
21mod roots; 17mod roots;
22mod symbol_index; 18mod symbol_index;
23 19
24use std::{fmt::Debug, sync::Arc}; 20use std::{fmt::Debug, sync::Arc};
25 21
26use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp};
27use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; 22use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
28use relative_path::{RelativePath, RelativePathBuf}; 23use relative_path::{RelativePath, RelativePathBuf};
29use rustc_hash::FxHashMap; 24use rustc_hash::FxHashMap;
30 25
26use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp};
27
31pub use crate::{ 28pub use crate::{
32 descriptors::FnDescriptor, 29 descriptors::FnDescriptor,
33 job::{JobHandle, JobToken},
34}; 30};
35pub use ra_editor::{ 31pub 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)]
37pub struct Canceled;
38
39pub type Cancelable<T> = Result<T, Canceled>;
40
41impl 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
47impl 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)]
41pub struct FileId(pub u32); 51pub 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 @@
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(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
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>> {
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};
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)]
@@ -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
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 {
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
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 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
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use ra_analysis::{ 10use ra_syntax::TextRange;
11 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle,
12};
13use relative_path::{RelativePath, RelativePathBuf}; 11use relative_path::{RelativePath, RelativePathBuf};
14use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
15use test_utils::{assert_eq_dbg, extract_offset}; 13use test_utils::{assert_eq_dbg, extract_offset};
16 14
15use ra_analysis::{
16 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor,
17};
18
17#[derive(Debug)] 19#[derive(Debug)]
18struct FileMap(Vec<(FileId, RelativePathBuf)>); 20struct 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]
72fn test_resolve_module() { 73fn 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]
90fn test_unresolved_module_diagnostic() { 90fn 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]
107fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 107fn 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]
114fn test_resolve_parent_module() { 114fn 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() {
124fn test_resolve_crate_root() { 124fn 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
229fn 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]
239fn 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]
258fn 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}
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
index 9088e5a60..f10bdf657 100644
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ b/crates/ra_editor/src/scope/fn_scope.rs
@@ -270,7 +270,6 @@ pub fn resolve_local_name<'a>(
270 .filter(|entry| shadowed.insert(entry.name())) 270 .filter(|entry| shadowed.insert(entry.name()))
271 .filter(|entry| entry.name() == name_ref.text()) 271 .filter(|entry| entry.name() == name_ref.text())
272 .nth(0); 272 .nth(0);
273 eprintln!("ret = {:?}", ret);
274 ret 273 ret
275} 274}
276 275
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 1dd495791..b6436b646 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions, 2 CodeActionProviderCapability, CompletionOptions, DocumentOnTypeFormattingOptions,
3 ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities, 3 ExecuteCommandOptions, FoldingRangeProviderCapability, ServerCapabilities,
4 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, 4 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
5 TextDocumentSyncOptions, 5 TextDocumentSyncOptions, RenameProviderCapability, RenameOptions
6}; 6};
7 7
8pub fn server_capabilities() -> ServerCapabilities { 8pub fn server_capabilities() -> ServerCapabilities {
@@ -27,7 +27,7 @@ pub fn server_capabilities() -> ServerCapabilities {
27 definition_provider: Some(true), 27 definition_provider: Some(true),
28 type_definition_provider: None, 28 type_definition_provider: None,
29 implementation_provider: None, 29 implementation_provider: None,
30 references_provider: None, 30 references_provider: Some(true),
31 document_highlight_provider: None, 31 document_highlight_provider: None,
32 document_symbol_provider: Some(true), 32 document_symbol_provider: Some(true),
33 workspace_symbol_provider: Some(true), 33 workspace_symbol_provider: Some(true),
@@ -40,7 +40,9 @@ pub fn server_capabilities() -> ServerCapabilities {
40 more_trigger_character: None, 40 more_trigger_character: None,
41 }), 41 }),
42 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 42 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
43 rename_provider: None, 43 rename_provider: Some(RenameProviderCapability::Options(RenameOptions{
44 prepare_provider: Some(true)
45 })),
44 color_provider: None, 46 color_provider: None,
45 execute_command_provider: Some(ExecuteCommandOptions { 47 execute_command_provider: Some(ExecuteCommandOptions {
46 commands: vec!["apply_code_action".to_string()], 48 commands: vec!["apply_code_action".to_string()],
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 3e58e6f54..11f34eb93 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,11 +1,13 @@
1use rustc_hash::FxHashMap; 1use std::collections::HashMap;
2 2
3use rustc_hash::FxHashMap;
3use languageserver_types::{ 4use languageserver_types::{
4 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, 5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
5 DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, 6 DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams,
6 InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit, 7 InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit,
8 RenameParams, WorkspaceEdit, PrepareRenameResponse
7}; 9};
8use ra_analysis::{FileId, FoldKind, JobToken, Query, RunnableKind}; 10use ra_analysis::{FileId, FoldKind, Query, RunnableKind};
9use ra_syntax::text_utils::contains_offset_nonstrict; 11use ra_syntax::text_utils::contains_offset_nonstrict;
10use serde_json::to_value; 12use serde_json::to_value;
11 13
@@ -20,7 +22,6 @@ use crate::{
20pub fn handle_syntax_tree( 22pub fn handle_syntax_tree(
21 world: ServerWorld, 23 world: ServerWorld,
22 params: req::SyntaxTreeParams, 24 params: req::SyntaxTreeParams,
23 _token: JobToken,
24) -> Result<String> { 25) -> Result<String> {
25 let id = params.text_document.try_conv_with(&world)?; 26 let id = params.text_document.try_conv_with(&world)?;
26 let res = world.analysis().syntax_tree(id); 27 let res = world.analysis().syntax_tree(id);
@@ -30,7 +31,6 @@ pub fn handle_syntax_tree(
30pub fn handle_extend_selection( 31pub fn handle_extend_selection(
31 world: ServerWorld, 32 world: ServerWorld,
32 params: req::ExtendSelectionParams, 33 params: req::ExtendSelectionParams,
33 _token: JobToken,
34) -> Result<req::ExtendSelectionResult> { 34) -> Result<req::ExtendSelectionResult> {
35 let file_id = params.text_document.try_conv_with(&world)?; 35 let file_id = params.text_document.try_conv_with(&world)?;
36 let file = world.analysis().file_syntax(file_id); 36 let file = world.analysis().file_syntax(file_id);
@@ -48,7 +48,6 @@ pub fn handle_extend_selection(
48pub fn handle_find_matching_brace( 48pub fn handle_find_matching_brace(
49 world: ServerWorld, 49 world: ServerWorld,
50 params: req::FindMatchingBraceParams, 50 params: req::FindMatchingBraceParams,
51 _token: JobToken,
52) -> Result<Vec<Position>> { 51) -> Result<Vec<Position>> {
53 let file_id = params.text_document.try_conv_with(&world)?; 52 let file_id = params.text_document.try_conv_with(&world)?;
54 let file = world.analysis().file_syntax(file_id); 53 let file = world.analysis().file_syntax(file_id);
@@ -71,7 +70,6 @@ pub fn handle_find_matching_brace(
71pub fn handle_join_lines( 70pub fn handle_join_lines(
72 world: ServerWorld, 71 world: ServerWorld,
73 params: req::JoinLinesParams, 72 params: req::JoinLinesParams,
74 _token: JobToken,
75) -> Result<req::SourceChange> { 73) -> Result<req::SourceChange> {
76 let file_id = params.text_document.try_conv_with(&world)?; 74 let file_id = params.text_document.try_conv_with(&world)?;
77 let line_index = world.analysis().file_line_index(file_id); 75 let line_index = world.analysis().file_line_index(file_id);
@@ -85,7 +83,6 @@ pub fn handle_join_lines(
85pub fn handle_on_enter( 83pub fn handle_on_enter(
86 world: ServerWorld, 84 world: ServerWorld,
87 params: req::TextDocumentPositionParams, 85 params: req::TextDocumentPositionParams,
88 _token: JobToken,
89) -> Result<Option<req::SourceChange>> { 86) -> Result<Option<req::SourceChange>> {
90 let file_id = params.text_document.try_conv_with(&world)?; 87 let file_id = params.text_document.try_conv_with(&world)?;
91 let line_index = world.analysis().file_line_index(file_id); 88 let line_index = world.analysis().file_line_index(file_id);
@@ -99,7 +96,6 @@ pub fn handle_on_enter(
99pub fn handle_on_type_formatting( 96pub fn handle_on_type_formatting(
100 world: ServerWorld, 97 world: ServerWorld,
101 params: req::DocumentOnTypeFormattingParams, 98 params: req::DocumentOnTypeFormattingParams,
102 _token: JobToken,
103) -> Result<Option<Vec<TextEdit>>> { 99) -> Result<Option<Vec<TextEdit>>> {
104 if params.ch != "=" { 100 if params.ch != "=" {
105 return Ok(None); 101 return Ok(None);
@@ -119,7 +115,6 @@ pub fn handle_on_type_formatting(
119pub fn handle_document_symbol( 115pub fn handle_document_symbol(
120 world: ServerWorld, 116 world: ServerWorld,
121 params: req::DocumentSymbolParams, 117 params: req::DocumentSymbolParams,
122 _token: JobToken,
123) -> Result<Option<req::DocumentSymbolResponse>> { 118) -> Result<Option<req::DocumentSymbolResponse>> {
124 let file_id = params.text_document.try_conv_with(&world)?; 119 let file_id = params.text_document.try_conv_with(&world)?;
125 let line_index = world.analysis().file_line_index(file_id); 120 let line_index = world.analysis().file_line_index(file_id);
@@ -158,7 +153,6 @@ pub fn handle_document_symbol(
158pub fn handle_workspace_symbol( 153pub fn handle_workspace_symbol(
159 world: ServerWorld, 154 world: ServerWorld,
160 params: req::WorkspaceSymbolParams, 155 params: req::WorkspaceSymbolParams,
161 token: JobToken,
162) -> Result<Option<Vec<SymbolInformation>>> { 156) -> Result<Option<Vec<SymbolInformation>>> {
163 let all_symbols = params.query.contains('#'); 157 let all_symbols = params.query.contains('#');
164 let libs = params.query.contains('*'); 158 let libs = params.query.contains('*');
@@ -178,11 +172,11 @@ pub fn handle_workspace_symbol(
178 q.limit(128); 172 q.limit(128);
179 q 173 q
180 }; 174 };
181 let mut res = exec_query(&world, query, &token)?; 175 let mut res = exec_query(&world, query)?;
182 if res.is_empty() && !all_symbols { 176 if res.is_empty() && !all_symbols {
183 let mut query = Query::new(params.query); 177 let mut query = Query::new(params.query);
184 query.limit(128); 178 query.limit(128);
185 res = exec_query(&world, query, &token)?; 179 res = exec_query(&world, query)?;
186 } 180 }
187 181
188 return Ok(Some(res)); 182 return Ok(Some(res));
@@ -190,10 +184,9 @@ pub fn handle_workspace_symbol(
190 fn exec_query( 184 fn exec_query(
191 world: &ServerWorld, 185 world: &ServerWorld,
192 query: Query, 186 query: Query,
193 token: &JobToken,
194 ) -> Result<Vec<SymbolInformation>> { 187 ) -> Result<Vec<SymbolInformation>> {
195 let mut res = Vec::new(); 188 let mut res = Vec::new();
196 for (file_id, symbol) in world.analysis().symbol_search(query, token) { 189 for (file_id, symbol) in world.analysis().symbol_search(query)? {
197 let line_index = world.analysis().file_line_index(file_id); 190 let line_index = world.analysis().file_line_index(file_id);
198 let info = SymbolInformation { 191 let info = SymbolInformation {
199 name: symbol.name.to_string(), 192 name: symbol.name.to_string(),
@@ -211,7 +204,6 @@ pub fn handle_workspace_symbol(
211pub fn handle_goto_definition( 204pub fn handle_goto_definition(
212 world: ServerWorld, 205 world: ServerWorld,
213 params: req::TextDocumentPositionParams, 206 params: req::TextDocumentPositionParams,
214 token: JobToken,
215) -> Result<Option<req::GotoDefinitionResponse>> { 207) -> Result<Option<req::GotoDefinitionResponse>> {
216 let file_id = params.text_document.try_conv_with(&world)?; 208 let file_id = params.text_document.try_conv_with(&world)?;
217 let line_index = world.analysis().file_line_index(file_id); 209 let line_index = world.analysis().file_line_index(file_id);
@@ -219,7 +211,7 @@ pub fn handle_goto_definition(
219 let mut res = Vec::new(); 211 let mut res = Vec::new();
220 for (file_id, symbol) in world 212 for (file_id, symbol) in world
221 .analysis() 213 .analysis()
222 .approximately_resolve_symbol(file_id, offset, &token) 214 .approximately_resolve_symbol(file_id, offset)?
223 { 215 {
224 let line_index = world.analysis().file_line_index(file_id); 216 let line_index = world.analysis().file_line_index(file_id);
225 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 217 let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
@@ -231,11 +223,10 @@ pub fn handle_goto_definition(
231pub fn handle_parent_module( 223pub fn handle_parent_module(
232 world: ServerWorld, 224 world: ServerWorld,
233 params: TextDocumentIdentifier, 225 params: TextDocumentIdentifier,
234 _token: JobToken,
235) -> Result<Vec<Location>> { 226) -> Result<Vec<Location>> {
236 let file_id = params.try_conv_with(&world)?; 227 let file_id = params.try_conv_with(&world)?;
237 let mut res = Vec::new(); 228 let mut res = Vec::new();
238 for (file_id, symbol) in world.analysis().parent_module(file_id) { 229 for (file_id, symbol) in world.analysis().parent_module(file_id)? {
239 let line_index = world.analysis().file_line_index(file_id); 230 let line_index = world.analysis().file_line_index(file_id);
240 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 231 let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
241 res.push(location); 232 res.push(location);
@@ -246,20 +237,19 @@ pub fn handle_parent_module(
246pub fn handle_runnables( 237pub fn handle_runnables(
247 world: ServerWorld, 238 world: ServerWorld,
248 params: req::RunnablesParams, 239 params: req::RunnablesParams,
249 _token: JobToken,
250) -> Result<Vec<req::Runnable>> { 240) -> Result<Vec<req::Runnable>> {
251 let file_id = params.text_document.try_conv_with(&world)?; 241 let file_id = params.text_document.try_conv_with(&world)?;
252 let line_index = world.analysis().file_line_index(file_id); 242 let line_index = world.analysis().file_line_index(file_id);
253 let offset = params.position.map(|it| it.conv_with(&line_index)); 243 let offset = params.position.map(|it| it.conv_with(&line_index));
254 let mut res = Vec::new(); 244 let mut res = Vec::new();
255 for runnable in world.analysis().runnables(file_id) { 245 for runnable in world.analysis().runnables(file_id)? {
256 if let Some(offset) = offset { 246 if let Some(offset) = offset {
257 if !contains_offset_nonstrict(runnable.range, offset) { 247 if !contains_offset_nonstrict(runnable.range, offset) {
258 continue; 248 continue;
259 } 249 }
260 } 250 }
261 251
262 let args = runnable_args(&world, file_id, &runnable.kind); 252 let args = runnable_args(&world, file_id, &runnable.kind)?;
263 253
264 let r = req::Runnable { 254 let r = req::Runnable {
265 range: runnable.range.conv_with(&line_index), 255 range: runnable.range.conv_with(&line_index),
@@ -279,9 +269,9 @@ pub fn handle_runnables(
279 } 269 }
280 return Ok(res); 270 return Ok(res);
281 271
282 fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Vec<String> { 272 fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result<Vec<String>> {
283 let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id).first() { 273 let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id)?.first() {
284 let file_id = world.analysis().crate_root(crate_id); 274 let file_id = world.analysis().crate_root(crate_id)?;
285 let path = world.path_map.get_path(file_id); 275 let path = world.path_map.get_path(file_id);
286 world 276 world
287 .workspaces 277 .workspaces
@@ -316,7 +306,7 @@ pub fn handle_runnables(
316 } 306 }
317 } 307 }
318 } 308 }
319 res 309 Ok(res)
320 } 310 }
321 311
322 fn spec_args(pkg_name: &str, tgt_name: &str, tgt_kind: TargetKind, buf: &mut Vec<String>) { 312 fn spec_args(pkg_name: &str, tgt_name: &str, tgt_kind: TargetKind, buf: &mut Vec<String>) {
@@ -350,21 +340,19 @@ pub fn handle_runnables(
350pub fn handle_decorations( 340pub fn handle_decorations(
351 world: ServerWorld, 341 world: ServerWorld,
352 params: TextDocumentIdentifier, 342 params: TextDocumentIdentifier,
353 _token: JobToken,
354) -> Result<Vec<Decoration>> { 343) -> Result<Vec<Decoration>> {
355 let file_id = params.try_conv_with(&world)?; 344 let file_id = params.try_conv_with(&world)?;
356 Ok(highlight(&world, file_id)) 345 highlight(&world, file_id)
357} 346}
358 347
359pub fn handle_completion( 348pub fn handle_completion(
360 world: ServerWorld, 349 world: ServerWorld,
361 params: req::CompletionParams, 350 params: req::CompletionParams,
362 _token: JobToken,
363) -> Result<Option<req::CompletionResponse>> { 351) -> Result<Option<req::CompletionResponse>> {
364 let file_id = params.text_document.try_conv_with(&world)?; 352 let file_id = params.text_document.try_conv_with(&world)?;
365 let line_index = world.analysis().file_line_index(file_id); 353 let line_index = world.analysis().file_line_index(file_id);
366 let offset = params.position.conv_with(&line_index); 354 let offset = params.position.conv_with(&line_index);
367 let items = match world.analysis().completions(file_id, offset) { 355 let items = match world.analysis().completions(file_id, offset)? {
368 None => return Ok(None), 356 None => return Ok(None),
369 Some(items) => items, 357 Some(items) => items,
370 }; 358 };
@@ -391,7 +379,6 @@ pub fn handle_completion(
391pub fn handle_folding_range( 379pub fn handle_folding_range(
392 world: ServerWorld, 380 world: ServerWorld,
393 params: FoldingRangeParams, 381 params: FoldingRangeParams,
394 _token: JobToken,
395) -> Result<Option<Vec<FoldingRange>>> { 382) -> Result<Option<Vec<FoldingRange>>> {
396 let file_id = params.text_document.try_conv_with(&world)?; 383 let file_id = params.text_document.try_conv_with(&world)?;
397 let line_index = world.analysis().file_line_index(file_id); 384 let line_index = world.analysis().file_line_index(file_id);
@@ -424,7 +411,6 @@ pub fn handle_folding_range(
424pub fn handle_signature_help( 411pub fn handle_signature_help(
425 world: ServerWorld, 412 world: ServerWorld,
426 params: req::TextDocumentPositionParams, 413 params: req::TextDocumentPositionParams,
427 token: JobToken,
428) -> Result<Option<req::SignatureHelp>> { 414) -> Result<Option<req::SignatureHelp>> {
429 use languageserver_types::{ParameterInformation, SignatureInformation}; 415 use languageserver_types::{ParameterInformation, SignatureInformation};
430 416
@@ -433,7 +419,7 @@ pub fn handle_signature_help(
433 let offset = params.position.conv_with(&line_index); 419 let offset = params.position.conv_with(&line_index);
434 420
435 if let Some((descriptor, active_param)) = 421 if let Some((descriptor, active_param)) =
436 world.analysis().resolve_callable(file_id, offset, &token) 422 world.analysis().resolve_callable(file_id, offset)?
437 { 423 {
438 let parameters: Vec<ParameterInformation> = descriptor 424 let parameters: Vec<ParameterInformation> = descriptor
439 .params 425 .params
@@ -460,19 +446,90 @@ pub fn handle_signature_help(
460 } 446 }
461} 447}
462 448
449pub fn handle_prepare_rename(
450 world: ServerWorld,
451 params: req::TextDocumentPositionParams,
452) -> Result<Option<PrepareRenameResponse>> {
453 let file_id = params.text_document.try_conv_with(&world)?;
454 let line_index = world.analysis().file_line_index(file_id);
455 let offset = params.position.conv_with(&line_index);
456
457 // We support renaming references like handle_rename does.
458 // In the future we may want to reject the renaming of things like keywords here too.
459 let refs = world.analysis().find_all_refs(file_id, offset)?;
460 if refs.is_empty() {
461 return Ok(None);
462 }
463
464 let r = refs.first().unwrap();
465 let loc = to_location(r.0, r.1, &world, &line_index)?;
466
467 Ok(Some(PrepareRenameResponse::Range(loc.range)))
468}
469
470pub fn handle_rename(
471 world: ServerWorld,
472 params: RenameParams,
473) -> Result<Option<WorkspaceEdit>> {
474 let file_id = params.text_document.try_conv_with(&world)?;
475 let line_index = world.analysis().file_line_index(file_id);
476 let offset = params.position.conv_with(&line_index);
477
478 if params.new_name.is_empty() {
479 return Ok(None);
480 }
481
482 let refs = world.analysis().find_all_refs(file_id, offset)?;
483 if refs.is_empty() {
484 return Ok(None);
485 }
486
487 let mut changes = HashMap::new();
488 for r in refs {
489 if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) {
490 changes.entry(loc.uri).or_insert(Vec::new()).push(
491 TextEdit {
492 range: loc.range,
493 new_text: params.new_name.clone()
494 });
495 }
496 }
497
498 Ok(Some(WorkspaceEdit {
499 changes: Some(changes),
500
501 // TODO: return this instead if client/server support it. See #144
502 document_changes : None,
503 }))
504}
505
506pub fn handle_references(
507 world: ServerWorld,
508 params: req::ReferenceParams,
509) -> Result<Option<Vec<Location>>> {
510 let file_id = params.text_document.try_conv_with(&world)?;
511 let line_index = world.analysis().file_line_index(file_id);
512 let offset = params.position.conv_with(&line_index);
513
514 let refs = world.analysis().find_all_refs(file_id, offset)?;
515
516 Ok(Some(refs.into_iter()
517 .filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
518 .collect()))
519}
520
463pub fn handle_code_action( 521pub fn handle_code_action(
464 world: ServerWorld, 522 world: ServerWorld,
465 params: req::CodeActionParams, 523 params: req::CodeActionParams,
466 _token: JobToken,
467) -> Result<Option<CodeActionResponse>> { 524) -> Result<Option<CodeActionResponse>> {
468 let file_id = params.text_document.try_conv_with(&world)?; 525 let file_id = params.text_document.try_conv_with(&world)?;
469 let line_index = world.analysis().file_line_index(file_id); 526 let line_index = world.analysis().file_line_index(file_id);
470 let range = params.range.conv_with(&line_index); 527 let range = params.range.conv_with(&line_index);
471 528
472 let assists = world.analysis().assists(file_id, range).into_iter(); 529 let assists = world.analysis().assists(file_id, range)?.into_iter();
473 let fixes = world 530 let fixes = world
474 .analysis() 531 .analysis()
475 .diagnostics(file_id) 532 .diagnostics(file_id)?
476 .into_iter() 533 .into_iter()
477 .filter_map(|d| Some((d.range, d.fix?))) 534 .filter_map(|d| Some((d.range, d.fix?)))
478 .filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start())) 535 .filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start()))
@@ -501,7 +558,7 @@ pub fn publish_diagnostics(
501 let line_index = world.analysis().file_line_index(file_id); 558 let line_index = world.analysis().file_line_index(file_id);
502 let diagnostics = world 559 let diagnostics = world
503 .analysis() 560 .analysis()
504 .diagnostics(file_id) 561 .diagnostics(file_id)?
505 .into_iter() 562 .into_iter()
506 .map(|d| Diagnostic { 563 .map(|d| Diagnostic {
507 range: d.range.conv_with(&line_index), 564 range: d.range.conv_with(&line_index),
@@ -522,19 +579,20 @@ pub fn publish_decorations(
522 let uri = world.file_id_to_uri(file_id)?; 579 let uri = world.file_id_to_uri(file_id)?;
523 Ok(req::PublishDecorationsParams { 580 Ok(req::PublishDecorationsParams {
524 uri, 581 uri,
525 decorations: highlight(&world, file_id), 582 decorations: highlight(&world, file_id)?,
526 }) 583 })
527} 584}
528 585
529fn highlight(world: &ServerWorld, file_id: FileId) -> Vec<Decoration> { 586fn highlight(world: &ServerWorld, file_id: FileId) -> Result<Vec<Decoration>> {
530 let line_index = world.analysis().file_line_index(file_id); 587 let line_index = world.analysis().file_line_index(file_id);
531 world 588 let res = world
532 .analysis() 589 .analysis()
533 .highlight(file_id) 590 .highlight(file_id)?
534 .into_iter() 591 .into_iter()
535 .map(|h| Decoration { 592 .map(|h| Decoration {
536 range: h.range.conv_with(&line_index), 593 range: h.range.conv_with(&line_index),
537 tag: h.tag, 594 tag: h.tag,
538 }) 595 })
539 .collect() 596 .collect();
597 Ok(res)
540} 598}
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index a11baf4aa..b35ebd38b 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -8,9 +8,9 @@ use gen_lsp_server::{
8 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, 8 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
9}; 9};
10use languageserver_types::NumberOrString; 10use languageserver_types::NumberOrString;
11use ra_analysis::{FileId, JobHandle, JobToken, LibraryData}; 11use ra_analysis::{FileId, LibraryData};
12use rayon::{self, ThreadPool}; 12use rayon::{self, ThreadPool};
13use rustc_hash::FxHashMap; 13use rustc_hash::FxHashSet;
14use serde::{de::DeserializeOwned, Serialize}; 14use serde::{de::DeserializeOwned, Serialize};
15 15
16use crate::{ 16use crate::{
@@ -47,7 +47,7 @@ pub fn main_loop(
47 info!("server initialized, serving requests"); 47 info!("server initialized, serving requests");
48 let mut state = ServerWorldState::new(); 48 let mut state = ServerWorldState::new();
49 49
50 let mut pending_requests = FxHashMap::default(); 50 let mut pending_requests = FxHashSet::default();
51 let mut subs = Subscriptions::new(); 51 let mut subs = Subscriptions::new();
52 let main_res = main_loop_inner( 52 let main_res = main_loop_inner(
53 internal_mode, 53 internal_mode,
@@ -92,7 +92,7 @@ fn main_loop_inner(
92 fs_worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>, 92 fs_worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>,
93 ws_worker: Worker<PathBuf, Result<CargoWorkspace>>, 93 ws_worker: Worker<PathBuf, Result<CargoWorkspace>>,
94 state: &mut ServerWorldState, 94 state: &mut ServerWorldState,
95 pending_requests: &mut FxHashMap<u64, JobHandle>, 95 pending_requests: &mut FxHashSet<u64>,
96 subs: &mut Subscriptions, 96 subs: &mut Subscriptions,
97) -> Result<()> { 97) -> Result<()> {
98 let (libdata_sender, libdata_receiver) = unbounded(); 98 let (libdata_sender, libdata_receiver) = unbounded();
@@ -204,14 +204,13 @@ fn main_loop_inner(
204fn on_task( 204fn on_task(
205 task: Task, 205 task: Task,
206 msg_sender: &Sender<RawMessage>, 206 msg_sender: &Sender<RawMessage>,
207 pending_requests: &mut FxHashMap<u64, JobHandle>, 207 pending_requests: &mut FxHashSet<u64>,
208) { 208) {
209 match task { 209 match task {
210 Task::Respond(response) => { 210 Task::Respond(response) => {
211 if let Some(handle) = pending_requests.remove(&response.id) { 211 if pending_requests.remove(&response.id) {
212 assert!(handle.has_completed()); 212 msg_sender.send(RawMessage::Response(response))
213 } 213 }
214 msg_sender.send(RawMessage::Response(response))
215 } 214 }
216 Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)), 215 Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)),
217 } 216 }
@@ -219,7 +218,7 @@ fn on_task(
219 218
220fn on_request( 219fn on_request(
221 world: &mut ServerWorldState, 220 world: &mut ServerWorldState,
222 pending_requests: &mut FxHashMap<u64, JobHandle>, 221 pending_requests: &mut FxHashSet<u64>,
223 pool: &ThreadPool, 222 pool: &ThreadPool,
224 sender: &Sender<Task>, 223 sender: &Sender<Task>,
225 req: RawRequest, 224 req: RawRequest,
@@ -248,10 +247,13 @@ fn on_request(
248 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 247 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
249 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? 248 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
250 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? 249 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
250 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
251 .on::<req::Rename>(handlers::handle_rename)?
252 .on::<req::References>(handlers::handle_references)?
251 .finish(); 253 .finish();
252 match req { 254 match req {
253 Ok((id, handle)) => { 255 Ok(id) => {
254 let inserted = pending_requests.insert(id, handle).is_none(); 256 let inserted = pending_requests.insert(id);
255 assert!(inserted, "duplicate request: {}", id); 257 assert!(inserted, "duplicate request: {}", id);
256 Ok(None) 258 Ok(None)
257 } 259 }
@@ -262,7 +264,7 @@ fn on_request(
262fn on_notification( 264fn on_notification(
263 msg_sender: &Sender<RawMessage>, 265 msg_sender: &Sender<RawMessage>,
264 state: &mut ServerWorldState, 266 state: &mut ServerWorldState,
265 pending_requests: &mut FxHashMap<u64, JobHandle>, 267 pending_requests: &mut FxHashSet<u64>,
266 subs: &mut Subscriptions, 268 subs: &mut Subscriptions,
267 not: RawNotification, 269 not: RawNotification,
268) -> Result<()> { 270) -> Result<()> {
@@ -274,9 +276,7 @@ fn on_notification(
274 panic!("string id's not supported: {:?}", id); 276 panic!("string id's not supported: {:?}", id);
275 } 277 }
276 }; 278 };
277 if let Some(handle) = pending_requests.remove(&id) { 279 pending_requests.remove(&id);
278 handle.cancel();
279 }
280 return Ok(()); 280 return Ok(());
281 } 281 }
282 Err(not) => not, 282 Err(not) => not,
@@ -333,7 +333,7 @@ fn on_notification(
333 333
334struct PoolDispatcher<'a> { 334struct PoolDispatcher<'a> {
335 req: Option<RawRequest>, 335 req: Option<RawRequest>,
336 res: Option<(u64, JobHandle)>, 336 res: Option<u64>,
337 pool: &'a ThreadPool, 337 pool: &'a ThreadPool,
338 world: &'a ServerWorldState, 338 world: &'a ServerWorldState,
339 sender: &'a Sender<Task>, 339 sender: &'a Sender<Task>,
@@ -342,7 +342,7 @@ struct PoolDispatcher<'a> {
342impl<'a> PoolDispatcher<'a> { 342impl<'a> PoolDispatcher<'a> {
343 fn on<'b, R>( 343 fn on<'b, R>(
344 &'b mut self, 344 &'b mut self,
345 f: fn(ServerWorld, R::Params, JobToken) -> Result<R::Result>, 345 f: fn(ServerWorld, R::Params) -> Result<R::Result>,
346 ) -> Result<&'b mut Self> 346 ) -> Result<&'b mut Self>
347 where 347 where
348 R: req::Request, 348 R: req::Request,
@@ -355,11 +355,10 @@ impl<'a> PoolDispatcher<'a> {
355 }; 355 };
356 match req.cast::<R>() { 356 match req.cast::<R>() {
357 Ok((id, params)) => { 357 Ok((id, params)) => {
358 let (handle, token) = JobHandle::new();
359 let world = self.world.snapshot(); 358 let world = self.world.snapshot();
360 let sender = self.sender.clone(); 359 let sender = self.sender.clone();
361 self.pool.spawn(move || { 360 self.pool.spawn(move || {
362 let resp = match f(world, params, token) { 361 let resp = match f(world, params) {
363 Ok(resp) => RawResponse::ok::<R>(id, &resp), 362 Ok(resp) => RawResponse::ok::<R>(id, &resp),
364 Err(e) => { 363 Err(e) => {
365 RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string()) 364 RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string())
@@ -368,14 +367,14 @@ impl<'a> PoolDispatcher<'a> {
368 let task = Task::Respond(resp); 367 let task = Task::Respond(resp);
369 sender.send(task); 368 sender.send(task);
370 }); 369 });
371 self.res = Some((id, handle)); 370 self.res = Some(id);
372 } 371 }
373 Err(req) => self.req = Some(req), 372 Err(req) => self.req = Some(req),
374 } 373 }
375 Ok(self) 374 Ok(self)
376 } 375 }
377 376
378 fn finish(&mut self) -> ::std::result::Result<(u64, JobHandle), RawRequest> { 377 fn finish(&mut self) -> ::std::result::Result<u64, RawRequest> {
379 match (self.res.take(), self.req.take()) { 378 match (self.res.take(), self.req.take()) {
380 (Some(res), None) => Ok(res), 379 (Some(res), None) => Ok(res),
381 (None, Some(req)) => Err(req), 380 (None, Some(req)) => Err(req),
diff --git a/crates/ra_lsp_server/src/path_map.rs b/crates/ra_lsp_server/src/path_map.rs
index 585013acd..d32829382 100644
--- a/crates/ra_lsp_server/src/path_map.rs
+++ b/crates/ra_lsp_server/src/path_map.rs
@@ -1,9 +1,9 @@
1use std::path::{Component, Path, PathBuf};
2
1use im; 3use im;
2use ra_analysis::{FileId, FileResolver}; 4use ra_analysis::{FileId, FileResolver};
3use relative_path::RelativePath; 5use relative_path::RelativePath;
4 6
5use std::path::{Component, Path, PathBuf};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)] 7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum Root { 8pub enum Root {
9 Workspace, 9 Workspace,
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs
index cedb67bae..cabb336a3 100644
--- a/crates/ra_lsp_server/src/project_model.rs
+++ b/crates/ra_lsp_server/src/project_model.rs
@@ -1,9 +1,9 @@
1use std::path::{Path, PathBuf};
2
1use cargo_metadata::{metadata_run, CargoOpt}; 3use cargo_metadata::{metadata_run, CargoOpt};
2use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
3use rustc_hash::{FxHashMap, FxHashSet}; 5use rustc_hash::{FxHashMap, FxHashSet};
4 6
5use std::path::{Path, PathBuf};
6
7use crate::{ 7use crate::{
8 thread_watcher::{ThreadWatcher, Worker}, 8 thread_watcher::{ThreadWatcher, Worker},
9 Result, 9 Result,
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index b76bfbcbc..6cd04d84c 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -7,7 +7,7 @@ pub use languageserver_types::{
7 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams, 7 CompletionResponse, DocumentOnTypeFormattingParams, DocumentSymbolParams,
8 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult, 8 DocumentSymbolResponse, ExecuteCommandParams, Hover, InitializeResult,
9 PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, 9 PublishDiagnosticsParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams,
10 TextEdit, WorkspaceSymbolParams, 10 TextEdit, WorkspaceSymbolParams, ReferenceParams,
11}; 11};
12 12
13pub enum SyntaxTree {} 13pub enum SyntaxTree {}
diff --git a/crates/ra_lsp_server/src/thread_watcher.rs b/crates/ra_lsp_server/src/thread_watcher.rs
index 6cc586456..5143c77ae 100644
--- a/crates/ra_lsp_server/src/thread_watcher.rs
+++ b/crates/ra_lsp_server/src/thread_watcher.rs
@@ -1,8 +1,9 @@
1use crate::Result; 1use std::thread;
2
2use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; 3use crossbeam_channel::{bounded, unbounded, Receiver, Sender};
3use drop_bomb::DropBomb; 4use drop_bomb::DropBomb;
4 5
5use std::thread; 6use crate::Result;
6 7
7pub struct Worker<I, O> { 8pub struct Worker<I, O> {
8 pub inp: Sender<I>, 9 pub inp: Sender<I>,