From d3a2b21a8c34c7b7eea0a001a1412992e3ed2cb7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 29 Sep 2020 20:08:27 +0200 Subject: [PATCH] Add panic_context module for better panic messages --- crates/rust-analyzer/src/dispatch.rs | 7 ++-- crates/stdx/src/lib.rs | 1 + crates/stdx/src/panic_context.rs | 49 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 crates/stdx/src/panic_context.rs diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index 891fdb96d1..36f0c1d520 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs @@ -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 @@ impl<'a> RequestDispatcher<'a> { ) -> 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::() { @@ -61,7 +61,10 @@ impl<'a> RequestDispatcher<'a> { 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::(id, result)) } diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 273b0f55b2..011935cade 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -5,6 +5,7 @@ use std::{ }; 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 index 0000000000..fd232e0cce --- /dev/null +++ b/crates/stdx/src/panic_context.rs @@ -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)) { + thread_local! { + static CTX: RefCell> = RefCell::new(Vec::new()); + } + CTX.with(|ctx| f(&mut *ctx.borrow_mut())) +}