about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-05-30 12:00:14 +0000
committerbors <bors@rust-lang.org>2023-05-30 12:00:14 +0000
commite8dbb8e2e06d6fb0cb97c98eef27121e81370c93 (patch)
tree5b8884f022aa6ddb8fd992d8ebb48430e810d287
parent51c3ab5b85189b2430e438954dd792825c07ac87 (diff)
parentcea84427e00ad76b8400d45a84347b65d27dcef3 (diff)
downloadrust-e8dbb8e2e06d6fb0cb97c98eef27121e81370c93.tar.gz
rust-e8dbb8e2e06d6fb0cb97c98eef27121e81370c93.zip
Auto merge of #14911 - Veykril:config-cfg, r=Veykril
Allow setting cfgs

Fixes https://github.com/rust-lang/rust-analyzer/issues/14365
-rw-r--r--crates/cfg/src/lib.rs2
-rw-r--r--crates/project-model/src/cargo_workspace.rs39
-rw-r--r--crates/project-model/src/lib.rs2
-rw-r--r--crates/project-model/src/tests.rs22
-rw-r--r--crates/project-model/src/workspace.rs48
-rw-r--r--crates/rust-analyzer/src/config.rs35
-rw-r--r--docs/user/generated_config.adoc7
-rw-r--r--editors/code/package.json7
8 files changed, 73 insertions, 89 deletions
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index 30709c968da..495119d5519 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -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>,
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 649a149504c..92b454150c3 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -1,6 +1,5 @@
 //! See [`CargoWorkspace`].
 
-use std::iter;
 use std::path::PathBuf;
 use std::str::from_utf8;
 use std::{ops, process::Command};
@@ -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,
@@ -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.
@@ -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>;
diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs
index 70cb71ae3bd..61acc646f81 100644
--- a/crates/project-model/src/lib.rs
+++ b/crates/project-model/src/lib.rs
@@ -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},
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index c3c654ddb6f..7815b9dda77 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -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(
@@ -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);
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 4adaa6d86ee..a695bc1cca7 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -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>()
     }
 }
 
@@ -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(),
@@ -886,12 +874,10 @@ 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).
@@ -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
                 // 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
         });
@@ -1109,14 +1095,10 @@ 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).
@@ -1124,7 +1106,7 @@ fn handle_rustc_crates(
                 // 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() {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index b1d019cb113..649ac90fc6e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -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,
@@ -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};
@@ -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
@@ -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.
@@ -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,
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index c2f8c6c754f..dc97366eef1 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -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: `[]`)::
 +
 --
@@ -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`)::
 +
diff --git a/editors/code/package.json b/editors/code/package.json
index 390508b883e..aa63c40c0d2 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -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": [],
@@ -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"
                     ],