diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 4ee86954acd..fe8e882bf6f 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -41,19 +41,50 @@ pub enum InvocationLocation { Workspace, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CargoOptions { + pub target_triples: Vec, + pub all_targets: bool, + pub no_default_features: bool, + pub all_features: bool, + pub features: Vec, + pub extra_args: Vec, + pub extra_env: FxHashMap, + pub target_dir: Option, +} + +impl CargoOptions { + fn apply_on_command(&self, cmd: &mut Command) { + for target in &self.target_triples { + cmd.args(["--target", target.as_str()]); + } + if self.all_targets { + cmd.arg("--all-targets"); + } + if self.all_features { + cmd.arg("--all-features"); + } else { + if self.no_default_features { + cmd.arg("--no-default-features"); + } + if !self.features.is_empty() { + cmd.arg("--features"); + cmd.arg(self.features.join(" ")); + } + } + if let Some(target_dir) = &self.target_dir { + cmd.arg("--target-dir").arg(target_dir); + } + cmd.envs(&self.extra_env); + } +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum FlycheckConfig { CargoCommand { command: String, - target_triples: Vec, - all_targets: bool, - no_default_features: bool, - all_features: bool, - features: Vec, - extra_args: Vec, - extra_env: FxHashMap, + options: CargoOptions, ansi_color_output: bool, - target_dir: Option, }, CustomCommand { command: String, @@ -332,18 +363,7 @@ fn check_command( saved_file: Option<&AbsPath>, ) -> Option { let (mut cmd, args) = match &self.config { - FlycheckConfig::CargoCommand { - command, - target_triples, - no_default_features, - all_targets, - all_features, - extra_args, - features, - extra_env, - ansi_color_output, - target_dir, - } => { + FlycheckConfig::CargoCommand { command, options, ansi_color_output } => { let mut cmd = Command::new(Tool::Cargo.path()); if let Some(sysroot_root) = &self.sysroot_root { cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); @@ -365,28 +385,8 @@ fn check_command( cmd.arg("--manifest-path"); cmd.arg(self.root.join("Cargo.toml")); - for target in target_triples { - cmd.args(["--target", target.as_str()]); - } - if *all_targets { - cmd.arg("--all-targets"); - } - if *all_features { - cmd.arg("--all-features"); - } else { - if *no_default_features { - cmd.arg("--no-default-features"); - } - if !features.is_empty() { - cmd.arg("--features"); - cmd.arg(features.join(" ")); - } - } - if let Some(target_dir) = target_dir { - cmd.arg("--target-dir").arg(target_dir); - } - cmd.envs(extra_env); - (cmd, extra_args.clone()) + options.apply_on_command(&mut cmd); + (cmd, options.extra_args.clone()) } FlycheckConfig::CustomCommand { command, diff --git a/crates/flycheck/src/test_runner.rs b/crates/flycheck/src/test_runner.rs index 9f761c9ead1..94c05ebc743 100644 --- a/crates/flycheck/src/test_runner.rs +++ b/crates/flycheck/src/test_runner.rs @@ -7,7 +7,10 @@ use serde::Deserialize; use toolchain::Tool; -use crate::command::{CommandHandle, ParseFromLine}; +use crate::{ + command::{CommandHandle, ParseFromLine}, + CargoOptions, +}; #[derive(Debug, Deserialize)] #[serde(tag = "event", rename_all = "camelCase")] @@ -58,13 +61,14 @@ pub struct CargoTestHandle { // cargo test --workspace --no-fail-fast -- module::func -Z unstable-options --format=json impl CargoTestHandle { - pub fn new(path: Option<&str>) -> std::io::Result { + pub fn new(path: Option<&str>, options: CargoOptions) -> std::io::Result { let mut cmd = Command::new(Tool::Cargo.path()); cmd.env("RUSTC_BOOTSTRAP", "1"); cmd.arg("test"); cmd.arg("--workspace"); // --no-fail-fast is needed to ensure that all requested tests will run cmd.arg("--no-fail-fast"); + options.apply_on_command(&mut cmd); cmd.arg("--"); if let Some(path) = path { cmd.arg(path); diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 80f024184a5..5890af17eb9 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -10,7 +10,7 @@ use std::{fmt, iter, ops::Not}; use cfg::{CfgAtom, CfgDiff}; -use flycheck::FlycheckConfig; +use flycheck::{CargoOptions, FlycheckConfig}; use ide::{ AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, @@ -1364,6 +1364,22 @@ pub fn flycheck_workspace(&self) -> bool { self.data.check_workspace } + pub fn cargo_test_options(&self) -> CargoOptions { + CargoOptions { + target_triples: self.data.cargo_target.clone().into_iter().collect(), + all_targets: false, + no_default_features: self.data.cargo_noDefaultFeatures, + all_features: matches!(self.data.cargo_features, CargoFeaturesDef::All), + features: match self.data.cargo_features.clone() { + CargoFeaturesDef::All => vec![], + CargoFeaturesDef::Selected(it) => it, + }, + extra_args: self.extra_args().clone(), + extra_env: self.extra_env().clone(), + target_dir: self.target_dir_from_config(), + } + } + pub fn flycheck(&self) -> FlycheckConfig { match &self.data.check_overrideCommand { Some(args) if !args.is_empty() => { @@ -1389,37 +1405,39 @@ pub fn flycheck(&self) -> FlycheckConfig { } Some(_) | None => FlycheckConfig::CargoCommand { command: self.data.check_command.clone(), - target_triples: self - .data - .check_targets - .clone() - .and_then(|targets| match &targets.0[..] { - [] => None, - targets => Some(targets.into()), - }) - .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), - all_targets: self.data.check_allTargets.unwrap_or(self.data.cargo_allTargets), - no_default_features: self - .data - .check_noDefaultFeatures - .unwrap_or(self.data.cargo_noDefaultFeatures), - all_features: matches!( - self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features), - CargoFeaturesDef::All - ), - features: match self - .data - .check_features - .clone() - .unwrap_or_else(|| self.data.cargo_features.clone()) - { - CargoFeaturesDef::All => vec![], - CargoFeaturesDef::Selected(it) => it, + options: CargoOptions { + target_triples: self + .data + .check_targets + .clone() + .and_then(|targets| match &targets.0[..] { + [] => None, + targets => Some(targets.into()), + }) + .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()), + all_targets: self.data.check_allTargets.unwrap_or(self.data.cargo_allTargets), + no_default_features: self + .data + .check_noDefaultFeatures + .unwrap_or(self.data.cargo_noDefaultFeatures), + all_features: matches!( + self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features), + CargoFeaturesDef::All + ), + features: match self + .data + .check_features + .clone() + .unwrap_or_else(|| self.data.cargo_features.clone()) + { + CargoFeaturesDef::All => vec![], + CargoFeaturesDef::Selected(it) => it, + }, + extra_args: self.check_extra_args(), + extra_env: self.check_extra_env(), + target_dir: self.target_dir_from_config(), }, - extra_args: self.check_extra_args(), - extra_env: self.check_extra_env(), ansi_color_output: self.color_diagnostic_output(), - target_dir: self.target_dir_from_config(), }, } } @@ -2772,7 +2790,7 @@ fn cargo_target_dir_unset() { .unwrap(); assert_eq!(config.data.cargo_targetDir, None); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir.is_none()) + matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none()) ); } @@ -2791,7 +2809,7 @@ fn cargo_target_dir_subdir() { .unwrap(); assert_eq!(config.data.cargo_targetDir, Some(TargetDirectory::UseSubdirectory(true))); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(Utf8PathBuf::from("target/rust-analyzer"))) + matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer"))) ); } @@ -2813,7 +2831,7 @@ fn cargo_target_dir_relative_dir() { Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder"))) ); assert!( - matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(Utf8PathBuf::from("other_folder"))) + matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder"))) ); } } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 77692ed3ae7..77c4ad32cc9 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -220,11 +220,11 @@ pub(crate) fn handle_run_test( None => "".to_owned(), }; let handle = if lca.is_empty() { - flycheck::CargoTestHandle::new(None) + flycheck::CargoTestHandle::new(None, state.config.cargo_test_options()) } else if let Some((_, path)) = lca.split_once("::") { - flycheck::CargoTestHandle::new(Some(path)) + flycheck::CargoTestHandle::new(Some(path), state.config.cargo_test_options()) } else { - flycheck::CargoTestHandle::new(None) + flycheck::CargoTestHandle::new(None, state.config.cargo_test_options()) }; state.test_run_session = Some(handle?); Ok(())