diff options
author | Aleksey Kladov <[email protected]> | 2020-10-30 18:38:29 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-10-30 18:57:52 +0000 |
commit | 3b9548e163ed64d21d56873a4ba3583bf2f44535 (patch) | |
tree | 4de2b573a2e0b4f02e6edc788737d40199a7a204 | |
parent | e7c8c600b783bbf12deb952a2e10be23264de953 (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.rs | 40 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lib.rs | 10 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 70 |
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; | |||
37 | pub mod lsp_ext; | 37 | pub mod lsp_ext; |
38 | pub mod config; | 38 | pub mod config; |
39 | 39 | ||
40 | use serde::de::DeserializeOwned; | ||
41 | |||
42 | pub type Result<T, E = Box<dyn std::error::Error + Send + Sync>> = std::result::Result<T, E>; | ||
43 | pub use crate::{caps::server_capabilities, main_loop::main_loop}; | ||
44 | use ide::AnalysisHost; | 40 | use ide::AnalysisHost; |
41 | use serde::de::DeserializeOwned; | ||
45 | use std::fmt; | 42 | use std::fmt; |
46 | use vfs::Vfs; | 43 | use vfs::Vfs; |
47 | 44 | ||
45 | pub use crate::{caps::server_capabilities, main_loop::main_loop}; | ||
46 | |||
47 | pub type Error = Box<dyn std::error::Error + Send + Sync>; | ||
48 | pub type Result<T, E = Error> = std::result::Result<T, E>; | ||
49 | |||
48 | pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> { | 50 | pub 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 | } |