mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
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:
commit
e8dbb8e2e0
8 changed files with 73 additions and 89 deletions
|
@ -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>,
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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`)::
|
||||||
+
|
+
|
||||||
|
|
|
@ -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"
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue