Unnamed repository; edit this file 'description' to name the repository.
Merge #10503
10503: Only include targets of packages that are workspace members r=Veykril a=bcully CargoWorkspace's package list includes packages that are path dependencies, even if those packages aren't actually members of the cargo workspace. As a result, rust-analyzer's runnable finder, which returns the target from the first workspace that has a matching package, may select the wrong working directory, causing runnables to fail, e.g., ``` error: package `root` cannot be tested because it requires dev-dependencies and is not a member of the workspace ``` To fix this, we filter out packages that aren't members of the workspace when searching for targets. Fixes #7764 Co-authored-by: Brendan Cully <[email protected]>
bors[bot] 2021-10-14
parent f87debc · parent 841d4f9 · commit c535487
-rw-r--r--crates/project_model/src/cargo_workspace.rs10
-rw-r--r--crates/rust-analyzer/tests/slow-tests/main.rs87
2 files changed, 95 insertions, 2 deletions
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index a55901a8f7..739f29b014 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -137,6 +137,8 @@ pub struct PackageData {
pub targets: Vec<Target>,
/// Does this package come from the local filesystem (and is editable)?
pub is_local: bool,
+ // Whether this package is a member of the workspace
+ pub is_member: bool,
/// List of packages this package depends on
pub dependencies: Vec<PackageDependency>,
/// Rust edition for this package
@@ -296,6 +298,8 @@ impl CargoWorkspace {
let mut packages = Arena::default();
let mut targets = Arena::default();
+ let ws_members = &meta.workspace_members;
+
meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
for meta_pkg in &meta.packages {
let cargo_metadata::Package {
@@ -309,6 +313,7 @@ impl CargoWorkspace {
// We treat packages without source as "local" packages. That includes all members of
// the current workspace, as well as any path dependency outside the workspace.
let is_local = meta_pkg.source.is_none();
+ let is_member = ws_members.contains(id);
let pkg = packages.alloc(PackageData {
id: id.repr.clone(),
@@ -317,6 +322,7 @@ impl CargoWorkspace {
manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)).try_into().unwrap(),
targets: Vec::new(),
is_local,
+ is_member,
edition,
dependencies: Vec::new(),
features: meta_pkg.features.clone().into_iter().collect(),
@@ -383,8 +389,8 @@ impl CargoWorkspace {
pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
self.packages()
- .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
- .next()
+ .filter(|&pkg| self[pkg].is_member)
+ .find_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
.copied()
}
diff --git a/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index f92902e2e7..9eb8ad1b72 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -202,6 +202,93 @@ fn main() {}
);
}
+// Each package in these workspaces should be run from its own root
+#[test]
+fn test_path_dependency_runnables() {
+ if skip_slow_tests() {
+ return;
+ }
+
+ let server = Project::with_fixture(
+ r#"
+//- /consumer/Cargo.toml
+[package]
+name = "consumer"
+version = "0.1.0"
+[dependencies]
+dependency = { path = "../dependency" }
+
+//- /consumer/src/lib.rs
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn consumer() {}
+}
+
+//- /dependency/Cargo.toml
+[package]
+name = "dependency"
+version = "0.1.0"
+[dev-dependencies]
+devdependency = { path = "../devdependency" }
+
+//- /dependency/src/lib.rs
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn dependency() {}
+}
+
+//- /devdependency/Cargo.toml
+[package]
+name = "devdependency"
+version = "0.1.0"
+
+//- /devdependency/src/lib.rs
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn devdependency() {}
+}
+ "#,
+ )
+ .root("consumer")
+ .root("dependency")
+ .root("devdependency")
+ .server()
+ .wait_until_workspace_is_loaded();
+
+ for runnable in ["consumer", "dependency", "devdependency"] {
+ server.request::<Runnables>(
+ RunnablesParams {
+ text_document: server.doc_id(&format!("{}/src/lib.rs", runnable)),
+ position: None,
+ },
+ json!([
+ "{...}",
+ {
+ "label": "cargo test -p [..] --all-targets",
+ "kind": "cargo",
+ "args": {
+ "overrideCargo": null,
+ "workspaceRoot": server.path().join(runnable),
+ "cargoArgs": [
+ "test",
+ "--package",
+ runnable,
+ "--all-targets"
+ ],
+ "cargoExtraArgs": [],
+ "executableArgs": []
+ },
+ },
+ "{...}",
+ "{...}"
+ ]),
+ );
+ }
+}
+
#[test]
fn test_format_document() {
if skip_slow_tests() {