Skip to content

Allow setting cfgs #14911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/cfg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl CfgOptions {
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct CfgDiff {
// Invariants: No duplicates, no atom that's both in `enable` and `disable`.
enable: Vec<CfgAtom>,
Expand Down
39 changes: 1 addition & 38 deletions crates/project-model/src/cargo_workspace.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! See [`CargoWorkspace`].

use std::iter;
use std::path::PathBuf;
use std::str::from_utf8;
use std::{ops, process::Command};
Expand Down Expand Up @@ -58,20 +57,6 @@ pub enum RustLibSource {
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)]
pub enum CargoFeatures {
All,
Expand Down Expand Up @@ -100,8 +85,7 @@ pub struct CargoConfig {
pub sysroot_src: Option<AbsPathBuf>,
/// rustc private crate source
pub rustc_source: Option<RustLibSource>,
/// crates to disable `#[cfg(test)]` on
pub unset_test_crates: UnsetTestCrates,
pub cfg_overrides: CfgOverrides,
/// Invoke `cargo check` through the RUSTC_WRAPPER.
pub wrap_rustc_in_build_scripts: bool,
/// The command to run instead of `cargo check` for building build scripts.
Expand All @@ -114,27 +98,6 @@ pub struct CargoConfig {
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 Target = Idx<TargetData>;
Expand Down
2 changes: 1 addition & 1 deletion crates/project-model/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub use crate::{
build_scripts::WorkspaceBuildScripts,
cargo_workspace::{
CargoConfig, CargoFeatures, CargoWorkspace, Package, PackageData, PackageDependency,
RustLibSource, Target, TargetData, TargetKind, UnsetTestCrates,
RustLibSource, Target, TargetData, TargetKind,
},
manifest_path::ManifestPath,
project_json::{ProjectJson, ProjectJsonData},
Expand Down
22 changes: 11 additions & 11 deletions crates/project-model/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,10 @@ fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) {

#[test]
fn cargo_hello_world_project_model_with_wildcard_overrides() {
let cfg_overrides = CfgOverrides::Wildcard(
CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
);
let cfg_overrides = CfgOverrides {
global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
selective: Default::default(),
};
let (crate_graph, _proc_macros) =
load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);
check_crate_graph(
Expand All @@ -173,14 +174,13 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {

#[test]
fn cargo_hello_world_project_model_with_selective_overrides() {
let cfg_overrides = {
CfgOverrides::Selective(
std::iter::once((
"libc".to_owned(),
CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
))
.collect(),
)
let cfg_overrides = CfgOverrides {
global: Default::default(),
selective: std::iter::once((
"libc".to_owned(),
CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
))
.collect(),
};
let (crate_graph, _proc_macros) =
load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);
Expand Down
48 changes: 15 additions & 33 deletions crates/project-model/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,17 @@ use crate::{
};

/// A set of cfg-overrides per crate.
///
/// `Wildcard(..)` is useful e.g. disabling `#[cfg(test)]` on all crates,
/// without having to first obtain a list of all crates.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CfgOverrides {
/// A single global set of overrides matching all crates.
Wildcard(CfgDiff),
#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct CfgOverrides {
/// A global set of overrides matching all crates.
pub global: CfgDiff,
/// A set of overrides matching specific crates.
Selective(FxHashMap<String, CfgDiff>),
}

impl Default for CfgOverrides {
fn default() -> Self {
Self::Selective(FxHashMap::default())
}
pub selective: FxHashMap<String, CfgDiff>,
}

impl CfgOverrides {
pub fn len(&self) -> usize {
match self {
CfgOverrides::Wildcard(_) => 1,
CfgOverrides::Selective(hash_map) => hash_map.len(),
}
self.global.len() + self.selective.iter().map(|(_, it)| it.len()).sum::<usize>()
}
}

Expand Down Expand Up @@ -292,7 +280,7 @@ impl ProjectWorkspace {
let rustc_cfg =
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(
Some(&cargo_toml),
config.target.as_deref(),
Expand Down Expand Up @@ -886,20 +874,18 @@ fn cargo_to_crate_graph(
cfg_options.insert_atom("test".into());
}

let overrides = match override_cfg {
CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name),
if !override_cfg.global.is_empty() {
cfg_options.apply_diff(override_cfg.global.clone());
};

if let Some(overrides) = overrides {
if let Some(diff) = override_cfg.selective.get(&cargo[pkg].name) {
// 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
// working on rust-lang/rust as that's the only time it appears outside sysroot).
//
// 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.

cfg_options.apply_diff(overrides.clone());
cfg_options.apply_diff(diff.clone());
};
cfg_options
});
Expand Down Expand Up @@ -1109,22 +1095,18 @@ fn handle_rustc_crates(

let mut cfg_options = cfg_options.clone();

let overrides = match override_cfg {
CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
CfgOverrides::Selective(cfg_overrides) => {
cfg_overrides.get(&rustc_workspace[pkg].name)
}
if !override_cfg.global.is_empty() {
cfg_options.apply_diff(override_cfg.global.clone());
};

if let Some(overrides) = overrides {
if let Some(diff) = override_cfg.selective.get(&rustc_workspace[pkg].name) {
// 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
// working on rust-lang/rust as that's the only time it appears outside sysroot).
//
// 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.

cfg_options.apply_diff(overrides.clone());
cfg_options.apply_diff(diff.clone());
};

for &tgt in rustc_workspace[pkg].targets.iter() {
Expand Down
35 changes: 32 additions & 3 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use std::{fmt, iter, ops::Not, path::PathBuf};

use cfg::{CfgAtom, CfgDiff};
use flycheck::FlycheckConfig;
use ide::{
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
Expand All @@ -23,7 +24,6 @@ use itertools::Itertools;
use lsp_types::{ClientCapabilities, MarkupKind};
use project_model::{
CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource,
UnsetTestCrates,
};
use rustc_hash::{FxHashMap, FxHashSet};
use serde::{de::DeserializeOwned, Deserialize};
Expand Down Expand Up @@ -101,6 +101,8 @@ config_data! {
/// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
/// avoid checking unnecessary things.
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.
cargo_extraArgs: Vec<String> = "[]",
/// Extra environment variables that will be set when running cargo, rustc
Expand Down Expand Up @@ -128,7 +130,7 @@ config_data! {
// FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
// than `checkOnSave_target`
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\"]",

/// Run the check command for diagnostics on save.
Expand Down Expand Up @@ -1189,7 +1191,34 @@ impl Config {
sysroot,
sysroot_src,
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,
invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy {
InvocationStrategy::Once => project_model::InvocationStrategy::Once,
Expand Down
7 changes: 6 additions & 1 deletion docs/user/generated_config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ cargo check --quiet --workspace --message-format=json --all-targets
Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
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: `[]`)::
+
--
Expand Down Expand Up @@ -120,7 +125,7 @@ Compilation target override (target triple).
[[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`)::
+
Expand Down
7 changes: 6 additions & 1 deletion editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,11 @@
"default": true,
"type": "boolean"
},
"rust-analyzer.cargo.cfgs": {
"markdownDescription": "List of cfg options to enable with the given values.",
"default": {},
"type": "object"
},
"rust-analyzer.cargo.extraArgs": {
"markdownDescription": "Extra arguments that are passed to every cargo invocation.",
"default": [],
Expand Down Expand Up @@ -617,7 +622,7 @@
]
},
"rust-analyzer.cargo.unsetTest": {
"markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.",
"markdownDescription": "Unsets the implicit `#[cfg(test)]` for the specified crates.",
"default": [
"core"
],
Expand Down