From 94f206a13936cd1897554c91c377b37915eb338e Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Tue, 20 Aug 2024 18:13:22 +0200 Subject: [PATCH 1/2] Run flycheck only on crate if target is binary. --- .../crates/rust-analyzer/src/flycheck.rs | 30 +++++++---- .../src/handlers/notification.rs | 51 +++++++++++++------ .../crates/rust-analyzer/src/main_loop.rs | 4 +- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index cf13a7386379b..0e859f327510a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -118,14 +118,14 @@ impl FlycheckHandle { } /// Schedule a re-start of the cargo check worker to do a workspace wide check. - pub(crate) fn restart_workspace(&self, saved_file: Option) { - self.sender.send(StateChange::Restart { package: None, saved_file }).unwrap(); + pub(crate) fn restart_workspace(&self, saved_file: Option, target: Option) { + self.sender.send(StateChange::Restart { package: None, saved_file, target }).unwrap(); } /// Schedule a re-start of the cargo check worker to do a package wide check. - pub(crate) fn restart_for_package(&self, package: String) { + pub(crate) fn restart_for_package(&self, package: String, target: Option) { self.sender - .send(StateChange::Restart { package: Some(package), saved_file: None }) + .send(StateChange::Restart { package: Some(package), saved_file: None, target }) .unwrap(); } @@ -183,7 +183,7 @@ pub(crate) enum Progress { } enum StateChange { - Restart { package: Option, saved_file: Option }, + Restart { package: Option, saved_file: Option, target: Option }, Cancel, } @@ -271,7 +271,7 @@ impl FlycheckActor { tracing::debug!(flycheck_id = self.id, "flycheck cancelled"); self.cancel_check_process(); } - Event::RequestStateChange(StateChange::Restart { package, saved_file }) => { + Event::RequestStateChange(StateChange::Restart { package, saved_file, target }) => { // Cancel the previously spawned process self.cancel_check_process(); while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) { @@ -281,11 +281,14 @@ impl FlycheckActor { } } - let command = - match self.check_command(package.as_deref(), saved_file.as_deref()) { - Some(c) => c, - None => continue, - }; + let command = match self.check_command( + package.as_deref(), + saved_file.as_deref(), + target.as_deref(), + ) { + Some(c) => c, + None => continue, + }; let formatted_command = format!("{command:?}"); tracing::debug!(?command, "will restart flycheck"); @@ -381,6 +384,7 @@ impl FlycheckActor { &self, package: Option<&str>, saved_file: Option<&AbsPath>, + bin_target: Option<&str>, ) -> Option { match &self.config { FlycheckConfig::CargoCommand { command, options, ansi_color_output } => { @@ -396,6 +400,10 @@ impl FlycheckActor { None => cmd.arg("--workspace"), }; + if let Some(tgt) = bin_target { + cmd.arg("--bin").arg(tgt); + } + cmd.arg(if *ansi_color_output { "--message-format=json-diagnostic-rendered-ansi" } else { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index de5d1f231368b..fb7caf652d06a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -20,6 +20,7 @@ use crate::{ lsp_ext::{self, RunFlycheckParams}, mem_docs::DocumentData, reload, + target_spec::TargetSpec, }; pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> anyhow::Result<()> { @@ -185,7 +186,7 @@ pub(crate) fn handle_did_save_text_document( } else if state.config.check_on_save() { // No specific flycheck was triggered, so let's trigger all of them. for flycheck in state.flycheck.iter() { - flycheck.restart_workspace(None); + flycheck.restart_workspace(None, None); } } Ok(()) @@ -287,16 +288,33 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let world = state.snapshot(); let mut updated = false; let task = move || -> std::result::Result<(), ide::Cancelled> { - // Trigger flychecks for all workspaces that depend on the saved file - // Crates containing or depending on the saved file - let crate_ids: Vec<_> = world - .analysis - .crates_for(file_id)? - .into_iter() - .flat_map(|id| world.analysis.transitive_rev_deps(id)) - .flatten() - .unique() - .collect(); + // Is the target binary? If so we let flycheck run only for the workspace that contains the crate. + let target_is_bin = TargetSpec::for_file(&world, file_id)?.and_then(|x| { + if x.target_kind() == project_model::TargetKind::Bin { + return match x { + TargetSpec::Cargo(c) => Some(c.target), + TargetSpec::ProjectJson(p) => Some(p.label), + }; + } + + None + }); + + let crate_ids = if target_is_bin.is_some() { + // Trigger flychecks for the only workspace which the binary crate belongs to + world.analysis.crates_for(file_id)?.into_iter().unique().collect::>() + } else { + // Trigger flychecks for all workspaces that depend on the saved file + // Crates containing or depending on the saved file + world + .analysis + .crates_for(file_id)? + .into_iter() + .flat_map(|id| world.analysis.transitive_rev_deps(id)) + .flatten() + .unique() + .collect::>() + }; let crate_root_paths: Vec<_> = crate_ids .iter() @@ -347,8 +365,11 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { if id == flycheck.id() { updated = true; match package.filter(|_| !world.config.flycheck_workspace()) { - Some(package) => flycheck.restart_for_package(package), - None => flycheck.restart_workspace(saved_file.clone()), + Some(package) => { + flycheck.restart_for_package(package, target_is_bin.clone()) + } + None => flycheck + .restart_workspace(saved_file.clone(), target_is_bin.clone()), } continue; } @@ -357,7 +378,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { // No specific flycheck was triggered, so let's trigger all of them. if !updated { for flycheck in world.flycheck.iter() { - flycheck.restart_workspace(saved_file.clone()); + flycheck.restart_workspace(saved_file.clone(), None); } } Ok(()) @@ -399,7 +420,7 @@ pub(crate) fn handle_run_flycheck( } // No specific flycheck was triggered, so let's trigger all of them. for flycheck in state.flycheck.iter() { - flycheck.restart_workspace(None); + flycheck.restart_workspace(None, None); } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 1d4ee71e5c1a0..79a209f8bfe23 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -406,7 +406,9 @@ impl GlobalState { if became_quiescent { if self.config.check_on_save() { // Project has loaded properly, kick off initial flycheck - self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None)); + self.flycheck + .iter() + .for_each(|flycheck| flycheck.restart_workspace(None, None)); } if self.config.prefill_caches() { self.prime_caches_queue.request_op("became quiescent".to_owned(), ()); From 0251cfa33bf10665055b9a2741aac6c60cdb65ad Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Thu, 22 Aug 2024 23:59:01 +0200 Subject: [PATCH 2/2] Apply changes --- .../crates/rust-analyzer/src/flycheck.rs | 39 +++++++++++------ .../src/handlers/notification.rs | 43 +++++++++++-------- .../crates/rust-analyzer/src/main_loop.rs | 4 +- 3 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 0e859f327510a..9fb43286579f8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -34,6 +34,14 @@ pub(crate) struct CargoOptions { pub(crate) target_dir: Option, } +#[derive(Clone)] +pub(crate) enum Target { + Bin(String), + Example(String), + Benchmark(String), + Test(String), +} + impl CargoOptions { pub(crate) fn apply_on_command(&self, cmd: &mut Command) { for target in &self.target_triples { @@ -118,12 +126,12 @@ impl FlycheckHandle { } /// Schedule a re-start of the cargo check worker to do a workspace wide check. - pub(crate) fn restart_workspace(&self, saved_file: Option, target: Option) { - self.sender.send(StateChange::Restart { package: None, saved_file, target }).unwrap(); + pub(crate) fn restart_workspace(&self, saved_file: Option) { + self.sender.send(StateChange::Restart { package: None, saved_file, target: None }).unwrap(); } /// Schedule a re-start of the cargo check worker to do a package wide check. - pub(crate) fn restart_for_package(&self, package: String, target: Option) { + pub(crate) fn restart_for_package(&self, package: String, target: Option) { self.sender .send(StateChange::Restart { package: Some(package), saved_file: None, target }) .unwrap(); @@ -183,7 +191,7 @@ pub(crate) enum Progress { } enum StateChange { - Restart { package: Option, saved_file: Option, target: Option }, + Restart { package: Option, saved_file: Option, target: Option }, Cancel, } @@ -281,14 +289,12 @@ impl FlycheckActor { } } - let command = match self.check_command( - package.as_deref(), - saved_file.as_deref(), - target.as_deref(), - ) { - Some(c) => c, - None => continue, + let Some(command) = + self.check_command(package.as_deref(), saved_file.as_deref(), target) + else { + continue; }; + let formatted_command = format!("{command:?}"); tracing::debug!(?command, "will restart flycheck"); @@ -384,7 +390,7 @@ impl FlycheckActor { &self, package: Option<&str>, saved_file: Option<&AbsPath>, - bin_target: Option<&str>, + target: Option, ) -> Option { match &self.config { FlycheckConfig::CargoCommand { command, options, ansi_color_output } => { @@ -400,8 +406,13 @@ impl FlycheckActor { None => cmd.arg("--workspace"), }; - if let Some(tgt) = bin_target { - cmd.arg("--bin").arg(tgt); + if let Some(tgt) = target { + match tgt { + Target::Bin(tgt) => cmd.arg("--bin").arg(tgt), + Target::Example(tgt) => cmd.arg("--example").arg(tgt), + Target::Test(tgt) => cmd.arg("--test").arg(tgt), + Target::Benchmark(tgt) => cmd.arg("--bench").arg(tgt), + }; } cmd.arg(if *ansi_color_output { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index fb7caf652d06a..f99319271ba4a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -15,6 +15,7 @@ use vfs::{AbsPathBuf, ChangeKind, VfsPath}; use crate::{ config::{Config, ConfigChange}, + flycheck::Target, global_state::{FetchWorkspaceRequest, GlobalState}, lsp::{from_proto, utils::apply_document_changes}, lsp_ext::{self, RunFlycheckParams}, @@ -186,7 +187,7 @@ pub(crate) fn handle_did_save_text_document( } else if state.config.check_on_save() { // No specific flycheck was triggered, so let's trigger all of them. for flycheck in state.flycheck.iter() { - flycheck.restart_workspace(None, None); + flycheck.restart_workspace(None); } } Ok(()) @@ -289,18 +290,25 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let mut updated = false; let task = move || -> std::result::Result<(), ide::Cancelled> { // Is the target binary? If so we let flycheck run only for the workspace that contains the crate. - let target_is_bin = TargetSpec::for_file(&world, file_id)?.and_then(|x| { - if x.target_kind() == project_model::TargetKind::Bin { - return match x { - TargetSpec::Cargo(c) => Some(c.target), - TargetSpec::ProjectJson(p) => Some(p.label), - }; - } + let target = TargetSpec::for_file(&world, file_id)?.and_then(|x| { + let tgt_kind = x.target_kind(); + let tgt_name = match x { + TargetSpec::Cargo(c) => c.target, + TargetSpec::ProjectJson(p) => p.label, + }; + + let tgt = match tgt_kind { + project_model::TargetKind::Bin => Target::Bin(tgt_name), + project_model::TargetKind::Example => Target::Example(tgt_name), + project_model::TargetKind::Test => Target::Test(tgt_name), + project_model::TargetKind::Bench => Target::Benchmark(tgt_name), + _ => return None, + }; - None + Some(tgt) }); - let crate_ids = if target_is_bin.is_some() { + let crate_ids = if target.is_some() { // Trigger flychecks for the only workspace which the binary crate belongs to world.analysis.crates_for(file_id)?.into_iter().unique().collect::>() } else { @@ -364,12 +372,11 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { for (id, package) in workspace_ids.clone() { if id == flycheck.id() { updated = true; - match package.filter(|_| !world.config.flycheck_workspace()) { - Some(package) => { - flycheck.restart_for_package(package, target_is_bin.clone()) - } - None => flycheck - .restart_workspace(saved_file.clone(), target_is_bin.clone()), + match package + .filter(|_| !world.config.flycheck_workspace() || target.is_some()) + { + Some(package) => flycheck.restart_for_package(package, target.clone()), + None => flycheck.restart_workspace(saved_file.clone()), } continue; } @@ -378,7 +385,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { // No specific flycheck was triggered, so let's trigger all of them. if !updated { for flycheck in world.flycheck.iter() { - flycheck.restart_workspace(saved_file.clone(), None); + flycheck.restart_workspace(saved_file.clone()); } } Ok(()) @@ -420,7 +427,7 @@ pub(crate) fn handle_run_flycheck( } // No specific flycheck was triggered, so let's trigger all of them. for flycheck in state.flycheck.iter() { - flycheck.restart_workspace(None, None); + flycheck.restart_workspace(None); } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 79a209f8bfe23..1d4ee71e5c1a0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -406,9 +406,7 @@ impl GlobalState { if became_quiescent { if self.config.check_on_save() { // Project has loaded properly, kick off initial flycheck - self.flycheck - .iter() - .for_each(|flycheck| flycheck.restart_workspace(None, None)); + self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None)); } if self.config.prefill_caches() { self.prime_caches_queue.request_op("became quiescent".to_owned(), ());