From df3c7a73b507b585c158e9a21c141077cfff06a2 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 8 Apr 2025 02:30:21 +0200 Subject: [PATCH] debugger: Pick best candidate binary for debugging cargo-located tasks (#28289) Closes #ISSUE Release Notes: - N/A --- .../src/debugger/locator_store/cargo.rs | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/crates/project/src/debugger/locator_store/cargo.rs b/crates/project/src/debugger/locator_store/cargo.rs index 4a958d56e0635bfd6df5c99846c41c47bf8aef81..7ec1898b3a35c3e3ee0d2b12d9282de2fbb9297b 100644 --- a/crates/project/src/debugger/locator_store/cargo.rs +++ b/crates/project/src/debugger/locator_store/cargo.rs @@ -11,6 +11,31 @@ use util::maybe; pub(super) struct CargoLocator; +async fn find_best_executable(executables: &[String], test_name: &str) -> Option { + if executables.len() == 1 { + return executables.first().cloned(); + } + for executable in executables { + let Some(mut child) = Command::new(&executable) + .arg("--list") + .stdout(Stdio::piped()) + .spawn() + .ok() + else { + continue; + }; + let mut test_lines = String::default(); + if let Some(mut stdout) = child.stdout.take() { + stdout.read_to_string(&mut test_lines).await.ok(); + for line in test_lines.lines() { + if line.contains(&test_name) { + return Some(executable.clone()); + } + } + } + } + None +} #[async_trait] impl DapLocator for CargoLocator { async fn run_locator(&self, debug_config: &mut DebugAdapterConfig) -> Result<()> { @@ -46,27 +71,27 @@ impl DapLocator for CargoLocator { return Err(anyhow::anyhow!("Cargo command failed")); } - let Some(executable) = output + let executables = output .lines() .filter(|line| !line.trim().is_empty()) .filter_map(|line| serde_json::from_str(line).ok()) - .find_map(|json: Value| { + .filter_map(|json: Value| { json.get("executable") .and_then(Value::as_str) .map(String::from) }) - else { + .collect::>(); + if executables.is_empty() { return Err(anyhow!("Couldn't get executable in cargo locator")); }; - launch_config.program = executable; - let mut test_name = None; - - if launch_config + let is_test = launch_config .args .first() - .map_or(false, |arg| arg == "test") - { + .map_or(false, |arg| arg == "test"); + + let mut test_name = None; + if is_test { if let Some(package_index) = launch_config .args .iter() @@ -79,6 +104,18 @@ impl DapLocator for CargoLocator { .cloned(); } } + let executable = { + if let Some(ref name) = test_name { + find_best_executable(&executables, &name).await + } else { + None + } + }; + let Some(executable) = executable.or_else(|| executables.first().cloned()) else { + return Err(anyhow!("Couldn't get executable in cargo locator")); + }; + + launch_config.program = executable; if debug_config.adapter == "LLDB" && debug_config.initialize_args.is_none() { // Find Rust pretty-printers in current toolchain's sysroot