Skip to content

in debug, include location information in error message on panic #926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions godot-core/src/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,27 +387,39 @@ where
// Handle panic info only in Debug mode.
#[cfg(debug_assertions)]
{
let guard = info.lock().unwrap();
let info = guard.as_ref().expect("no panic info available");
let msg = extract_panic_message(err);
let mut msg = format_panic_message(msg);

// Try to add location information.
if let Ok(guard) = info.lock() {
if let Some(info) = guard.as_ref() {
msg = format!("{}\n at {}:{}", msg, info.file, info.line);
}
}

if print {
godot_error!(
"Rust function panicked at {}:{}.\n Context: {}",
info.file,
info.line,
"Rust function panicked: {}\n Context: {}",
msg,
error_context()
);
//eprintln!("Backtrace:\n{}", info.backtrace);
}

Err(msg)
}

let msg = extract_panic_message(err);
let msg = format_panic_message(msg);
#[cfg(not(debug_assertions))]
{
let msg = extract_panic_message(err);
let msg = format_panic_message(msg);

if print {
godot_error!("{msg}");
}

if print {
godot_error!("{msg}");
Err(msg)
}

Err(msg)
}
}
}
Expand Down
23 changes: 20 additions & 3 deletions itest/rust/src/object_tests/dynamic_call_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,30 @@ fn dynamic_call_with_panic() {

assert_eq!(call_error.class_name(), Some("Object"));
assert_eq!(call_error.method_name(), "call");
assert_eq!(
call_error.to_string(),

let appendix = if cfg!(debug_assertions) {
let mut path = "itest/rust/src/object_tests/object_test.rs".to_string();

if cfg!(target_os = "windows") {
path = path.replace('/', "\\")
}

// Obtain line number dynamically, avoids tedious maintenance on code reorganization.
let line = ObjPayload::get_panic_line();

format!("\n at {path}:{line}")
} else {
String::new()
};

let expected_error_message = format!(
"godot-rust function call failed: Object::call(&\"do_panic\")\
\n Source: ObjPayload::do_panic()\
\n Reason: [panic] do_panic exploded"
\n Reason: [panic] do_panic exploded{appendix}"
);

assert_eq!(call_error.to_string(), expected_error_message);

obj.free();
}

Expand Down
5 changes: 5 additions & 0 deletions itest/rust/src/object_tests/object_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,11 @@ impl ObjPayload {
fn do_panic(&self) {
panic!("do_panic exploded");
}

// Obtain the line number of the panic!() call above; keep equidistant to do_panic() method.
pub fn get_panic_line() -> u32 {
line!() - 5
}
}

// ----------------------------------------------------------------------------------------------------------------------------------------------
Expand Down
Loading