Auto merge of #14911 - Veykril:config-cfg, r=Veykril

Allow setting cfgs

Fixes https://github.com/rust-lang/rust-analyzer/issues/14365
This commit is contained in:
bors 2023-05-30 12:00:14 +00:00
commit e8dbb8e2e0
8 changed files with 73 additions and 89 deletions

View file

@ -86,7 +86,7 @@ impl CfgOptions {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct CfgDiff { pub struct CfgDiff {
// Invariants: No duplicates, no atom that's both in `enable` and `disable`. // Invariants: No duplicates, no atom that's both in `enable` and `disable`.
enable: Vec<CfgAtom>, enable: Vec<CfgAtom>,

View file

@ -1,6 +1,5 @@
//! See [`CargoWorkspace`]. //! See [`CargoWorkspace`].
use std::iter;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::from_utf8; use std::str::from_utf8;
use std::{ops, process::Command}; use std::{ops, process::Command};
@ -58,20 +57,6 @@ pub enum RustLibSource {
Discover, Discover,
} }
/// Crates to disable `#[cfg(test)]` on.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UnsetTestCrates {
None,
Only(Vec<String>),
All,
}
impl Default for UnsetTestCrates {
fn default() -> Self {
Self::None
}
}
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum CargoFeatures { pub enum CargoFeatures {
All, All,
@ -100,8 +85,7 @@ pub struct CargoConfig {
pub sysroot_src: Option<AbsPathBuf>, pub sysroot_src: Option<AbsPathBuf>,
/// rustc private crate source /// rustc private crate source
pub rustc_source: Option<RustLibSource>, pub rustc_source: Option<RustLibSource>,
/// crates to disable `#[cfg(test)]` on pub cfg_overrides: CfgOverrides,
pub unset_test_crates: UnsetTestCrates,
/// Invoke `cargo check` through the RUSTC_WRAPPER. /// Invoke `cargo check` through the RUSTC_WRAPPER.
pub wrap_rustc_in_build_scripts: bool, pub wrap_rustc_in_build_scripts: bool,
/// The command to run instead of `cargo check` for building build scripts. /// The command to run instead of `cargo check` for building build scripts.
@ -114,27 +98,6 @@ pub struct CargoConfig {
pub invocation_location: InvocationLocation, pub invocation_location: InvocationLocation,
} }
impl CargoConfig {
pub fn cfg_overrides(&self) -> CfgOverrides {
match &self.unset_test_crates {
UnsetTestCrates::None => CfgOverrides::Selective(iter::empty().collect()),
UnsetTestCrates::Only(unset_test_crates) => CfgOverrides::Selective(
unset_test_crates
.iter()
.cloned()
.zip(iter::repeat_with(|| {
cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())])
.unwrap()
}))
.collect(),
),
UnsetTestCrates::All => CfgOverrides::Wildcard(
cfg::CfgDiff::new(Vec::new(), vec![cfg::CfgAtom::Flag("test".into())]).unwrap(),
),
}
}
}
pub type Package = Idx<PackageData>; pub type Package = Idx<PackageData>;
pub type Target = Idx<TargetData>; pub type Target = Idx<TargetData>;

View file

@ -44,7 +44,7 @@ pub use crate::{
build_scripts::WorkspaceBuildScripts, build_scripts::WorkspaceBuildScripts,
cargo_workspace::{ cargo_workspace::{
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency, CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
RustLibSource, Target, TargetData, TargetKind, UnsetTestCrates, RustLibSource, Target, TargetData, TargetKind,
}, },
manifest_path::ManifestPath, manifest_path::ManifestPath,
project_json::{ProjectJson, ProjectJsonData}, project_json::{ProjectJson, ProjectJsonData},

View file

@ -158,9 +158,10 @@ fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) {
#[test] #[test]
fn cargo_hello_world_project_model_with_wildcard_overrides() { fn cargo_hello_world_project_model_with_wildcard_overrides() {
let cfg_overrides = CfgOverrides::Wildcard( let cfg_overrides = CfgOverrides {
CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
); selective: Default::default(),
};
let (crate_graph, _proc_macros) = let (crate_graph, _proc_macros) =
load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);
check_crate_graph( check_crate_graph(
@ -173,14 +174,13 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
#[test] #[test]
fn cargo_hello_world_project_model_with_selective_overrides() { fn cargo_hello_world_project_model_with_selective_overrides() {
let cfg_overrides = { let cfg_overrides = CfgOverrides {
CfgOverrides::Selective( global: Default::default(),
std::iter::once(( selective: std::iter::once((
"libc".to_owned(), "libc".to_owned(),
CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
)) ))
.collect(), .collect(),
)
}; };
let (crate_graph, _proc_macros) = let (crate_graph, _proc_macros) =
load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);

View file

@ -28,29 +28,17 @@ use crate::{
}; };
/// A set of cfg-overrides per crate. /// A set of cfg-overrides per crate.
/// #[derive(Default, Debug, Clone, Eq, PartialEq)]
/// `Wildcard(..)` is useful e.g. disabling `#[cfg(test)]` on all crates, pub struct CfgOverrides {
/// without having to first obtain a list of all crates. /// A global set of overrides matching all crates.
#[derive(Debug, Clone, Eq, PartialEq)] pub global: CfgDiff,
pub enum CfgOverrides {
/// A single global set of overrides matching all crates.
Wildcard(CfgDiff),
/// A set of overrides matching specific crates. /// A set of overrides matching specific crates.
Selective(FxHashMap<String, CfgDiff>), pub selective: FxHashMap<String, CfgDiff>,
}
impl Default for CfgOverrides {
fn default() -> Self {
Self::Selective(FxHashMap::default())
}
} }
impl CfgOverrides { impl CfgOverrides {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
match self { self.global.len() + self.selective.iter().map(|(_, it)| it.len()).sum::<usize>()
CfgOverrides::Wildcard(_) => 1,
CfgOverrides::Selective(hash_map) => hash_map.len(),
}
} }
} }
@ -292,7 +280,7 @@ impl ProjectWorkspace {
let rustc_cfg = let rustc_cfg =
rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env); rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
let cfg_overrides = config.cfg_overrides(); let cfg_overrides = config.cfg_overrides.clone();
let data_layout = target_data_layout::get( let data_layout = target_data_layout::get(
Some(&cargo_toml), Some(&cargo_toml),
config.target.as_deref(), config.target.as_deref(),
@ -886,12 +874,10 @@ fn cargo_to_crate_graph(
cfg_options.insert_atom("test".into()); cfg_options.insert_atom("test".into());
} }
let overrides = match override_cfg { if !override_cfg.global.is_empty() {
CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), cfg_options.apply_diff(override_cfg.global.clone());
CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name),
}; };
if let Some(diff) = override_cfg.selective.get(&cargo[pkg].name) {
if let Some(overrides) = overrides {
// FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
// in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
// working on rust-lang/rust as that's the only time it appears outside sysroot). // working on rust-lang/rust as that's the only time it appears outside sysroot).
@ -899,7 +885,7 @@ fn cargo_to_crate_graph(
// A more ideal solution might be to reanalyze crates based on where the cursor is and // A more ideal solution might be to reanalyze crates based on where the cursor is and
// figure out the set of cfgs that would have to apply to make it active. // figure out the set of cfgs that would have to apply to make it active.
cfg_options.apply_diff(overrides.clone()); cfg_options.apply_diff(diff.clone());
}; };
cfg_options cfg_options
}); });
@ -1109,14 +1095,10 @@ fn handle_rustc_crates(
let mut cfg_options = cfg_options.clone(); let mut cfg_options = cfg_options.clone();
let overrides = match override_cfg { if !override_cfg.global.is_empty() {
CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff), cfg_options.apply_diff(override_cfg.global.clone());
CfgOverrides::Selective(cfg_overrides) => {
cfg_overrides.get(&rustc_workspace[pkg].name)
}
}; };
if let Some(diff) = override_cfg.selective.get(&rustc_workspace[pkg].name) {
if let Some(overrides) = overrides {
// FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
// in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
// working on rust-lang/rust as that's the only time it appears outside sysroot). // working on rust-lang/rust as that's the only time it appears outside sysroot).
@ -1124,7 +1106,7 @@ fn handle_rustc_crates(
// A more ideal solution might be to reanalyze crates based on where the cursor is and // A more ideal solution might be to reanalyze crates based on where the cursor is and
// figure out the set of cfgs that would have to apply to make it active. // figure out the set of cfgs that would have to apply to make it active.
cfg_options.apply_diff(overrides.clone()); cfg_options.apply_diff(diff.clone());
}; };
for &tgt in rustc_workspace[pkg].targets.iter() { for &tgt in rustc_workspace[pkg].targets.iter() {

View file

@ -9,6 +9,7 @@
use std::{fmt, iter, ops::Not, path::PathBuf}; use std::{fmt, iter, ops::Not, path::PathBuf};
use cfg::{CfgAtom, CfgDiff};
use flycheck::FlycheckConfig; use flycheck::FlycheckConfig;
use ide::{ use ide::{
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
@ -23,7 +24,6 @@ use itertools::Itertools;
use lsp_types::{ClientCapabilities, MarkupKind}; use lsp_types::{ClientCapabilities, MarkupKind};
use project_model::{ use project_model::{
CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource, CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource,
UnsetTestCrates,
}; };
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use serde::{de::DeserializeOwned, Deserialize}; use serde::{de::DeserializeOwned, Deserialize};
@ -101,6 +101,8 @@ config_data! {
/// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
/// avoid checking unnecessary things. /// avoid checking unnecessary things.
cargo_buildScripts_useRustcWrapper: bool = "true", cargo_buildScripts_useRustcWrapper: bool = "true",
/// List of cfg options to enable with the given values.
cargo_cfgs: FxHashMap<String, String> = "{}",
/// Extra arguments that are passed to every cargo invocation. /// Extra arguments that are passed to every cargo invocation.
cargo_extraArgs: Vec<String> = "[]", cargo_extraArgs: Vec<String> = "[]",
/// Extra environment variables that will be set when running cargo, rustc /// Extra environment variables that will be set when running cargo, rustc
@ -128,7 +130,7 @@ config_data! {
// FIXME(@poliorcetics): move to multiple targets here too, but this will need more work // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
// than `checkOnSave_target` // than `checkOnSave_target`
cargo_target: Option<String> = "null", cargo_target: Option<String> = "null",
/// Unsets `#[cfg(test)]` for the specified crates. /// Unsets the implicit `#[cfg(test)]` for the specified crates.
cargo_unsetTest: Vec<String> = "[\"core\"]", cargo_unsetTest: Vec<String> = "[\"core\"]",
/// Run the check command for diagnostics on save. /// Run the check command for diagnostics on save.
@ -1189,7 +1191,34 @@ impl Config {
sysroot, sysroot,
sysroot_src, sysroot_src,
rustc_source, rustc_source,
unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()), cfg_overrides: project_model::CfgOverrides {
global: CfgDiff::new(
self.data
.cargo_cfgs
.iter()
.map(|(key, val)| {
if val.is_empty() {
CfgAtom::Flag(key.into())
} else {
CfgAtom::KeyValue { key: key.into(), value: val.into() }
}
})
.collect(),
vec![],
)
.unwrap(),
selective: self
.data
.cargo_unsetTest
.iter()
.map(|it| {
(
it.clone(),
CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap(),
)
})
.collect(),
},
wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper, wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy { invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy {
InvocationStrategy::Once => project_model::InvocationStrategy::Once, InvocationStrategy::Once => project_model::InvocationStrategy::Once,

View file

@ -71,6 +71,11 @@ cargo check --quiet --workspace --message-format=json --all-targets
Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
avoid checking unnecessary things. avoid checking unnecessary things.
-- --
[[rust-analyzer.cargo.cfgs]]rust-analyzer.cargo.cfgs (default: `{}`)::
+
--
List of cfg options to enable with the given values.
--
[[rust-analyzer.cargo.extraArgs]]rust-analyzer.cargo.extraArgs (default: `[]`):: [[rust-analyzer.cargo.extraArgs]]rust-analyzer.cargo.extraArgs (default: `[]`)::
+ +
-- --
@ -120,7 +125,7 @@ Compilation target override (target triple).
[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`):: [[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`)::
+ +
-- --
Unsets `#[cfg(test)]` for the specified crates. Unsets the implicit `#[cfg(test)]` for the specified crates.
-- --
[[rust-analyzer.checkOnSave]]rust-analyzer.checkOnSave (default: `true`):: [[rust-analyzer.checkOnSave]]rust-analyzer.checkOnSave (default: `true`)::
+ +

View file

@ -553,6 +553,11 @@
"default": true, "default": true,
"type": "boolean" "type": "boolean"
}, },
"rust-analyzer.cargo.cfgs": {
"markdownDescription": "List of cfg options to enable with the given values.",
"default": {},
"type": "object"
},
"rust-analyzer.cargo.extraArgs": { "rust-analyzer.cargo.extraArgs": {
"markdownDescription": "Extra arguments that are passed to every cargo invocation.", "markdownDescription": "Extra arguments that are passed to every cargo invocation.",
"default": [], "default": [],
@ -617,7 +622,7 @@
] ]
}, },
"rust-analyzer.cargo.unsetTest": { "rust-analyzer.cargo.unsetTest": {
"markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.", "markdownDescription": "Unsets the implicit `#[cfg(test)]` for the specified crates.",
"default": [ "default": [
"core" "core"
], ],