diff options
-rw-r--r-- | crates/rust-analyzer/src/dispatch.rs | 7 | ||||
-rw-r--r-- | crates/stdx/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/stdx/src/panic_context.rs | 49 |
3 files changed, 55 insertions, 2 deletions
diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index 891fdb96d..36f0c1d52 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! A visitor for downcasting arbitrary request (JSON) into a specific type. | 1 | //! A visitor for downcasting arbitrary request (JSON) into a specific type. |
2 | use std::panic; | 2 | use std::{fmt, panic}; |
3 | 3 | ||
4 | use serde::{de::DeserializeOwned, Serialize}; | 4 | use serde::{de::DeserializeOwned, Serialize}; |
5 | 5 | ||
@@ -49,7 +49,7 @@ impl<'a> RequestDispatcher<'a> { | |||
49 | ) -> Result<&mut Self> | 49 | ) -> Result<&mut Self> |
50 | where | 50 | where |
51 | R: lsp_types::request::Request + 'static, | 51 | R: lsp_types::request::Request + 'static, |
52 | R::Params: DeserializeOwned + Send + 'static, | 52 | R::Params: DeserializeOwned + Send + fmt::Debug + 'static, |
53 | R::Result: Serialize + 'static, | 53 | R::Result: Serialize + 'static, |
54 | { | 54 | { |
55 | let (id, params) = match self.parse::<R>() { | 55 | let (id, params) = match self.parse::<R>() { |
@@ -61,7 +61,10 @@ impl<'a> RequestDispatcher<'a> { | |||
61 | 61 | ||
62 | self.global_state.task_pool.handle.spawn({ | 62 | self.global_state.task_pool.handle.spawn({ |
63 | let world = self.global_state.snapshot(); | 63 | let world = self.global_state.snapshot(); |
64 | |||
64 | move || { | 65 | move || { |
66 | let _ctx = | ||
67 | stdx::panic_context::enter(format!("request: {} {:#?}", R::METHOD, params)); | ||
65 | let result = f(world, params); | 68 | let result = f(world, params); |
66 | Task::Response(result_to_response::<R>(id, result)) | 69 | Task::Response(result_to_response::<R>(id, result)) |
67 | } | 70 | } |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 273b0f55b..011935cad 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -5,6 +5,7 @@ use std::{ | |||
5 | }; | 5 | }; |
6 | 6 | ||
7 | mod macros; | 7 | mod macros; |
8 | pub mod panic_context; | ||
8 | 9 | ||
9 | #[inline(always)] | 10 | #[inline(always)] |
10 | pub fn is_ci() -> bool { | 11 | pub fn is_ci() -> bool { |
diff --git a/crates/stdx/src/panic_context.rs b/crates/stdx/src/panic_context.rs new file mode 100644 index 000000000..fd232e0cc --- /dev/null +++ b/crates/stdx/src/panic_context.rs | |||
@@ -0,0 +1,49 @@ | |||
1 | //! A micro-crate to enhance panic messages with context info. | ||
2 | //! | ||
3 | //! FIXME: upstream to https://github.com/kriomant/panic-context ? | ||
4 | |||
5 | use std::{cell::RefCell, panic, sync::Once}; | ||
6 | |||
7 | pub fn enter(context: String) -> impl Drop { | ||
8 | static ONCE: Once = Once::new(); | ||
9 | ONCE.call_once(PanicContext::init); | ||
10 | |||
11 | with_ctx(|ctx| ctx.push(context)); | ||
12 | PanicContext { _priv: () } | ||
13 | } | ||
14 | |||
15 | #[must_use] | ||
16 | struct PanicContext { | ||
17 | _priv: (), | ||
18 | } | ||
19 | |||
20 | impl PanicContext { | ||
21 | fn init() { | ||
22 | let default_hook = panic::take_hook(); | ||
23 | let hook = move |panic_info: &panic::PanicInfo<'_>| { | ||
24 | with_ctx(|ctx| { | ||
25 | if !ctx.is_empty() { | ||
26 | eprintln!("Panic context:"); | ||
27 | for frame in ctx.iter() { | ||
28 | eprintln!("> {}\n", frame) | ||
29 | } | ||
30 | } | ||
31 | default_hook(panic_info) | ||
32 | }) | ||
33 | }; | ||
34 | panic::set_hook(Box::new(hook)) | ||
35 | } | ||
36 | } | ||
37 | |||
38 | impl Drop for PanicContext { | ||
39 | fn drop(&mut self) { | ||
40 | with_ctx(|ctx| assert!(ctx.pop().is_some())) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | fn with_ctx(f: impl FnOnce(&mut Vec<String>)) { | ||
45 | thread_local! { | ||
46 | static CTX: RefCell<Vec<String>> = RefCell::new(Vec::new()); | ||
47 | } | ||
48 | CTX.with(|ctx| f(&mut *ctx.borrow_mut())) | ||
49 | } | ||