Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/base-db/src/lib.rs')
-rw-r--r--crates/base-db/src/lib.rs58
1 files changed, 52 insertions, 6 deletions
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index 1d73ba804a..9275a58687 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -3,7 +3,7 @@
mod change;
mod input;
-use std::hash::BuildHasherDefault;
+use std::{cell::RefCell, hash::BuildHasherDefault, panic, sync::Once};
pub use crate::{
change::FileChange,
@@ -60,7 +60,7 @@ impl Files {
match self.files.get(&file_id) {
Some(text) => *text,
None => {
- panic!("Unable to fetch file text for `vfs::FileId`: {:?}; this is a bug", file_id)
+ panic!("Unable to fetch file text for `vfs::FileId`: {file_id:?}; this is a bug")
}
}
}
@@ -101,8 +101,7 @@ impl Files {
let source_root = match self.source_roots.get(&source_root_id) {
Some(source_root) => source_root,
None => panic!(
- "Unable to fetch `SourceRootInput` with `SourceRootId` ({:?}); this is a bug",
- source_root_id
+ "Unable to fetch `SourceRootInput` with `SourceRootId` ({source_root_id:?}); this is a bug"
),
};
@@ -132,8 +131,7 @@ impl Files {
let file_source_root = match self.file_source_roots.get(&id) {
Some(file_source_root) => file_source_root,
None => panic!(
- "Unable to get `FileSourceRootInput` with `vfs::FileId` ({:?}); this is a bug",
- id
+ "Unable to get `FileSourceRootInput` with `vfs::FileId` ({id:?}); this is a bug",
),
};
*file_source_root
@@ -384,3 +382,51 @@ fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> {
let source_root = db.file_source_root(file_id);
db.source_root_crates(source_root.source_root_id(db))
}
+
+#[must_use]
+pub struct DbPanicContext {
+ // prevent arbitrary construction
+ _priv: (),
+}
+
+impl Drop for DbPanicContext {
+ fn drop(&mut self) {
+ Self::with_ctx(|ctx| assert!(ctx.pop().is_some()));
+ }
+}
+
+impl DbPanicContext {
+ pub fn enter(frame: String) -> DbPanicContext {
+ #[expect(clippy::print_stderr, reason = "already panicking anyway")]
+ fn set_hook() {
+ let default_hook = panic::take_hook();
+ panic::set_hook(Box::new(move |panic_info| {
+ DbPanicContext::with_ctx(|ctx| {
+ if !ctx.is_empty() {
+ eprintln!("Panic context:");
+ for frame in ctx.iter() {
+ eprintln!("> {frame}\n");
+ }
+ }
+ });
+ if let Some(backtrace) = salsa::Backtrace::capture() {
+ eprintln!("{backtrace}");
+ }
+ default_hook(panic_info);
+ }));
+ }
+
+ static SET_HOOK: Once = Once::new();
+ SET_HOOK.call_once(set_hook);
+
+ Self::with_ctx(|ctx| ctx.push(frame));
+ DbPanicContext { _priv: () }
+ }
+
+ fn with_ctx(f: impl FnOnce(&mut Vec<String>)) {
+ thread_local! {
+ static CTX: RefCell<Vec<String>> = const { RefCell::new(Vec::new()) };
+ }
+ CTX.with(|ctx| f(&mut ctx.borrow_mut()));
+ }
+}