]> git.lizzy.rs Git - rust.git/commitdiff
Only include targets of packages that are workspace members
authorBrendan Cully <brendan@cully.org>
Sun, 10 Oct 2021 02:49:34 +0000 (19:49 -0700)
committerBrendan Cully <brendan@cully.org>
Tue, 12 Oct 2021 01:28:05 +0000 (18:28 -0700)
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

crates/project_model/src/cargo_workspace.rs
crates/rust-analyzer/tests/slow-tests/main.rs

index 1417ac2fa1d1b0f357768b8175d1a7ead90f8730..dccdf1d431a3bb6ddcea63bcdac6524ae91796a9 100644 (file)
@@ -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 @@ pub fn new(mut meta: cargo_metadata::Metadata) -> 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 @@ pub fn new(mut meta: cargo_metadata::Metadata) -> 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 @@ pub fn new(mut meta: cargo_metadata::Metadata) -> 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 @@ pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterat
 
     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()
     }
 
index f92902e2e74f837acf59618dd07a3ec45546e55d..9eb8ad1b720f4374d61d438c7a4cad6f20b45f72 100644 (file)
@@ -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() {