Skip to content

Commit 44fd708

Browse files
committed
Auto merge of #17912 - alibektas:cargo_check_on_binary, r=Veykril
fix: run flycheck without rev_deps when target is specified Since querying for a crate's target is a call to salsa and therefore blocking, flycheck task is now deferred out of main thread by using `GlobalState`s `deferred_task_queue`. Fixes #17829 and rust-lang/rustlings#2071
2 parents 9b72445 + 03456c5 commit 44fd708

File tree

2 files changed

+69
-22
lines changed

2 files changed

+69
-22
lines changed

crates/rust-analyzer/src/flycheck.rs

+29-10
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ pub(crate) struct CargoOptions {
3434
pub(crate) target_dir: Option<Utf8PathBuf>,
3535
}
3636

37+
#[derive(Clone)]
38+
pub(crate) enum Target {
39+
Bin(String),
40+
Example(String),
41+
Benchmark(String),
42+
Test(String),
43+
}
44+
3745
impl CargoOptions {
3846
pub(crate) fn apply_on_command(&self, cmd: &mut Command) {
3947
for target in &self.target_triples {
@@ -119,13 +127,13 @@ impl FlycheckHandle {
119127

120128
/// Schedule a re-start of the cargo check worker to do a workspace wide check.
121129
pub(crate) fn restart_workspace(&self, saved_file: Option<AbsPathBuf>) {
122-
self.sender.send(StateChange::Restart { package: None, saved_file }).unwrap();
130+
self.sender.send(StateChange::Restart { package: None, saved_file, target: None }).unwrap();
123131
}
124132

125133
/// Schedule a re-start of the cargo check worker to do a package wide check.
126-
pub(crate) fn restart_for_package(&self, package: String) {
134+
pub(crate) fn restart_for_package(&self, package: String, target: Option<Target>) {
127135
self.sender
128-
.send(StateChange::Restart { package: Some(package), saved_file: None })
136+
.send(StateChange::Restart { package: Some(package), saved_file: None, target })
129137
.unwrap();
130138
}
131139

@@ -183,7 +191,7 @@ pub(crate) enum Progress {
183191
}
184192

185193
enum StateChange {
186-
Restart { package: Option<String>, saved_file: Option<AbsPathBuf> },
194+
Restart { package: Option<String>, saved_file: Option<AbsPathBuf>, target: Option<Target> },
187195
Cancel,
188196
}
189197

@@ -271,7 +279,7 @@ impl FlycheckActor {
271279
tracing::debug!(flycheck_id = self.id, "flycheck cancelled");
272280
self.cancel_check_process();
273281
}
274-
Event::RequestStateChange(StateChange::Restart { package, saved_file }) => {
282+
Event::RequestStateChange(StateChange::Restart { package, saved_file, target }) => {
275283
// Cancel the previously spawned process
276284
self.cancel_check_process();
277285
while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
@@ -281,11 +289,12 @@ impl FlycheckActor {
281289
}
282290
}
283291

284-
let command =
285-
match self.check_command(package.as_deref(), saved_file.as_deref()) {
286-
Some(c) => c,
287-
None => continue,
288-
};
292+
let Some(command) =
293+
self.check_command(package.as_deref(), saved_file.as_deref(), target)
294+
else {
295+
continue;
296+
};
297+
289298
let formatted_command = format!("{command:?}");
290299

291300
tracing::debug!(?command, "will restart flycheck");
@@ -381,6 +390,7 @@ impl FlycheckActor {
381390
&self,
382391
package: Option<&str>,
383392
saved_file: Option<&AbsPath>,
393+
target: Option<Target>,
384394
) -> Option<Command> {
385395
match &self.config {
386396
FlycheckConfig::CargoCommand { command, options, ansi_color_output } => {
@@ -396,6 +406,15 @@ impl FlycheckActor {
396406
None => cmd.arg("--workspace"),
397407
};
398408

409+
if let Some(tgt) = target {
410+
match tgt {
411+
Target::Bin(tgt) => cmd.arg("--bin").arg(tgt),
412+
Target::Example(tgt) => cmd.arg("--example").arg(tgt),
413+
Target::Test(tgt) => cmd.arg("--test").arg(tgt),
414+
Target::Benchmark(tgt) => cmd.arg("--bench").arg(tgt),
415+
};
416+
}
417+
399418
cmd.arg(if *ansi_color_output {
400419
"--message-format=json-diagnostic-rendered-ansi"
401420
} else {

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

+40-12
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ use vfs::{AbsPathBuf, ChangeKind, VfsPath};
1515

1616
use crate::{
1717
config::{Config, ConfigChange},
18+
flycheck::Target,
1819
global_state::{FetchWorkspaceRequest, GlobalState},
1920
lsp::{from_proto, utils::apply_document_changes},
2021
lsp_ext::{self, RunFlycheckParams},
2122
mem_docs::DocumentData,
2223
reload,
24+
target_spec::TargetSpec,
2325
};
2426

2527
pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> anyhow::Result<()> {
@@ -287,16 +289,40 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
287289
let world = state.snapshot();
288290
let mut updated = false;
289291
let task = move || -> std::result::Result<(), ide::Cancelled> {
290-
// Trigger flychecks for all workspaces that depend on the saved file
291-
// Crates containing or depending on the saved file
292-
let crate_ids: Vec<_> = world
293-
.analysis
294-
.crates_for(file_id)?
295-
.into_iter()
296-
.flat_map(|id| world.analysis.transitive_rev_deps(id))
297-
.flatten()
298-
.unique()
299-
.collect();
292+
// Is the target binary? If so we let flycheck run only for the workspace that contains the crate.
293+
let target = TargetSpec::for_file(&world, file_id)?.and_then(|x| {
294+
let tgt_kind = x.target_kind();
295+
let tgt_name = match x {
296+
TargetSpec::Cargo(c) => c.target,
297+
TargetSpec::ProjectJson(p) => p.label,
298+
};
299+
300+
let tgt = match tgt_kind {
301+
project_model::TargetKind::Bin => Target::Bin(tgt_name),
302+
project_model::TargetKind::Example => Target::Example(tgt_name),
303+
project_model::TargetKind::Test => Target::Test(tgt_name),
304+
project_model::TargetKind::Bench => Target::Benchmark(tgt_name),
305+
_ => return None,
306+
};
307+
308+
Some(tgt)
309+
});
310+
311+
let crate_ids = if target.is_some() {
312+
// Trigger flychecks for the only workspace which the binary crate belongs to
313+
world.analysis.crates_for(file_id)?.into_iter().unique().collect::<Vec<_>>()
314+
} else {
315+
// Trigger flychecks for all workspaces that depend on the saved file
316+
// Crates containing or depending on the saved file
317+
world
318+
.analysis
319+
.crates_for(file_id)?
320+
.into_iter()
321+
.flat_map(|id| world.analysis.transitive_rev_deps(id))
322+
.flatten()
323+
.unique()
324+
.collect::<Vec<_>>()
325+
};
300326

301327
let crate_root_paths: Vec<_> = crate_ids
302328
.iter()
@@ -346,8 +372,10 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
346372
for (id, package) in workspace_ids.clone() {
347373
if id == flycheck.id() {
348374
updated = true;
349-
match package.filter(|_| !world.config.flycheck_workspace()) {
350-
Some(package) => flycheck.restart_for_package(package),
375+
match package
376+
.filter(|_| !world.config.flycheck_workspace() || target.is_some())
377+
{
378+
Some(package) => flycheck.restart_for_package(package, target.clone()),
351379
None => flycheck.restart_workspace(saved_file.clone()),
352380
}
353381
continue;

0 commit comments

Comments
 (0)