Skip to content

Commit 841d4f9

Browse files
committed
Only include targets of packages that are workspace members
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
1 parent 098284a commit 841d4f9

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

crates/project_model/src/cargo_workspace.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ pub struct PackageData {
137137
pub targets: Vec<Target>,
138138
/// Does this package come from the local filesystem (and is editable)?
139139
pub is_local: bool,
140+
// Whether this package is a member of the workspace
141+
pub is_member: bool,
140142
/// List of packages this package depends on
141143
pub dependencies: Vec<PackageDependency>,
142144
/// Rust edition for this package
@@ -296,6 +298,8 @@ impl CargoWorkspace {
296298
let mut packages = Arena::default();
297299
let mut targets = Arena::default();
298300

301+
let ws_members = &meta.workspace_members;
302+
299303
meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
300304
for meta_pkg in &meta.packages {
301305
let cargo_metadata::Package {
@@ -309,6 +313,7 @@ impl CargoWorkspace {
309313
// We treat packages without source as "local" packages. That includes all members of
310314
// the current workspace, as well as any path dependency outside the workspace.
311315
let is_local = meta_pkg.source.is_none();
316+
let is_member = ws_members.contains(id);
312317

313318
let pkg = packages.alloc(PackageData {
314319
id: id.repr.clone(),
@@ -317,6 +322,7 @@ impl CargoWorkspace {
317322
manifest: AbsPathBuf::assert(PathBuf::from(&manifest_path)).try_into().unwrap(),
318323
targets: Vec::new(),
319324
is_local,
325+
is_member,
320326
edition,
321327
dependencies: Vec::new(),
322328
features: meta_pkg.features.clone().into_iter().collect(),
@@ -383,8 +389,8 @@ impl CargoWorkspace {
383389

384390
pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
385391
self.packages()
386-
.filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
387-
.next()
392+
.filter(|&pkg| self[pkg].is_member)
393+
.find_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
388394
.copied()
389395
}
390396

crates/rust-analyzer/tests/slow-tests/main.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,93 @@ fn main() {}
202202
);
203203
}
204204

205+
// Each package in these workspaces should be run from its own root
206+
#[test]
207+
fn test_path_dependency_runnables() {
208+
if skip_slow_tests() {
209+
return;
210+
}
211+
212+
let server = Project::with_fixture(
213+
r#"
214+
//- /consumer/Cargo.toml
215+
[package]
216+
name = "consumer"
217+
version = "0.1.0"
218+
[dependencies]
219+
dependency = { path = "../dependency" }
220+
221+
//- /consumer/src/lib.rs
222+
#[cfg(test)]
223+
mod tests {
224+
#[test]
225+
fn consumer() {}
226+
}
227+
228+
//- /dependency/Cargo.toml
229+
[package]
230+
name = "dependency"
231+
version = "0.1.0"
232+
[dev-dependencies]
233+
devdependency = { path = "../devdependency" }
234+
235+
//- /dependency/src/lib.rs
236+
#[cfg(test)]
237+
mod tests {
238+
#[test]
239+
fn dependency() {}
240+
}
241+
242+
//- /devdependency/Cargo.toml
243+
[package]
244+
name = "devdependency"
245+
version = "0.1.0"
246+
247+
//- /devdependency/src/lib.rs
248+
#[cfg(test)]
249+
mod tests {
250+
#[test]
251+
fn devdependency() {}
252+
}
253+
"#,
254+
)
255+
.root("consumer")
256+
.root("dependency")
257+
.root("devdependency")
258+
.server()
259+
.wait_until_workspace_is_loaded();
260+
261+
for runnable in ["consumer", "dependency", "devdependency"] {
262+
server.request::<Runnables>(
263+
RunnablesParams {
264+
text_document: server.doc_id(&format!("{}/src/lib.rs", runnable)),
265+
position: None,
266+
},
267+
json!([
268+
"{...}",
269+
{
270+
"label": "cargo test -p [..] --all-targets",
271+
"kind": "cargo",
272+
"args": {
273+
"overrideCargo": null,
274+
"workspaceRoot": server.path().join(runnable),
275+
"cargoArgs": [
276+
"test",
277+
"--package",
278+
runnable,
279+
"--all-targets"
280+
],
281+
"cargoExtraArgs": [],
282+
"executableArgs": []
283+
},
284+
},
285+
"{...}",
286+
"{...}"
287+
]),
288+
);
289+
}
290+
}
291+
205292
#[test]
206293
fn test_format_document() {
207294
if skip_slow_tests() {

0 commit comments

Comments
 (0)