Skip to content

Commit f61964c

Browse files
committed
refactor: Define a TargetSpec wrapper type
1 parent b0041b4 commit f61964c

File tree

5 files changed

+88
-72
lines changed

5 files changed

+88
-72
lines changed

crates/rust-analyzer/src/global_state.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use parking_lot::{
1818
RwLockWriteGuard,
1919
};
2020
use proc_macro_api::ProcMacroServer;
21-
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
21+
use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
2222
use rustc_hash::{FxHashMap, FxHashSet};
2323
use triomphe::Arc;
2424
use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
@@ -33,6 +33,7 @@ use crate::{
3333
mem_docs::MemDocs,
3434
op_queue::OpQueue,
3535
reload,
36+
target_spec::{CargoTargetSpec, TargetSpec},
3637
task_pool::{TaskPool, TaskQueue},
3738
};
3839

@@ -502,20 +503,38 @@ impl GlobalStateSnapshot {
502503
self.vfs_read().file_path(file_id).clone()
503504
}
504505

505-
pub(crate) fn cargo_target_for_crate_root(
506-
&self,
507-
crate_id: CrateId,
508-
) -> Option<(&CargoWorkspace, Target)> {
506+
pub(crate) fn target_spec_for_crate(&self, crate_id: CrateId) -> Option<TargetSpec> {
509507
let file_id = self.analysis.crate_root(crate_id).ok()?;
510508
let path = self.vfs_read().file_path(file_id).clone();
511509
let path = path.as_path()?;
512-
self.workspaces.iter().find_map(|ws| match ws {
513-
ProjectWorkspace::Cargo { cargo, .. } => {
514-
cargo.target_by_root(path).map(|it| (cargo, it))
510+
511+
for workspace in self.workspaces.iter() {
512+
match workspace {
513+
ProjectWorkspace::Cargo { cargo, .. } => {
514+
let Some(target_idx) = cargo.target_by_root(path) else {
515+
continue;
516+
};
517+
518+
let target_data = &cargo[target_idx];
519+
let package_data = &cargo[target_data.package];
520+
521+
return Some(TargetSpec::Cargo(CargoTargetSpec {
522+
workspace_root: cargo.workspace_root().to_path_buf(),
523+
cargo_toml: package_data.manifest.clone(),
524+
crate_id,
525+
package: cargo.package_flag(package_data),
526+
target: target_data.name.clone(),
527+
target_kind: target_data.kind,
528+
required_features: target_data.required_features.clone(),
529+
features: package_data.features.keys().cloned().collect(),
530+
}));
531+
}
532+
ProjectWorkspace::Json { .. } => {}
533+
ProjectWorkspace::DetachedFiles { .. } => {}
515534
}
516-
ProjectWorkspace::Json { .. } => None,
517-
ProjectWorkspace::DetachedFiles { .. } => None,
518-
})
535+
}
536+
537+
None
519538
}
520539

521540
pub(crate) fn file_exists(&self, file_id: FileId) -> bool {

crates/rust-analyzer/src/handlers/request.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use triomphe::Arc;
3535
use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
3636

3737
use crate::{
38-
cargo_target_spec::CargoTargetSpec,
3938
config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
4039
diff::diff,
4140
global_state::{GlobalState, GlobalStateSnapshot},
@@ -50,6 +49,7 @@ use crate::{
5049
self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
5150
FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
5251
},
52+
target_spec::TargetSpec,
5353
};
5454

5555
pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
@@ -771,8 +771,8 @@ pub(crate) fn handle_parent_module(
771771
Some(&crate_id) => crate_id,
772772
None => return Ok(None),
773773
};
774-
let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
775-
Some(it) => it,
774+
let cargo_spec = match TargetSpec::for_file(&snap, file_id)? {
775+
Some(TargetSpec::Cargo(it)) => it,
776776
None => return Ok(None),
777777
};
778778

@@ -804,7 +804,7 @@ pub(crate) fn handle_runnables(
804804
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
805805
let line_index = snap.file_line_index(file_id)?;
806806
let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
807-
let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
807+
let target_spec = TargetSpec::for_file(&snap, file_id)?;
808808

809809
let expect_test = match offset {
810810
Some(offset) => {
@@ -821,7 +821,7 @@ pub(crate) fn handle_runnables(
821821
if should_skip_for_offset(&runnable, offset) {
822822
continue;
823823
}
824-
if should_skip_target(&runnable, cargo_spec.as_ref()) {
824+
if should_skip_target(&runnable, target_spec.as_ref()) {
825825
continue;
826826
}
827827
let mut runnable = to_proto::runnable(&snap, runnable)?;
@@ -834,8 +834,8 @@ pub(crate) fn handle_runnables(
834834

835835
// Add `cargo check` and `cargo test` for all targets of the whole package
836836
let config = snap.config.runnables();
837-
match cargo_spec {
838-
Some(spec) => {
837+
match target_spec {
838+
Some(TargetSpec::Cargo(spec)) => {
839839
let all_targets = !snap.analysis.is_crate_no_std(spec.crate_id)?;
840840
for cmd in ["check", "test"] {
841841
let mut cargo_args =
@@ -1351,14 +1351,14 @@ pub(crate) fn handle_code_lens(
13511351
}
13521352

13531353
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
1354-
let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?;
1354+
let target_spec = TargetSpec::for_file(&snap, file_id)?;
13551355

13561356
let annotations = snap.analysis.annotations(
13571357
&AnnotationConfig {
1358-
binary_target: cargo_target_spec
1358+
binary_target: target_spec
13591359
.map(|spec| {
13601360
matches!(
1361-
spec.target_kind,
1361+
spec.target_kind(),
13621362
TargetKind::Bin | TargetKind::Example | TargetKind::Test
13631363
)
13641364
})
@@ -1765,8 +1765,8 @@ pub(crate) fn handle_open_cargo_toml(
17651765
let _p = tracing::span!(tracing::Level::INFO, "handle_open_cargo_toml").entered();
17661766
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
17671767

1768-
let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
1769-
Some(it) => it,
1768+
let cargo_spec = match TargetSpec::for_file(&snap, file_id)? {
1769+
Some(TargetSpec::Cargo(it)) => it,
17701770
None => return Ok(None),
17711771
};
17721772

@@ -1895,8 +1895,8 @@ fn runnable_action_links(
18951895
return None;
18961896
}
18971897

1898-
let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
1899-
if should_skip_target(&runnable, cargo_spec.as_ref()) {
1898+
let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
1899+
if should_skip_target(&runnable, target_spec.as_ref()) {
19001900
return None;
19011901
}
19021902

@@ -1961,13 +1961,13 @@ fn prepare_hover_actions(
19611961
.collect()
19621962
}
19631963

1964-
fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool {
1964+
fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&TargetSpec>) -> bool {
19651965
match runnable.kind {
19661966
RunnableKind::Bin => {
19671967
// Do not suggest binary run on other target than binary
19681968
match &cargo_spec {
19691969
Some(spec) => !matches!(
1970-
spec.target_kind,
1970+
spec.target_kind(),
19711971
TargetKind::Bin | TargetKind::Example | TargetKind::Test
19721972
),
19731973
None => true,
@@ -2044,9 +2044,9 @@ fn run_rustfmt(
20442044
}
20452045
RustfmtConfig::CustomCommand { command, args } => {
20462046
let cmd = Utf8PathBuf::from(&command);
2047-
let workspace = CargoTargetSpec::for_file(snap, file_id)?;
2048-
let mut cmd = match workspace {
2049-
Some(spec) => {
2047+
let target_spec = TargetSpec::for_file(snap, file_id)?;
2048+
let mut cmd = match target_spec {
2049+
Some(TargetSpec::Cargo(spec)) => {
20502050
// approach: if the command name contains a path separator, join it with the workspace root.
20512051
// however, if the path is absolute, joining will result in the absolute path being preserved.
20522052
// as a fallback, rely on $PATH-based discovery.

crates/rust-analyzer/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
pub mod cli;
1515

1616
mod caps;
17-
mod cargo_target_spec;
1817
mod diagnostics;
1918
mod diff;
2019
mod dispatch;
@@ -25,6 +24,7 @@ mod main_loop;
2524
mod mem_docs;
2625
mod op_queue;
2726
mod reload;
27+
mod target_spec;
2828
mod task_pool;
2929
mod version;
3030

crates/rust-analyzer/src/lsp/to_proto.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use serde_json::to_value;
2121
use vfs::AbsPath;
2222

2323
use crate::{
24-
cargo_target_spec::CargoTargetSpec,
2524
config::{CallInfoConfig, Config},
2625
global_state::GlobalStateSnapshot,
2726
line_index::{LineEndings, LineIndex, PositionEncoding},
@@ -31,6 +30,7 @@ use crate::{
3130
LspError,
3231
},
3332
lsp_ext::{self, SnippetTextEdit},
33+
target_spec::{CargoTargetSpec, TargetSpec},
3434
};
3535

3636
pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
@@ -1347,10 +1347,10 @@ pub(crate) fn runnable(
13471347
runnable: Runnable,
13481348
) -> Cancellable<lsp_ext::Runnable> {
13491349
let config = snap.config.runnables();
1350-
let target_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id)?;
1350+
let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id)?;
13511351

13521352
match target_spec {
1353-
Some(spec) => {
1353+
Some(TargetSpec::Cargo(spec)) => {
13541354
let workspace_root = spec.workspace_root.clone();
13551355
let target = spec.target.clone();
13561356

@@ -1549,12 +1549,8 @@ pub(crate) fn test_item(
15491549
id: test_item.id,
15501550
label: test_item.label,
15511551
kind: match test_item.kind {
1552-
ide::TestItemKind::Crate(id) => 'b: {
1553-
let Some((cargo_ws, target)) = snap.cargo_target_for_crate_root(id) else {
1554-
break 'b lsp_ext::TestItemKind::Package;
1555-
};
1556-
let target = &cargo_ws[target];
1557-
match target.kind {
1552+
ide::TestItemKind::Crate(id) => match snap.target_spec_for_crate(id) {
1553+
Some(target_spec) => match target_spec.target_kind() {
15581554
project_model::TargetKind::Bin
15591555
| project_model::TargetKind::Lib { .. }
15601556
| project_model::TargetKind::Example
@@ -1563,8 +1559,9 @@ pub(crate) fn test_item(
15631559
project_model::TargetKind::Test => lsp_ext::TestItemKind::Test,
15641560
// benches are not tests needed to be shown in the test explorer
15651561
project_model::TargetKind::Bench => return None,
1566-
}
1567-
}
1562+
},
1563+
None => lsp_ext::TestItemKind::Package,
1564+
},
15681565
ide::TestItemKind::Module => lsp_ext::TestItemKind::Module,
15691566
ide::TestItemKind::Function => lsp_ext::TestItemKind::Test,
15701567
},

crates/rust-analyzer/src/cargo_target_spec.rs renamed to crates/rust-analyzer/src/target_spec.rs

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! See `CargoTargetSpec`
1+
//! See `TargetSpec`
22
33
use std::mem;
44

@@ -10,6 +10,35 @@ use vfs::AbsPathBuf;
1010

1111
use crate::global_state::GlobalStateSnapshot;
1212

13+
/// A target represents a thing we can build or test.
14+
///
15+
/// We use it to calculate the CLI arguments required to build, run or
16+
/// test the target.
17+
#[derive(Clone)]
18+
pub(crate) enum TargetSpec {
19+
Cargo(CargoTargetSpec),
20+
}
21+
22+
impl TargetSpec {
23+
pub(crate) fn for_file(
24+
global_state_snapshot: &GlobalStateSnapshot,
25+
file_id: FileId,
26+
) -> Cancellable<Option<Self>> {
27+
let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
28+
&[crate_id, ..] => crate_id,
29+
_ => return Ok(None),
30+
};
31+
32+
Ok(global_state_snapshot.target_spec_for_crate(crate_id))
33+
}
34+
35+
pub(crate) fn target_kind(&self) -> TargetKind {
36+
match self {
37+
TargetSpec::Cargo(cargo) => cargo.target_kind,
38+
}
39+
}
40+
}
41+
1342
/// Abstract representation of Cargo target.
1443
///
1544
/// We use it to cook up the set of cli args we need to pass to Cargo to
@@ -120,35 +149,6 @@ impl CargoTargetSpec {
120149
(args, extra_args)
121150
}
122151

123-
pub(crate) fn for_file(
124-
global_state_snapshot: &GlobalStateSnapshot,
125-
file_id: FileId,
126-
) -> Cancellable<Option<CargoTargetSpec>> {
127-
let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
128-
&[crate_id, ..] => crate_id,
129-
_ => return Ok(None),
130-
};
131-
let (cargo_ws, target) = match global_state_snapshot.cargo_target_for_crate_root(crate_id) {
132-
Some(it) => it,
133-
None => return Ok(None),
134-
};
135-
136-
let target_data = &cargo_ws[target];
137-
let package_data = &cargo_ws[target_data.package];
138-
let res = CargoTargetSpec {
139-
workspace_root: cargo_ws.workspace_root().to_path_buf(),
140-
cargo_toml: package_data.manifest.clone(),
141-
package: cargo_ws.package_flag(package_data),
142-
target: target_data.name.clone(),
143-
target_kind: target_data.kind,
144-
required_features: target_data.required_features.clone(),
145-
features: package_data.features.keys().cloned().collect(),
146-
crate_id,
147-
};
148-
149-
Ok(Some(res))
150-
}
151-
152152
pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
153153
buf.push("--package".to_owned());
154154
buf.push(self.package);

0 commit comments

Comments
 (0)