From 4cc06bfb4ef22095c845f05d88579b1e96ed666c Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 2 Jul 2025 19:36:35 +0200 Subject: [PATCH] debugger: Fix wrong cwd in Rust tests (#33788) This commit introduces a new task variable RUST_MANIFEST_DIRNAME which points at the parent directory of the manifest for the current package. Previously we were running `cargo test` inside of parent dir of a currently focused source file, which happened to work with non-debug stuff (as `cargo test` itself fixed cwd for us), but that no longer works with debug scenarios - they are compiled separately and so we no longer have cargo doing the heavy lifting for us Co-authored-by: Remco Smits Co-authored-by: Anthony Eid Closes #33751 Release Notes: - debugger: Fixed wrong cwd in automatically-generated Rust test debug sessions Co-authored-by: Remco Smits Co-authored-by: Anthony Eid --- crates/languages/src/rust.rs | 164 +++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 56 deletions(-) diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs index c4edec1f29..3f83c9c000 100644 --- a/crates/languages/src/rust.rs +++ b/crates/languages/src/rust.rs @@ -571,6 +571,9 @@ const RUST_DOC_TEST_NAME_TASK_VARIABLE: VariableName = const RUST_TEST_NAME_TASK_VARIABLE: VariableName = VariableName::Custom(Cow::Borrowed("RUST_TEST_NAME")); +const RUST_MANIFEST_DIRNAME_TASK_VARIABLE: VariableName = + VariableName::Custom(Cow::Borrowed("RUST_MANIFEST_DIRNAME")); + impl ContextProvider for RustContextProvider { fn build_context( &self, @@ -615,8 +618,11 @@ impl ContextProvider for RustContextProvider { variables.insert(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name); } } - if let Some(path) = local_abs_path.as_ref() { - if let Some(target) = target_info_from_abs_path(&path, project_env.as_ref()).await { + if let Some(path) = local_abs_path.as_ref() + && let Some((target, manifest_path)) = + target_info_from_abs_path(&path, project_env.as_ref()).await + { + if let Some(target) = target { variables.extend(TaskVariables::from_iter([ (RUST_PACKAGE_TASK_VARIABLE.clone(), target.package_name), (RUST_BIN_NAME_TASK_VARIABLE.clone(), target.target_name), @@ -639,6 +645,10 @@ impl ContextProvider for RustContextProvider { ); } } + variables.extend(TaskVariables::from_iter([( + RUST_MANIFEST_DIRNAME_TASK_VARIABLE.clone(), + manifest_path.to_string_lossy().into_owned(), + )])); } Ok(variables) }) @@ -708,7 +718,7 @@ impl ContextProvider for RustContextProvider { RUST_TEST_NAME_TASK_VARIABLE.template_value(), ], tags: vec!["rust-test".to_owned()], - cwd: Some("$ZED_DIRNAME".to_owned()), + cwd: Some(RUST_MANIFEST_DIRNAME_TASK_VARIABLE.template_value()), ..TaskTemplate::default() }, TaskTemplate { @@ -729,7 +739,7 @@ impl ContextProvider for RustContextProvider { RUST_DOC_TEST_NAME_TASK_VARIABLE.template_value(), ], tags: vec!["rust-doc-test".to_owned()], - cwd: Some("$ZED_DIRNAME".to_owned()), + cwd: Some(RUST_MANIFEST_DIRNAME_TASK_VARIABLE.template_value()), ..TaskTemplate::default() }, TaskTemplate { @@ -747,7 +757,7 @@ impl ContextProvider for RustContextProvider { RUST_TEST_FRAGMENT_TASK_VARIABLE.template_value(), ], tags: vec!["rust-mod-test".to_owned()], - cwd: Some("$ZED_DIRNAME".to_owned()), + cwd: Some(RUST_MANIFEST_DIRNAME_TASK_VARIABLE.template_value()), ..TaskTemplate::default() }, TaskTemplate { @@ -782,7 +792,7 @@ impl ContextProvider for RustContextProvider { "-p".into(), RUST_PACKAGE_TASK_VARIABLE.template_value(), ], - cwd: Some("$ZED_DIRNAME".to_owned()), + cwd: Some(RUST_MANIFEST_DIRNAME_TASK_VARIABLE.template_value()), ..TaskTemplate::default() }, TaskTemplate { @@ -826,18 +836,19 @@ impl ContextProvider for RustContextProvider { } /// Part of the data structure of Cargo metadata -#[derive(serde::Deserialize)] +#[derive(Debug, serde::Deserialize)] struct CargoMetadata { packages: Vec, } -#[derive(serde::Deserialize)] +#[derive(Debug, serde::Deserialize)] struct CargoPackage { id: String, targets: Vec, + manifest_path: Arc, } -#[derive(serde::Deserialize)] +#[derive(Debug, serde::Deserialize)] struct CargoTarget { name: String, kind: Vec, @@ -883,7 +894,7 @@ struct TargetInfo { async fn target_info_from_abs_path( abs_path: &Path, project_env: Option<&HashMap>, -) -> Option { +) -> Option<(Option, Arc)> { let mut command = util::command::new_smol_command("cargo"); if let Some(envs) = project_env { command.envs(envs); @@ -900,12 +911,33 @@ async fn target_info_from_abs_path( .stdout; let metadata: CargoMetadata = serde_json::from_slice(&output).log_err()?; - target_info_from_metadata(metadata, abs_path) } -fn target_info_from_metadata(metadata: CargoMetadata, abs_path: &Path) -> Option { +fn target_info_from_metadata( + metadata: CargoMetadata, + abs_path: &Path, +) -> Option<(Option, Arc)> { + let mut manifest_path = None; for package in metadata.packages { + let Some(manifest_dir_path) = package.manifest_path.parent() else { + continue; + }; + + let Some(path_from_manifest_dir) = abs_path.strip_prefix(manifest_dir_path).ok() else { + continue; + }; + let candidate_path_length = path_from_manifest_dir.components().count(); + // Pick the most specific manifest path + if let Some((path, current_length)) = &mut manifest_path { + if candidate_path_length > *current_length { + *path = Arc::from(manifest_dir_path); + *current_length = candidate_path_length; + } + } else { + manifest_path = Some((Arc::from(manifest_dir_path), candidate_path_length)); + }; + for target in package.targets { let Some(bin_kind) = target .kind @@ -916,17 +948,22 @@ fn target_info_from_metadata(metadata: CargoMetadata, abs_path: &Path) -> Option }; let target_path = PathBuf::from(target.src_path); if target_path == abs_path { - return package_name_from_pkgid(&package.id).map(|package_name| TargetInfo { - package_name: package_name.to_owned(), - target_name: target.name, - required_features: target.required_features, - target_kind: bin_kind, + return manifest_path.map(|(path, _)| { + ( + package_name_from_pkgid(&package.id).map(|package_name| TargetInfo { + package_name: package_name.to_owned(), + target_name: target.name, + required_features: target.required_features, + target_kind: bin_kind, + }), + path, + ) }); } } } - None + manifest_path.map(|(path, _)| (None, path)) } async fn human_readable_package_name( @@ -1380,62 +1417,77 @@ mod tests { fn test_target_info_from_metadata() { for (input, absolute_path, expected) in [ ( - r#"{"packages":[{"id":"path+file:///absolute/path/to/project/zed/crates/zed#0.131.0","targets":[{"name":"zed","kind":["bin"],"src_path":"/path/to/zed/src/main.rs"}]}]}"#, + r#"{"packages":[{"id":"path+file:///absolute/path/to/project/zed/crates/zed#0.131.0","manifest_path":"/path/to/zed/Cargo.toml","targets":[{"name":"zed","kind":["bin"],"src_path":"/path/to/zed/src/main.rs"}]}]}"#, "/path/to/zed/src/main.rs", - Some(TargetInfo { - package_name: "zed".into(), - target_name: "zed".into(), - required_features: Vec::new(), - target_kind: TargetKind::Bin, - }), + Some(( + Some(TargetInfo { + package_name: "zed".into(), + target_name: "zed".into(), + required_features: Vec::new(), + target_kind: TargetKind::Bin, + }), + Arc::from("/path/to/zed".as_ref()), + )), ), ( - r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["bin"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#, + r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","manifest_path":"/path/to/custom-package/Cargo.toml","targets":[{"name":"my-custom-bin","kind":["bin"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#, "/path/to/custom-package/src/main.rs", - Some(TargetInfo { - package_name: "my-custom-package".into(), - target_name: "my-custom-bin".into(), - required_features: Vec::new(), - target_kind: TargetKind::Bin, - }), + Some(( + Some(TargetInfo { + package_name: "my-custom-package".into(), + target_name: "my-custom-bin".into(), + required_features: Vec::new(), + target_kind: TargetKind::Bin, + }), + Arc::from("/path/to/custom-package".as_ref()), + )), ), ( - r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#, + r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs"}],"manifest_path":"/path/to/custom-package/Cargo.toml"}]}"#, "/path/to/custom-package/src/main.rs", - Some(TargetInfo { - package_name: "my-custom-package".into(), - target_name: "my-custom-bin".into(), - required_features: Vec::new(), - target_kind: TargetKind::Example, - }), + Some(( + Some(TargetInfo { + package_name: "my-custom-package".into(), + target_name: "my-custom-bin".into(), + required_features: Vec::new(), + target_kind: TargetKind::Example, + }), + Arc::from("/path/to/custom-package".as_ref()), + )), ), ( - r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs","required-features":["foo","bar"]}]}]}"#, + r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","manifest_path":"/path/to/custom-package/Cargo.toml","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs","required-features":["foo","bar"]}]}]}"#, "/path/to/custom-package/src/main.rs", - Some(TargetInfo { - package_name: "my-custom-package".into(), - target_name: "my-custom-bin".into(), - required_features: vec!["foo".to_owned(), "bar".to_owned()], - target_kind: TargetKind::Example, - }), + Some(( + Some(TargetInfo { + package_name: "my-custom-package".into(), + target_name: "my-custom-bin".into(), + required_features: vec!["foo".to_owned(), "bar".to_owned()], + target_kind: TargetKind::Example, + }), + Arc::from("/path/to/custom-package".as_ref()), + )), ), ( - r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs","required-features":[]}]}]}"#, + r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-bin","kind":["example"],"src_path":"/path/to/custom-package/src/main.rs","required-features":[]}],"manifest_path":"/path/to/custom-package/Cargo.toml"}]}"#, "/path/to/custom-package/src/main.rs", - Some(TargetInfo { - package_name: "my-custom-package".into(), - target_name: "my-custom-bin".into(), - required_features: vec![], - target_kind: TargetKind::Example, - }), + Some(( + Some(TargetInfo { + package_name: "my-custom-package".into(), + target_name: "my-custom-bin".into(), + required_features: vec![], + target_kind: TargetKind::Example, + }), + Arc::from("/path/to/custom-package".as_ref()), + )), ), ( - r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-package","kind":["lib"],"src_path":"/path/to/custom-package/src/main.rs"}]}]}"#, + r#"{"packages":[{"id":"path+file:///path/to/custom-package#my-custom-package@0.1.0","targets":[{"name":"my-custom-package","kind":["lib"],"src_path":"/path/to/custom-package/src/main.rs"}],"manifest_path":"/path/to/custom-package/Cargo.toml"}]}"#, "/path/to/custom-package/src/main.rs", - None, + Some((None, Arc::from("/path/to/custom-package".as_ref()))), ), ] { - let metadata: CargoMetadata = serde_json::from_str(input).unwrap(); + let metadata: CargoMetadata = serde_json::from_str(input).context(input).unwrap(); let absolute_path = Path::new(absolute_path);