aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-09-29 19:08:27 +0100
committerAleksey Kladov <[email protected]>2020-09-29 19:20:47 +0100
commitd3a2b21a8c34c7b7eea0a001a1412992e3ed2cb7 (patch)
tree0f965a835c179637f6df293cef010134f283cfea
parente315fd9bb0e0647ab8b0e118d264d2103e271586 (diff)
Add panic_context module for better panic messages
-rw-r--r--crates/rust-analyzer/src/dispatch.rs7
-rw-r--r--crates/stdx/src/lib.rs1
-rw-r--r--crates/stdx/src/panic_context.rs49
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.
2use std::panic; 2use std::{fmt, panic};
3 3
4use serde::{de::DeserializeOwned, Serialize}; 4use 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
7mod macros; 7mod macros;
8pub mod panic_context;
8 9
9#[inline(always)] 10#[inline(always)]
10pub fn is_ci() -> bool { 11pub 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
5use std::{cell::RefCell, panic, sync::Once};
6
7pub 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]
16struct PanicContext {
17 _priv: (),
18}
19
20impl 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
38impl Drop for PanicContext {
39 fn drop(&mut self) {
40 with_ctx(|ctx| assert!(ctx.pop().is_some()))
41 }
42}
43
44fn 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}