diff --git a/Cargo.lock b/Cargo.lock index bb0feec2ed..f519148834 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -609,7 +609,6 @@ dependencies = [ name = "ra_analysis" version = "0.1.0" dependencies = [ - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "fst 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "im 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/crates/ra_analysis/Cargo.toml b/crates/ra_analysis/Cargo.toml index dd4ec83752..d7ac69fe8d 100644 --- a/crates/ra_analysis/Cargo.toml +++ b/crates/ra_analysis/Cargo.toml @@ -7,7 +7,6 @@ authors = ["Aleksey Kladov "] [dependencies] relative-path = "0.3.7" log = "0.4.2" -crossbeam-channel = "0.2.4" parking_lot = "0.6.3" once_cell = "0.1.5" rayon = "1.0.2" diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index cce9596696..09d74b9e74 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs @@ -1,17 +1,20 @@ -use crate::{ - module_map::{ModuleDescriptorQuery, ModuleTreeQuery, ModulesDatabase}, - symbol_index::SymbolIndex, - FileId, FileResolverImp, +use std::{ + fmt, + hash::{Hash, Hasher}, + sync::Arc, }; + use ra_editor::LineIndex; use ra_syntax::File; use rustc_hash::FxHashSet; use salsa; -use std::{ - fmt, - hash::{Hash, Hasher}, - sync::Arc, +use crate::{ + db, + Cancelable, Canceled, + module_map::{ModuleDescriptorQuery, ModuleTreeQuery, ModulesDatabase}, + symbol_index::SymbolIndex, + FileId, FileResolverImp, }; #[derive(Default)] @@ -31,6 +34,14 @@ impl salsa::Database for RootDatabase { } } +pub(crate) fn check_canceled(db: &impl salsa::Database) -> Cancelable<()> { + if db.salsa_runtime().is_current_revision_canceled() { + Err(Canceled) + } else { + Ok(()) + } +} + impl salsa::ParallelDatabase for RootDatabase { fn fork(&self) -> Self { RootDatabase { @@ -98,7 +109,7 @@ salsa::query_group! { fn file_lines(file_id: FileId) -> Arc { type FileLinesQuery; } - fn file_symbols(file_id: FileId) -> Arc { + fn file_symbols(file_id: FileId) -> Cancelable> { type FileSymbolsQuery; } } @@ -112,7 +123,8 @@ fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc { let text = db.file_text(file_id); Arc::new(LineIndex::new(&*text)) } -fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Arc { +fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable> { + db::check_canceled(db)?; let syntax = db.file_syntax(file_id); - Arc::new(SymbolIndex::for_file(file_id, syntax)) + Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) } diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs index 6f26f9935d..310bf15857 100644 --- a/crates/ra_analysis/src/descriptors.rs +++ b/crates/ra_analysis/src/descriptors.rs @@ -1,4 +1,5 @@ -use crate::{imp::FileResolverImp, FileId}; +use std::collections::BTreeMap; + use ra_syntax::{ ast::{self, AstNode, NameOwner}, text_utils::is_subrange, @@ -6,7 +7,7 @@ use ra_syntax::{ }; use relative_path::RelativePathBuf; -use std::collections::BTreeMap; +use crate::{imp::FileResolverImp, FileId}; #[derive(Debug, PartialEq, Eq, Hash)] pub struct ModuleDescriptor { diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index a67b1717a7..32e9bb6d7f 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs @@ -19,8 +19,8 @@ use rustc_hash::FxHashSet; use crate::{ descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem}, roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot}, - CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, JobToken, Position, - Query, SourceChange, SourceFileEdit, + CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, Position, + Query, SourceChange, SourceFileEdit, Cancelable, }; #[derive(Clone, Debug)] @@ -148,19 +148,21 @@ impl AnalysisImpl { pub fn file_line_index(&self, file_id: FileId) -> Arc { self.root(file_id).lines(file_id) } - pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { + pub fn world_symbols(&self, query: Query) -> Cancelable> { let mut buf = Vec::new(); if query.libs { - self.data.libs.iter().for_each(|it| it.symbols(&mut buf)); + for lib in self.data.libs.iter() { + lib.symbols(&mut buf)?; + } } else { - self.data.root.symbols(&mut buf); + self.data.root.symbols(&mut buf)?; } - query.search(&buf, token) + Ok(query.search(&buf)) } - pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { + pub fn parent_module(&self, file_id: FileId) -> Cancelable> { let root = self.root(file_id); - let module_tree = root.module_tree(); - module_tree + let module_tree = root.module_tree()?; + let res = module_tree .parent_modules(file_id) .iter() .map(|link| { @@ -174,10 +176,11 @@ impl AnalysisImpl { }; (file_id, sym) }) - .collect() + .collect(); + Ok(res) } - pub fn crate_for(&self, file_id: FileId) -> Vec { - let module_tree = self.root(file_id).module_tree(); + pub fn crate_for(&self, file_id: FileId) -> Cancelable> { + let module_tree = self.root(file_id).module_tree()?; let crate_graph = &self.data.crate_graph; let mut res = Vec::new(); let mut work = VecDeque::new(); @@ -195,7 +198,7 @@ impl AnalysisImpl { .filter(|&id| visited.insert(id)); work.extend(parents); } - res + Ok(res) } pub fn crate_root(&self, crate_id: CrateId) -> FileId { self.data.crate_graph.crate_roots[&crate_id] @@ -204,15 +207,14 @@ impl AnalysisImpl { &self, file_id: FileId, offset: TextUnit, - token: &JobToken, - ) -> Vec<(FileId, FileSymbol)> { + ) -> Cancelable> { let root = self.root(file_id); - let module_tree = root.module_tree(); + let module_tree = root.module_tree()?; let file = root.syntax(file_id); let syntax = file.syntax(); if let Some(name_ref) = find_node_at_offset::(syntax, offset) { // First try to resolve the symbol locally - if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { + return if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { let mut vec = vec![]; vec.push(( file_id, @@ -222,12 +224,11 @@ impl AnalysisImpl { kind: NAME, }, )); - - return vec; + Ok(vec) } else { // If that fails try the index based approach. - return self.index_resolve(name_ref, token); - } + self.index_resolve(name_ref) + }; } if let Some(name) = find_node_at_offset::(syntax, offset) { if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { @@ -250,14 +251,14 @@ impl AnalysisImpl { }) .collect(); - return res; + return Ok(res); } } } - vec![] + Ok(vec![]) } - pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, _token: &JobToken) -> Vec<(FileId, TextRange)> { + pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit) -> Vec<(FileId, TextRange)> { let root = self.root(file_id); let file = root.syntax(file_id); let syntax = file.syntax(); @@ -289,9 +290,9 @@ impl AnalysisImpl { ret } - pub fn diagnostics(&self, file_id: FileId) -> Vec { + pub fn diagnostics(&self, file_id: FileId) -> Cancelable> { let root = self.root(file_id); - let module_tree = root.module_tree(); + let module_tree = root.module_tree()?; let syntax = root.syntax(file_id); let mut res = ra_editor::diagnostics(&syntax) @@ -346,7 +347,7 @@ impl AnalysisImpl { }; res.push(diag) } - res + Ok(res) } pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec { @@ -379,18 +380,23 @@ impl AnalysisImpl { &self, file_id: FileId, offset: TextUnit, - token: &JobToken, - ) -> Option<(FnDescriptor, Option)> { + ) -> Cancelable)>> { let root = self.root(file_id); let file = root.syntax(file_id); let syntax = file.syntax(); // Find the calling expression and it's NameRef - let calling_node = FnCallNode::with_node(syntax, offset)?; - let name_ref = calling_node.name_ref()?; + let calling_node = match FnCallNode::with_node(syntax, offset) { + Some(node) => node, + None => return Ok(None), + }; + let name_ref = match calling_node.name_ref() { + Some(name) => name, + None => return Ok(None), + }; // Resolve the function's NameRef (NOTE: this isn't entirely accurate). - let file_symbols = self.index_resolve(name_ref, token); + let file_symbols = self.index_resolve(name_ref)?; for (_, fs) in file_symbols { if fs.kind == FN_DEF { if let Some(fn_def) = find_node_at_offset(syntax, fs.node_range.start()) { @@ -432,21 +438,21 @@ impl AnalysisImpl { } } - return Some((descriptor, current_parameter)); + return Ok(Some((descriptor, current_parameter))); } } } } - None + Ok(None) } - fn index_resolve(&self, name_ref: ast::NameRef, token: &JobToken) -> Vec<(FileId, FileSymbol)> { + fn index_resolve(&self, name_ref: ast::NameRef) -> Cancelable> { let name = name_ref.text(); let mut query = Query::new(name.to_string()); query.exact(); query.limit(4); - self.world_symbols(query, token) + self.world_symbols(query) } fn resolve_module( diff --git a/crates/ra_analysis/src/job.rs b/crates/ra_analysis/src/job.rs deleted file mode 100644 index 2871f98390..0000000000 --- a/crates/ra_analysis/src/job.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crossbeam_channel::{bounded, Receiver, Sender}; - -pub struct JobHandle { - job_alive: Receiver, - _job_canceled: Sender, -} - -pub struct JobToken { - _job_alive: Sender, - job_canceled: Receiver, -} - -impl JobHandle { - pub fn new() -> (JobHandle, JobToken) { - let (sender_alive, receiver_alive) = bounded(0); - let (sender_canceled, receiver_canceled) = bounded(0); - let token = JobToken { - _job_alive: sender_alive, - job_canceled: receiver_canceled, - }; - let handle = JobHandle { - job_alive: receiver_alive, - _job_canceled: sender_canceled, - }; - (handle, token) - } - pub fn has_completed(&self) -> bool { - is_closed(&self.job_alive) - } - pub fn cancel(self) {} -} - -impl JobToken { - pub fn is_canceled(&self) -> bool { - is_closed(&self.job_canceled) - } -} - -// We don't actually send messages through the channels, -// and instead just check if the channel is closed, -// so we use uninhabited enum as a message type -enum Never {} - -/// Nonblocking -fn is_closed(chan: &Receiver) -> bool { - select! { - recv(chan, msg) => match msg { - None => true, - Some(never) => match never {} - } - default => false, - } -} diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 46cc0722b2..28e0a12b20 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs @@ -7,8 +7,6 @@ extern crate ra_editor; extern crate ra_syntax; extern crate rayon; extern crate relative_path; -#[macro_use] -extern crate crossbeam_channel; extern crate im; extern crate rustc_hash; extern crate salsa; @@ -16,27 +14,40 @@ extern crate salsa; mod db; mod descriptors; mod imp; -mod job; mod module_map; mod roots; mod symbol_index; use std::{fmt::Debug, sync::Arc}; -use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}; use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; use relative_path::{RelativePath, RelativePathBuf}; use rustc_hash::FxHashMap; +use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}; + pub use crate::{ descriptors::FnDescriptor, - job::{JobHandle, JobToken}, }; pub use ra_editor::{ CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable, RunnableKind, StructureNode, }; +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Canceled; + +pub type Cancelable = Result; + +impl std::fmt::Display for Canceled { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fmt.write_str("Canceled") + } +} + +impl std::error::Error for Canceled { +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FileId(pub u32); @@ -205,60 +216,57 @@ impl Analysis { let file = self.imp.file_syntax(file_id); ra_editor::file_structure(&file) } - pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { - self.imp.world_symbols(query, token) - } - pub fn approximately_resolve_symbol( - &self, - file_id: FileId, - offset: TextUnit, - token: &JobToken, - ) -> Vec<(FileId, FileSymbol)> { - self.imp - .approximately_resolve_symbol(file_id, offset, token) - } - pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, TextRange)> { - self.imp.find_all_refs(file_id, offset, token) - } - pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { - self.imp.parent_module(file_id) - } - pub fn crate_for(&self, file_id: FileId) -> Vec { - self.imp.crate_for(file_id) - } - pub fn crate_root(&self, crate_id: CrateId) -> FileId { - self.imp.crate_root(crate_id) - } - pub fn runnables(&self, file_id: FileId) -> Vec { - let file = self.imp.file_syntax(file_id); - ra_editor::runnables(&file) - } - pub fn highlight(&self, file_id: FileId) -> Vec { - let file = self.imp.file_syntax(file_id); - ra_editor::highlight(&file) - } - pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Option> { - let file = self.imp.file_syntax(file_id); - ra_editor::scope_completion(&file, offset) - } - pub fn assists(&self, file_id: FileId, range: TextRange) -> Vec { - self.imp.assists(file_id, range) - } - pub fn diagnostics(&self, file_id: FileId) -> Vec { - self.imp.diagnostics(file_id) - } pub fn folding_ranges(&self, file_id: FileId) -> Vec { let file = self.imp.file_syntax(file_id); ra_editor::folding_ranges(&file) } - + pub fn symbol_search(&self, query: Query) -> Cancelable> { + self.imp.world_symbols(query) + } + pub fn approximately_resolve_symbol( + &self, + file_id: FileId, + offset: TextUnit + ) -> Cancelable> { + self.imp + .approximately_resolve_symbol(file_id, offset) + } + pub fn find_all_refs(&self, file_id: FileId, offset: TextUnit, ) -> Cancelable> { + Ok(self.imp.find_all_refs(file_id, offset)) + } + pub fn parent_module(&self, file_id: FileId) -> Cancelable> { + self.imp.parent_module(file_id) + } + pub fn crate_for(&self, file_id: FileId) -> Cancelable> { + self.imp.crate_for(file_id) + } + pub fn crate_root(&self, crate_id: CrateId) -> Cancelable { + Ok(self.imp.crate_root(crate_id)) + } + pub fn runnables(&self, file_id: FileId) -> Cancelable> { + let file = self.imp.file_syntax(file_id); + Ok(ra_editor::runnables(&file)) + } + pub fn highlight(&self, file_id: FileId) -> Cancelable> { + let file = self.imp.file_syntax(file_id); + Ok(ra_editor::highlight(&file)) + } + pub fn completions(&self, file_id: FileId, offset: TextUnit) -> Cancelable>> { + let file = self.imp.file_syntax(file_id); + Ok(ra_editor::scope_completion(&file, offset)) + } + pub fn assists(&self, file_id: FileId, range: TextRange) -> Cancelable> { + Ok(self.imp.assists(file_id, range)) + } + pub fn diagnostics(&self, file_id: FileId) -> Cancelable> { + self.imp.diagnostics(file_id) + } pub fn resolve_callable( &self, file_id: FileId, offset: TextUnit, - token: &JobToken, - ) -> Option<(FnDescriptor, Option)> { - self.imp.resolve_callable(file_id, offset, token) + ) -> Cancelable)>> { + self.imp.resolve_callable(file_id, offset) } } diff --git a/crates/ra_analysis/src/module_map.rs b/crates/ra_analysis/src/module_map.rs index b15432498c..3c800265ad 100644 --- a/crates/ra_analysis/src/module_map.rs +++ b/crates/ra_analysis/src/module_map.rs @@ -1,37 +1,41 @@ +use std::sync::Arc; + use crate::{ + db, + Cancelable, db::SyntaxDatabase, descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, FileId, }; -use std::sync::Arc; - salsa::query_group! { pub(crate) trait ModulesDatabase: SyntaxDatabase { - fn module_tree() -> Arc { + fn module_tree() -> Cancelable> { type ModuleTreeQuery; } - fn module_descriptor(file_id: FileId) -> Arc { + fn module_descriptor(file_id: FileId) -> Cancelable> { type ModuleDescriptorQuery; } } } -fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc { +fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Cancelable> { + db::check_canceled(db)?; let file = db.file_syntax(file_id); - Arc::new(ModuleDescriptor::new(file.ast())) + Ok(Arc::new(ModuleDescriptor::new(file.ast()))) } -fn module_tree(db: &impl ModulesDatabase) -> Arc { +fn module_tree(db: &impl ModulesDatabase) -> Cancelable> { + db::check_canceled(db)?; let file_set = db.file_set(); let mut files = Vec::new(); for &file_id in file_set.files.iter() { - let module_descr = db.module_descriptor(file_id); + let module_descr = db.module_descriptor(file_id)?; files.push((file_id, module_descr)); } let res = ModuleTreeDescriptor::new( files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.resolver, ); - Arc::new(res) + Ok(Arc::new(res)) } diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs index 19c84df65a..123c4acfa1 100644 --- a/crates/ra_analysis/src/roots.rs +++ b/crates/ra_analysis/src/roots.rs @@ -8,6 +8,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use salsa::Database; use crate::{ + Cancelable, db::{self, FilesDatabase, SyntaxDatabase}, descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, imp::FileResolverImp, @@ -18,10 +19,10 @@ use crate::{ pub(crate) trait SourceRoot { fn contains(&self, file_id: FileId) -> bool; - fn module_tree(&self) -> Arc; + fn module_tree(&self) -> Cancelable>; fn lines(&self, file_id: FileId) -> Arc; fn syntax(&self, file_id: FileId) -> File; - fn symbols(&self, acc: &mut Vec>); + fn symbols(&self, acc: &mut Vec>) -> Cancelable<()>; } #[derive(Default, Debug, Clone)] @@ -64,7 +65,7 @@ impl WritableSourceRoot { } impl SourceRoot for WritableSourceRoot { - fn module_tree(&self) -> Arc { + fn module_tree(&self) -> Cancelable> { self.db.module_tree() } fn contains(&self, file_id: FileId) -> bool { @@ -76,14 +77,12 @@ impl SourceRoot for WritableSourceRoot { fn syntax(&self, file_id: FileId) -> File { self.db.file_syntax(file_id) } - fn symbols<'a>(&'a self, acc: &mut Vec>) { - let db = &self.db; - let symbols = db.file_set(); - let symbols = symbols - .files - .iter() - .map(|&file_id| db.file_symbols(file_id)); - acc.extend(symbols); + fn symbols<'a>(&'a self, acc: &mut Vec>) -> Cancelable<()> { + for &file_id in self.db.file_set().files.iter() { + let symbols = self.db.file_symbols(file_id)?; + acc.push(symbols) + } + Ok(()) } } @@ -167,8 +166,8 @@ impl ReadonlySourceRoot { } impl SourceRoot for ReadonlySourceRoot { - fn module_tree(&self) -> Arc { - Arc::clone(&self.module_tree) + fn module_tree(&self) -> Cancelable> { + Ok(Arc::clone(&self.module_tree)) } fn contains(&self, file_id: FileId) -> bool { self.file_map.contains_key(&file_id) @@ -179,7 +178,8 @@ impl SourceRoot for ReadonlySourceRoot { fn syntax(&self, file_id: FileId) -> File { self.data(file_id).syntax().clone() } - fn symbols(&self, acc: &mut Vec>) { - acc.push(Arc::clone(&self.symbol_index)) + fn symbols(&self, acc: &mut Vec>) -> Cancelable<()> { + acc.push(Arc::clone(&self.symbol_index)); + Ok(()) } } diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 51eef81704..a0f3c04374 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs @@ -1,4 +1,8 @@ -use crate::{FileId, JobToken, Query}; +use std::{ + hash::{Hash, Hasher}, + sync::Arc, +}; + use fst::{self, Streamer}; use ra_editor::{file_symbols, FileSymbol}; use ra_syntax::{ @@ -7,10 +11,7 @@ use ra_syntax::{ }; use rayon::prelude::*; -use std::{ - hash::{Hash, Hasher}, - sync::Arc, -}; +use crate::{FileId, Query}; #[derive(Debug)] pub(crate) struct SymbolIndex { @@ -59,7 +60,6 @@ impl Query { pub(crate) fn search( self, indices: &[Arc], - token: &JobToken, ) -> Vec<(FileId, FileSymbol)> { let mut op = fst::map::OpBuilder::new(); for file_symbols in indices.iter() { @@ -69,7 +69,7 @@ impl Query { let mut stream = op.union(); let mut res = Vec::new(); while let Some((_, indexed_values)) = stream.next() { - if res.len() >= self.limit || token.is_canceled() { + if res.len() >= self.limit { break; } for indexed_value in indexed_values { diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index 0c2c69ea0d..7ae3d0eebf 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs @@ -7,15 +7,15 @@ extern crate test_utils; use std::sync::Arc; -use ra_analysis::{ - Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle, -}; use ra_syntax::TextRange; - use relative_path::{RelativePath, RelativePathBuf}; use rustc_hash::FxHashMap; use test_utils::{assert_eq_dbg, extract_offset}; +use ra_analysis::{ + Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, +}; + #[derive(Debug)] struct FileMap(Vec<(FileId, RelativePathBuf)>); @@ -64,24 +64,22 @@ fn get_signature(text: &str) -> (FnDescriptor, Option) { let (offset, code) = extract_offset(text); let code = code.as_str(); - let (_handle, token) = JobHandle::new(); let snap = analysis(&[("/lib.rs", code)]); - snap.resolve_callable(FileId(1), offset, &token).unwrap() + snap.resolve_callable(FileId(1), offset).unwrap().unwrap() } #[test] fn test_resolve_module() { let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); - let (_handle, token) = JobHandle::new(); - let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); + let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()).unwrap(); assert_eq_dbg( r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, &symbols, ); let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]); - let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); + let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into()).unwrap(); assert_eq_dbg( r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, &symbols, @@ -91,7 +89,7 @@ fn test_resolve_module() { #[test] fn test_unresolved_module_diagnostic() { let snap = analysis(&[("/lib.rs", "mod foo;")]); - let diagnostics = snap.diagnostics(FileId(1)); + let diagnostics = snap.diagnostics(FileId(1)).unwrap(); assert_eq_dbg( r#"[Diagnostic { message: "unresolved module", @@ -108,14 +106,14 @@ fn test_unresolved_module_diagnostic() { #[test] fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { let snap = analysis(&[("/lib.rs", "mod foo {}")]); - let diagnostics = snap.diagnostics(FileId(1)); + let diagnostics = snap.diagnostics(FileId(1)).unwrap(); assert_eq_dbg(r#"[]"#, &diagnostics); } #[test] fn test_resolve_parent_module() { let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); - let symbols = snap.parent_module(FileId(2)); + let symbols = snap.parent_module(FileId(2)).unwrap(); assert_eq_dbg( r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, &symbols, @@ -126,7 +124,7 @@ fn test_resolve_parent_module() { fn test_resolve_crate_root() { let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]); let snap = host.analysis(); - assert!(snap.crate_for(FileId(2)).is_empty()); + assert!(snap.crate_for(FileId(2)).unwrap().is_empty()); let crate_graph = CrateGraph { crate_roots: { @@ -138,7 +136,7 @@ fn test_resolve_crate_root() { host.set_crate_graph(crate_graph); let snap = host.analysis(); - assert_eq!(snap.crate_for(FileId(2)), vec![CrateId(1)],); + assert_eq!(snap.crate_for(FileId(2)).unwrap(), vec![CrateId(1)],); } #[test] @@ -232,10 +230,9 @@ fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> { let (offset, code) = extract_offset(text); let code = code.as_str(); - let (_handle, token) = JobHandle::new(); let snap = analysis(&[("/lib.rs", code)]); - snap.find_all_refs(FileId(1), offset, &token) + snap.find_all_refs(FileId(1), offset).unwrap() } #[test] @@ -266,4 +263,4 @@ fn test_find_all_refs_for_param_inside() { let refs = get_all_refs(code); assert_eq!(refs.len(), 2); -} \ No newline at end of file +} diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 639fe45537..f5dff4c80a 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -1,12 +1,13 @@ -use rustc_hash::FxHashMap; +use std::collections::HashMap; +use rustc_hash::FxHashMap; use languageserver_types::{ CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams, InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit, RenameParams, WorkspaceEdit, PrepareRenameResponse }; -use ra_analysis::{FileId, FoldKind, JobToken, Query, RunnableKind}; +use ra_analysis::{FileId, FoldKind, Query, RunnableKind}; use ra_syntax::text_utils::contains_offset_nonstrict; use serde_json::to_value; @@ -18,12 +19,9 @@ use crate::{ Result, }; -use std::collections::HashMap; - pub fn handle_syntax_tree( world: ServerWorld, params: req::SyntaxTreeParams, - _token: JobToken, ) -> Result { let id = params.text_document.try_conv_with(&world)?; let res = world.analysis().syntax_tree(id); @@ -33,7 +31,6 @@ pub fn handle_syntax_tree( pub fn handle_extend_selection( world: ServerWorld, params: req::ExtendSelectionParams, - _token: JobToken, ) -> Result { let file_id = params.text_document.try_conv_with(&world)?; let file = world.analysis().file_syntax(file_id); @@ -51,7 +48,6 @@ pub fn handle_extend_selection( pub fn handle_find_matching_brace( world: ServerWorld, params: req::FindMatchingBraceParams, - _token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let file = world.analysis().file_syntax(file_id); @@ -74,7 +70,6 @@ pub fn handle_find_matching_brace( pub fn handle_join_lines( world: ServerWorld, params: req::JoinLinesParams, - _token: JobToken, ) -> Result { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); @@ -88,7 +83,6 @@ pub fn handle_join_lines( pub fn handle_on_enter( world: ServerWorld, params: req::TextDocumentPositionParams, - _token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); @@ -102,7 +96,6 @@ pub fn handle_on_enter( pub fn handle_on_type_formatting( world: ServerWorld, params: req::DocumentOnTypeFormattingParams, - _token: JobToken, ) -> Result>> { if params.ch != "=" { return Ok(None); @@ -122,7 +115,6 @@ pub fn handle_on_type_formatting( pub fn handle_document_symbol( world: ServerWorld, params: req::DocumentSymbolParams, - _token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); @@ -161,7 +153,6 @@ pub fn handle_document_symbol( pub fn handle_workspace_symbol( world: ServerWorld, params: req::WorkspaceSymbolParams, - token: JobToken, ) -> Result>> { let all_symbols = params.query.contains("#"); let libs = params.query.contains("*"); @@ -181,11 +172,11 @@ pub fn handle_workspace_symbol( q.limit(128); q }; - let mut res = exec_query(&world, query, &token)?; + let mut res = exec_query(&world, query)?; if res.is_empty() && !all_symbols { let mut query = Query::new(params.query); query.limit(128); - res = exec_query(&world, query, &token)?; + res = exec_query(&world, query)?; } return Ok(Some(res)); @@ -193,10 +184,9 @@ pub fn handle_workspace_symbol( fn exec_query( world: &ServerWorld, query: Query, - token: &JobToken, ) -> Result> { let mut res = Vec::new(); - for (file_id, symbol) in world.analysis().symbol_search(query, token) { + for (file_id, symbol) in world.analysis().symbol_search(query)? { let line_index = world.analysis().file_line_index(file_id); let info = SymbolInformation { name: symbol.name.to_string(), @@ -214,7 +204,6 @@ pub fn handle_workspace_symbol( pub fn handle_goto_definition( world: ServerWorld, params: req::TextDocumentPositionParams, - token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); @@ -222,7 +211,7 @@ pub fn handle_goto_definition( let mut res = Vec::new(); for (file_id, symbol) in world .analysis() - .approximately_resolve_symbol(file_id, offset, &token) + .approximately_resolve_symbol(file_id, offset)? { let line_index = world.analysis().file_line_index(file_id); let location = to_location(file_id, symbol.node_range, &world, &line_index)?; @@ -234,11 +223,10 @@ pub fn handle_goto_definition( pub fn handle_parent_module( world: ServerWorld, params: TextDocumentIdentifier, - _token: JobToken, ) -> Result> { let file_id = params.try_conv_with(&world)?; let mut res = Vec::new(); - for (file_id, symbol) in world.analysis().parent_module(file_id) { + for (file_id, symbol) in world.analysis().parent_module(file_id)? { let line_index = world.analysis().file_line_index(file_id); let location = to_location(file_id, symbol.node_range, &world, &line_index)?; res.push(location); @@ -249,20 +237,19 @@ pub fn handle_parent_module( pub fn handle_runnables( world: ServerWorld, params: req::RunnablesParams, - _token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); let offset = params.position.map(|it| it.conv_with(&line_index)); let mut res = Vec::new(); - for runnable in world.analysis().runnables(file_id) { + for runnable in world.analysis().runnables(file_id)? { if let Some(offset) = offset { if !contains_offset_nonstrict(runnable.range, offset) { continue; } } - let args = runnable_args(&world, file_id, &runnable.kind); + let args = runnable_args(&world, file_id, &runnable.kind)?; let r = req::Runnable { range: runnable.range.conv_with(&line_index), @@ -282,9 +269,9 @@ pub fn handle_runnables( } return Ok(res); - fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Vec { - let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id).first() { - let file_id = world.analysis().crate_root(crate_id); + fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result> { + let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id)?.first() { + let file_id = world.analysis().crate_root(crate_id)?; let path = world.path_map.get_path(file_id); world .workspaces @@ -319,7 +306,7 @@ pub fn handle_runnables( } } } - res + Ok(res) } fn spec_args(pkg_name: &str, tgt_name: &str, tgt_kind: TargetKind, buf: &mut Vec) { @@ -353,21 +340,19 @@ pub fn handle_runnables( pub fn handle_decorations( world: ServerWorld, params: TextDocumentIdentifier, - _token: JobToken, ) -> Result> { let file_id = params.try_conv_with(&world)?; - Ok(highlight(&world, file_id)) + highlight(&world, file_id) } pub fn handle_completion( world: ServerWorld, params: req::CompletionParams, - _token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); let offset = params.position.conv_with(&line_index); - let items = match world.analysis().completions(file_id, offset) { + let items = match world.analysis().completions(file_id, offset)? { None => return Ok(None), Some(items) => items, }; @@ -394,7 +379,6 @@ pub fn handle_completion( pub fn handle_folding_range( world: ServerWorld, params: FoldingRangeParams, - _token: JobToken, ) -> Result>> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); @@ -427,7 +411,6 @@ pub fn handle_folding_range( pub fn handle_signature_help( world: ServerWorld, params: req::TextDocumentPositionParams, - token: JobToken, ) -> Result> { use languageserver_types::{ParameterInformation, SignatureInformation}; @@ -436,7 +419,7 @@ pub fn handle_signature_help( let offset = params.position.conv_with(&line_index); if let Some((descriptor, active_param)) = - world.analysis().resolve_callable(file_id, offset, &token) + world.analysis().resolve_callable(file_id, offset)? { let parameters: Vec = descriptor .params @@ -466,7 +449,6 @@ pub fn handle_signature_help( pub fn handle_prepare_rename( world: ServerWorld, params: req::TextDocumentPositionParams, - token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); @@ -474,7 +456,7 @@ pub fn handle_prepare_rename( // We support renaming references like handle_rename does. // In the future we may want to reject the renaming of things like keywords here too. - let refs = world.analysis().find_all_refs(file_id, offset, &token); + let refs = world.analysis().find_all_refs(file_id, offset)?; if refs.is_empty() { return Ok(None); } @@ -488,7 +470,6 @@ pub fn handle_prepare_rename( pub fn handle_rename( world: ServerWorld, params: RenameParams, - token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); @@ -498,7 +479,7 @@ pub fn handle_rename( return Ok(None); } - let refs = world.analysis().find_all_refs(file_id, offset, &token); + let refs = world.analysis().find_all_refs(file_id, offset)?; if refs.is_empty() { return Ok(None); } @@ -525,13 +506,12 @@ pub fn handle_rename( pub fn handle_references( world: ServerWorld, params: req::ReferenceParams, - token: JobToken, ) -> Result>> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); let offset = params.position.conv_with(&line_index); - let refs = world.analysis().find_all_refs(file_id, offset, &token); + let refs = world.analysis().find_all_refs(file_id, offset)?; Ok(Some(refs.into_iter() .filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok()) @@ -541,16 +521,15 @@ pub fn handle_references( pub fn handle_code_action( world: ServerWorld, params: req::CodeActionParams, - _token: JobToken, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; let line_index = world.analysis().file_line_index(file_id); let range = params.range.conv_with(&line_index); - let assists = world.analysis().assists(file_id, range).into_iter(); + let assists = world.analysis().assists(file_id, range)?.into_iter(); let fixes = world .analysis() - .diagnostics(file_id) + .diagnostics(file_id)? .into_iter() .filter_map(|d| Some((d.range, d.fix?))) .filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start())) @@ -579,7 +558,7 @@ pub fn publish_diagnostics( let line_index = world.analysis().file_line_index(file_id); let diagnostics = world .analysis() - .diagnostics(file_id) + .diagnostics(file_id)? .into_iter() .map(|d| Diagnostic { range: d.range.conv_with(&line_index), @@ -600,19 +579,20 @@ pub fn publish_decorations( let uri = world.file_id_to_uri(file_id)?; Ok(req::PublishDecorationsParams { uri, - decorations: highlight(&world, file_id), + decorations: highlight(&world, file_id)?, }) } -fn highlight(world: &ServerWorld, file_id: FileId) -> Vec { +fn highlight(world: &ServerWorld, file_id: FileId) -> Result> { let line_index = world.analysis().file_line_index(file_id); - world + let res = world .analysis() - .highlight(file_id) + .highlight(file_id)? .into_iter() .map(|h| Decoration { range: h.range.conv_with(&line_index), tag: h.tag, }) - .collect() + .collect(); + Ok(res) } diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs index 165f2e78f0..b35ebd38b6 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::{ handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, }; use languageserver_types::NumberOrString; -use ra_analysis::{FileId, JobHandle, JobToken, LibraryData}; +use ra_analysis::{FileId, LibraryData}; use rayon::{self, ThreadPool}; -use rustc_hash::FxHashMap; +use rustc_hash::FxHashSet; use serde::{de::DeserializeOwned, Serialize}; use crate::{ @@ -47,7 +47,7 @@ pub fn main_loop( info!("server initialized, serving requests"); let mut state = ServerWorldState::new(); - let mut pending_requests = FxHashMap::default(); + let mut pending_requests = FxHashSet::default(); let mut subs = Subscriptions::new(); let main_res = main_loop_inner( internal_mode, @@ -92,7 +92,7 @@ fn main_loop_inner( fs_worker: Worker)>, ws_worker: Worker>, state: &mut ServerWorldState, - pending_requests: &mut FxHashMap, + pending_requests: &mut FxHashSet, subs: &mut Subscriptions, ) -> Result<()> { let (libdata_sender, libdata_receiver) = unbounded(); @@ -204,14 +204,13 @@ fn main_loop_inner( fn on_task( task: Task, msg_sender: &Sender, - pending_requests: &mut FxHashMap, + pending_requests: &mut FxHashSet, ) { match task { Task::Respond(response) => { - if let Some(handle) = pending_requests.remove(&response.id) { - assert!(handle.has_completed()); + if pending_requests.remove(&response.id) { + msg_sender.send(RawMessage::Response(response)) } - msg_sender.send(RawMessage::Response(response)) } Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)), } @@ -219,7 +218,7 @@ fn on_task( fn on_request( world: &mut ServerWorldState, - pending_requests: &mut FxHashMap, + pending_requests: &mut FxHashSet, pool: &ThreadPool, sender: &Sender, req: RawRequest, @@ -253,8 +252,8 @@ fn on_request( .on::(handlers::handle_references)? .finish(); match req { - Ok((id, handle)) => { - let inserted = pending_requests.insert(id, handle).is_none(); + Ok(id) => { + let inserted = pending_requests.insert(id); assert!(inserted, "duplicate request: {}", id); Ok(None) } @@ -265,7 +264,7 @@ fn on_request( fn on_notification( msg_sender: &Sender, state: &mut ServerWorldState, - pending_requests: &mut FxHashMap, + pending_requests: &mut FxHashSet, subs: &mut Subscriptions, not: RawNotification, ) -> Result<()> { @@ -277,9 +276,7 @@ fn on_notification( panic!("string id's not supported: {:?}", id); } }; - if let Some(handle) = pending_requests.remove(&id) { - handle.cancel(); - } + pending_requests.remove(&id); return Ok(()); } Err(not) => not, @@ -336,7 +333,7 @@ fn on_notification( struct PoolDispatcher<'a> { req: Option, - res: Option<(u64, JobHandle)>, + res: Option, pool: &'a ThreadPool, world: &'a ServerWorldState, sender: &'a Sender, @@ -345,7 +342,7 @@ struct PoolDispatcher<'a> { impl<'a> PoolDispatcher<'a> { fn on<'b, R>( &'b mut self, - f: fn(ServerWorld, R::Params, JobToken) -> Result, + f: fn(ServerWorld, R::Params) -> Result, ) -> Result<&'b mut Self> where R: req::Request, @@ -358,11 +355,10 @@ impl<'a> PoolDispatcher<'a> { }; match req.cast::() { Ok((id, params)) => { - let (handle, token) = JobHandle::new(); let world = self.world.snapshot(); let sender = self.sender.clone(); self.pool.spawn(move || { - let resp = match f(world, params, token) { + let resp = match f(world, params) { Ok(resp) => RawResponse::ok::(id, &resp), Err(e) => { RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string()) @@ -371,14 +367,14 @@ impl<'a> PoolDispatcher<'a> { let task = Task::Respond(resp); sender.send(task); }); - self.res = Some((id, handle)); + self.res = Some(id); } Err(req) => self.req = Some(req), } Ok(self) } - fn finish(&mut self) -> ::std::result::Result<(u64, JobHandle), RawRequest> { + fn finish(&mut self) -> ::std::result::Result { match (self.res.take(), self.req.take()) { (Some(res), None) => Ok(res), (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 585013acd3..d328293826 100644 --- a/crates/ra_lsp_server/src/path_map.rs +++ b/crates/ra_lsp_server/src/path_map.rs @@ -1,9 +1,9 @@ +use std::path::{Component, Path, PathBuf}; + use im; use ra_analysis::{FileId, FileResolver}; use relative_path::RelativePath; -use std::path::{Component, Path, PathBuf}; - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Root { Workspace, diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index d170ceb733..04e2ef9c85 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs @@ -1,9 +1,9 @@ +use std::path::{Path, PathBuf}; + use cargo_metadata::{metadata_run, CargoOpt}; use ra_syntax::SmolStr; use rustc_hash::{FxHashMap, FxHashSet}; -use std::path::{Path, PathBuf}; - use crate::{ thread_watcher::{ThreadWatcher, Worker}, Result, diff --git a/crates/ra_lsp_server/src/thread_watcher.rs b/crates/ra_lsp_server/src/thread_watcher.rs index 67952eb747..51b35fa667 100644 --- a/crates/ra_lsp_server/src/thread_watcher.rs +++ b/crates/ra_lsp_server/src/thread_watcher.rs @@ -1,8 +1,9 @@ -use crate::Result; +use std::thread; + use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; use drop_bomb::DropBomb; -use std::thread; +use crate::Result; pub struct Worker { pub inp: Sender,