]> git.lizzy.rs Git - rust.git/commitdiff
Add panic_context module for better panic messages
authorAleksey Kladov <aleksey.kladov@gmail.com>
Tue, 29 Sep 2020 18:08:27 +0000 (20:08 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Tue, 29 Sep 2020 18:20:47 +0000 (20:20 +0200)
crates/rust-analyzer/src/dispatch.rs
crates/stdx/src/lib.rs
crates/stdx/src/panic_context.rs [new file with mode: 0644]

index 891fdb96d1de90976d6aaddc265a76ecdde236ee..36f0c1d520e2de407660872231f1a7832bfb7757 100644 (file)
@@ -1,5 +1,5 @@
 //! A visitor for downcasting arbitrary request (JSON) into a specific type.
-use std::panic;
+use std::{fmt, panic};
 
 use serde::{de::DeserializeOwned, Serialize};
 
@@ -49,7 +49,7 @@ pub(crate) fn on<R>(
     ) -> Result<&mut Self>
     where
         R: lsp_types::request::Request + 'static,
-        R::Params: DeserializeOwned + Send + 'static,
+        R::Params: DeserializeOwned + Send + fmt::Debug + 'static,
         R::Result: Serialize + 'static,
     {
         let (id, params) = match self.parse::<R>() {
@@ -61,7 +61,10 @@ pub(crate) fn on<R>(
 
         self.global_state.task_pool.handle.spawn({
             let world = self.global_state.snapshot();
+
             move || {
+                let _ctx =
+                    stdx::panic_context::enter(format!("request: {} {:#?}", R::METHOD, params));
                 let result = f(world, params);
                 Task::Response(result_to_response::<R>(id, result))
             }
index 273b0f55b2c12d102cc831d1713da87bd390f8d8..011935cade9caebce60ff64f8e0f94f3ff3009e2 100644 (file)
@@ -5,6 +5,7 @@
 };
 
 mod macros;
+pub mod panic_context;
 
 #[inline(always)]
 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 (file)
index 0000000..fd232e0
--- /dev/null
@@ -0,0 +1,49 @@
+//! A micro-crate to enhance panic messages with context info.
+//!
+//! FIXME: upstream to https://github.com/kriomant/panic-context ?
+
+use std::{cell::RefCell, panic, sync::Once};
+
+pub fn enter(context: String) -> impl Drop {
+    static ONCE: Once = Once::new();
+    ONCE.call_once(PanicContext::init);
+
+    with_ctx(|ctx| ctx.push(context));
+    PanicContext { _priv: () }
+}
+
+#[must_use]
+struct PanicContext {
+    _priv: (),
+}
+
+impl PanicContext {
+    fn init() {
+        let default_hook = panic::take_hook();
+        let hook = move |panic_info: &panic::PanicInfo<'_>| {
+            with_ctx(|ctx| {
+                if !ctx.is_empty() {
+                    eprintln!("Panic context:");
+                    for frame in ctx.iter() {
+                        eprintln!("> {}\n", frame)
+                    }
+                }
+                default_hook(panic_info)
+            })
+        };
+        panic::set_hook(Box::new(hook))
+    }
+}
+
+impl Drop for PanicContext {
+    fn drop(&mut self) {
+        with_ctx(|ctx| assert!(ctx.pop().is_some()))
+    }
+}
+
+fn with_ctx(f: impl FnOnce(&mut Vec<String>)) {
+    thread_local! {
+        static CTX: RefCell<Vec<String>> = RefCell::new(Vec::new());
+    }
+    CTX.with(|ctx| f(&mut *ctx.borrow_mut()))
+}