aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-10-30 18:38:29 +0000
committerAleksey Kladov <[email protected]>2020-10-30 18:57:52 +0000
commit3b9548e163ed64d21d56873a4ba3583bf2f44535 (patch)
tree4de2b573a2e0b4f02e6edc788737d40199a7a204
parente7c8c600b783bbf12deb952a2e10be23264de953 (diff)
Respond with JSON-RPC error if we failed to deserialize request
Historically, we intentinally violated JSON-RPC spec here by hard crashing. The idea was to poke both the clients and servers to fix stuff. However, this is confusing for server implementors, and falls down in one important place -- protocol extension are not always backwards compatible, which causes crashes simply due to version mismatch. We had once such case with our own extension, and one for semantic tokens. So let's be less adventerous and just err on the err side!
-rw-r--r--crates/rust-analyzer/src/dispatch.rs40
-rw-r--r--crates/rust-analyzer/src/lib.rs10
-rw-r--r--crates/rust-analyzer/src/main_loop.rs70
3 files changed, 62 insertions, 58 deletions
diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs
index 7a87515e9..81b85a269 100644
--- a/crates/rust-analyzer/src/dispatch.rs
+++ b/crates/rust-analyzer/src/dispatch.rs
@@ -28,17 +28,16 @@ impl<'a> RequestDispatcher<'a> {
28 { 28 {
29 let (id, params) = match self.parse::<R>() { 29 let (id, params) = match self.parse::<R>() {
30 Some(it) => it, 30 Some(it) => it,
31 None => { 31 None => return Ok(self),
32 return Ok(self);
33 }
34 }; 32 };
35 let world = panic::AssertUnwindSafe(&mut *self.global_state); 33 let world = panic::AssertUnwindSafe(&mut *self.global_state);
34
36 let response = panic::catch_unwind(move || { 35 let response = panic::catch_unwind(move || {
37 let _pctx = stdx::panic_context::enter(format!("request: {} {:#?}", R::METHOD, params)); 36 let _pctx = stdx::panic_context::enter(format!("request: {} {:#?}", R::METHOD, params));
38 let result = f(world.0, params); 37 let result = f(world.0, params);
39 result_to_response::<R>(id, result) 38 result_to_response::<R>(id, result)
40 }) 39 })
41 .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?; 40 .map_err(|_err| format!("sync task {:?} panicked", R::METHOD))?;
42 self.global_state.respond(response); 41 self.global_state.respond(response);
43 Ok(self) 42 Ok(self)
44 } 43 }
@@ -47,7 +46,7 @@ impl<'a> RequestDispatcher<'a> {
47 pub(crate) fn on<R>( 46 pub(crate) fn on<R>(
48 &mut self, 47 &mut self,
49 f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>, 48 f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
50 ) -> Result<&mut Self> 49 ) -> &mut Self
51 where 50 where
52 R: lsp_types::request::Request + 'static, 51 R: lsp_types::request::Request + 'static,
53 R::Params: DeserializeOwned + Send + fmt::Debug + 'static, 52 R::Params: DeserializeOwned + Send + fmt::Debug + 'static,
@@ -55,9 +54,7 @@ impl<'a> RequestDispatcher<'a> {
55 { 54 {
56 let (id, params) = match self.parse::<R>() { 55 let (id, params) = match self.parse::<R>() {
57 Some(it) => it, 56 Some(it) => it,
58 None => { 57 None => return self,
59 return Ok(self);
60 }
61 }; 58 };
62 59
63 self.global_state.task_pool.handle.spawn({ 60 self.global_state.task_pool.handle.spawn({
@@ -71,7 +68,7 @@ impl<'a> RequestDispatcher<'a> {
71 } 68 }
72 }); 69 });
73 70
74 Ok(self) 71 self
75 } 72 }
76 73
77 pub(crate) fn finish(&mut self) { 74 pub(crate) fn finish(&mut self) {
@@ -82,7 +79,7 @@ impl<'a> RequestDispatcher<'a> {
82 lsp_server::ErrorCode::MethodNotFound as i32, 79 lsp_server::ErrorCode::MethodNotFound as i32,
83 "unknown request".to_string(), 80 "unknown request".to_string(),
84 ); 81 );
85 self.global_state.respond(response) 82 self.global_state.respond(response);
86 } 83 }
87 } 84 }
88 85
@@ -91,15 +88,24 @@ impl<'a> RequestDispatcher<'a> {
91 R: lsp_types::request::Request + 'static, 88 R: lsp_types::request::Request + 'static,
92 R::Params: DeserializeOwned + 'static, 89 R::Params: DeserializeOwned + 'static,
93 { 90 {
94 let req = self.req.take()?; 91 let req = match &self.req {
95 let (id, params) = match req.extract::<R::Params>(R::METHOD) { 92 Some(req) if req.method == R::METHOD => self.req.take().unwrap(),
96 Ok(it) => it, 93 _ => return None,
97 Err(req) => { 94 };
98 self.req = Some(req); 95
96 let res = crate::from_json(R::METHOD, req.params);
97 match res {
98 Ok(params) => return Some((req.id, params)),
99 Err(err) => {
100 let response = lsp_server::Response::new_err(
101 req.id,
102 lsp_server::ErrorCode::InvalidParams as i32,
103 err.to_string(),
104 );
105 self.global_state.respond(response);
99 return None; 106 return None;
100 } 107 }
101 }; 108 }
102 Some((id, params))
103 } 109 }
104} 110}
105 111
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index 87f72b497..ad08f1afb 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -37,14 +37,16 @@ mod document;
37pub mod lsp_ext; 37pub mod lsp_ext;
38pub mod config; 38pub mod config;
39 39
40use serde::de::DeserializeOwned;
41
42pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>;
43pub use crate::{caps::server_capabilities, main_loop::main_loop};
44use ide::AnalysisHost; 40use ide::AnalysisHost;
41use serde::de::DeserializeOwned;
45use std::fmt; 42use std::fmt;
46use vfs::Vfs; 43use vfs::Vfs;
47 44
45pub use crate::{caps::server_capabilities, main_loop::main_loop};
46
47pub type Error = Box<dyn std::error::Error + Send + Sync>;
48pub type Result<T, E = Error> = std::result::Result<T, E>;
49
48pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { 50pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> {
49 let res = T::deserialize(&json) 51 let res = T::deserialize(&json)
50 .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?; 52 .map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?;
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index ff855fe1a..53f8ca194 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -403,53 +403,49 @@ impl GlobalState {
403 handlers::handle_matching_brace(s.snapshot(), p) 403 handlers::handle_matching_brace(s.snapshot(), p)
404 })? 404 })?
405 .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? 405 .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
406 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)? 406 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
407 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)? 407 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
408 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)? 408 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
409 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)? 409 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
410 .on::<lsp_ext::Runnables>(handlers::handle_runnables)? 410 .on::<lsp_ext::Runnables>(handlers::handle_runnables)
411 .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints)? 411 .on::<lsp_ext::InlayHints>(handlers::handle_inlay_hints)
412 .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)? 412 .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)
413 .on::<lsp_ext::ResolveCodeActionRequest>(handlers::handle_resolve_code_action)? 413 .on::<lsp_ext::ResolveCodeActionRequest>(handlers::handle_resolve_code_action)
414 .on::<lsp_ext::HoverRequest>(handlers::handle_hover)? 414 .on::<lsp_ext::HoverRequest>(handlers::handle_hover)
415 .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)? 415 .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
416 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)? 416 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)
417 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)? 417 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
418 .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)? 418 .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)
419 .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)? 419 .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
420 .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)? 420 .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
421 .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)? 421 .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
422 .on::<lsp_types::request::Completion>(handlers::handle_completion)? 422 .on::<lsp_types::request::Completion>(handlers::handle_completion)
423 .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)? 423 .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
424 .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)? 424 .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
425 .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)? 425 .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
426 .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)? 426 .on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)
427 .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)? 427 .on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)
428 .on::<lsp_types::request::Rename>(handlers::handle_rename)? 428 .on::<lsp_types::request::Rename>(handlers::handle_rename)
429 .on::<lsp_types::request::References>(handlers::handle_references)? 429 .on::<lsp_types::request::References>(handlers::handle_references)
430 .on::<lsp_types::request::Formatting>(handlers::handle_formatting)? 430 .on::<lsp_types::request::Formatting>(handlers::handle_formatting)
431 .on::<lsp_types::request::DocumentHighlightRequest>( 431 .on::<lsp_types::request::DocumentHighlightRequest>(handlers::handle_document_highlight)
432 handlers::handle_document_highlight, 432 .on::<lsp_types::request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
433 )?
434 .on::<lsp_types::request::CallHierarchyPrepare>(
435 handlers::handle_call_hierarchy_prepare,
436 )?
437 .on::<lsp_types::request::CallHierarchyIncomingCalls>( 433 .on::<lsp_types::request::CallHierarchyIncomingCalls>(
438 handlers::handle_call_hierarchy_incoming, 434 handlers::handle_call_hierarchy_incoming,
439 )? 435 )
440 .on::<lsp_types::request::CallHierarchyOutgoingCalls>( 436 .on::<lsp_types::request::CallHierarchyOutgoingCalls>(
441 handlers::handle_call_hierarchy_outgoing, 437 handlers::handle_call_hierarchy_outgoing,
442 )? 438 )
443 .on::<lsp_types::request::SemanticTokensFullRequest>( 439 .on::<lsp_types::request::SemanticTokensFullRequest>(
444 handlers::handle_semantic_tokens_full, 440 handlers::handle_semantic_tokens_full,
445 )? 441 )
446 .on::<lsp_types::request::SemanticTokensFullDeltaRequest>( 442 .on::<lsp_types::request::SemanticTokensFullDeltaRequest>(
447 handlers::handle_semantic_tokens_full_delta, 443 handlers::handle_semantic_tokens_full_delta,
448 )? 444 )
449 .on::<lsp_types::request::SemanticTokensRangeRequest>( 445 .on::<lsp_types::request::SemanticTokensRangeRequest>(
450 handlers::handle_semantic_tokens_range, 446 handlers::handle_semantic_tokens_range,
451 )? 447 )
452 .on::<lsp_ext::Ssr>(handlers::handle_ssr)? 448 .on::<lsp_ext::Ssr>(handlers::handle_ssr)
453 .finish(); 449 .finish();
454 Ok(()) 450 Ok(())
455 } 451 }