about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-03-03 11:42:40 +0000
committerGitHub <noreply@github.com>2025-03-03 11:42:40 +0000
commit73e0fe15454f5e2c445a23183fbf61269a20cb5b (patch)
tree9270b47eaa5d07cc6685d6c6eb4c31cd9553621b /src
parent6610e60175f772dc3c193530957ad72ac8b27529 (diff)
parent66368aa629ff844aa6e92ed49dc6ed12bc65f4e5 (diff)
downloadrust-73e0fe15454f5e2c445a23183fbf61269a20cb5b.tar.gz
rust-73e0fe15454f5e2c445a23183fbf61269a20cb5b.zip
Merge pull request #19243 from Veykril/push-qrrqsywkwyzp
Allow unsetting default cfgs
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs19
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/dnf.rs19
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/lib.rs20
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs56
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs26
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md4
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json2
10 files changed, 96 insertions, 64 deletions
diff --git a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
index 84b91a527f0..0ec082dfa7f 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs
@@ -18,6 +18,25 @@ pub enum CfgAtom {
     KeyValue { key: Symbol, value: Symbol },
 }
 
+impl PartialOrd for CfgAtom {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for CfgAtom {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        match (self, other) {
+            (CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()),
+            (CfgAtom::Flag(_), CfgAtom::KeyValue { .. }) => std::cmp::Ordering::Less,
+            (CfgAtom::KeyValue { .. }, CfgAtom::Flag(_)) => std::cmp::Ordering::Greater,
+            (CfgAtom::KeyValue { key, value }, CfgAtom::KeyValue { key: key2, value: value2 }) => {
+                key.as_str().cmp(key2.as_str()).then(value.as_str().cmp(value2.as_str()))
+            }
+        }
+    }
+}
+
 impl fmt::Display for CfgAtom {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
diff --git a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
index f3ebca04650..424672a275e 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/dnf.rs
@@ -66,9 +66,9 @@ impl DnfExpr {
             }
         }
 
-        res.enabled.sort_unstable_by(compare);
+        res.enabled.sort_unstable();
         res.enabled.dedup();
-        res.disabled.sort_unstable_by(compare);
+        res.disabled.sort_unstable();
         res.disabled.dedup();
         Some(res)
     }
@@ -114,25 +114,14 @@ impl DnfExpr {
             };
 
             // Undo the FxHashMap randomization for consistent output.
-            diff.enable.sort_unstable_by(compare);
-            diff.disable.sort_unstable_by(compare);
+            diff.enable.sort_unstable();
+            diff.disable.sort_unstable();
 
             Some(diff)
         })
     }
 }
 
-fn compare(a: &CfgAtom, b: &CfgAtom) -> std::cmp::Ordering {
-    match (a, b) {
-        (CfgAtom::Flag(a), CfgAtom::Flag(b)) => a.as_str().cmp(b.as_str()),
-        (CfgAtom::Flag(_), CfgAtom::KeyValue { .. }) => std::cmp::Ordering::Less,
-        (CfgAtom::KeyValue { .. }, CfgAtom::Flag(_)) => std::cmp::Ordering::Greater,
-        (CfgAtom::KeyValue { key, value }, CfgAtom::KeyValue { key: key2, value: value2 }) => {
-            key.as_str().cmp(key2.as_str()).then(value.as_str().cmp(value2.as_str()))
-        }
-    }
-}
-
 impl fmt::Display for DnfExpr {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         if self.conjunctions.len() != 1 {
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index 6a6213a871f..08545b68511 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -148,16 +148,20 @@ pub struct CfgDiff {
 }
 
 impl CfgDiff {
-    /// Create a new CfgDiff. Will return None if the same item appears more than once in the set
-    /// of both.
-    pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> {
-        let mut occupied = FxHashSet::default();
-        if enable.iter().chain(disable.iter()).any(|item| !occupied.insert(item)) {
-            // was present
-            return None;
+    /// Create a new CfgDiff.
+    pub fn new(mut enable: Vec<CfgAtom>, mut disable: Vec<CfgAtom>) -> CfgDiff {
+        enable.sort();
+        enable.dedup();
+        disable.sort();
+        disable.dedup();
+        for i in (0..enable.len()).rev() {
+            if let Some(j) = disable.iter().position(|atom| *atom == enable[i]) {
+                enable.remove(i);
+                disable.remove(j);
+            }
         }
 
-        Some(CfgDiff { enable, disable })
+        CfgDiff { enable, disable }
     }
 
     /// Returns the total number of atoms changed by this diff.
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index cfc666970bd..83740622732 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -166,7 +166,7 @@ fn check_crate_graph(crate_graph: CrateGraph, expect: ExpectFile) {
 #[test]
 fn cargo_hello_world_project_model_with_wildcard_overrides() {
     let cfg_overrides = CfgOverrides {
-        global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(),
+        global: CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]),
         selective: Default::default(),
     };
     let (crate_graph, _proc_macros) =
@@ -185,7 +185,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
         global: Default::default(),
         selective: std::iter::once((
             "libc".to_owned(),
-            CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]).unwrap(),
+            CfgDiff::new(Vec::new(), vec![CfgAtom::Flag(sym::test.clone())]),
         ))
         .collect(),
     };
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 2c9f41e828e..89818be8d47 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -1521,7 +1521,7 @@ fn extend_crate_graph_with_sysroot(
 ) -> (SysrootPublicDeps, Option<CrateId>) {
     let mut pub_deps = vec![];
     let mut libproc_macro = None;
-    let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag(sym::test.clone())]).unwrap();
+    let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag(sym::test.clone())]);
     for (cid, c) in sysroot_crate_graph.iter_mut() {
         // uninject `test` flag so `core` keeps working.
         Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone());
@@ -1599,8 +1599,7 @@ fn sysroot_to_crate_graph(
                             CfgAtom::Flag(sym::miri.clone()),
                         ],
                         vec![],
-                    )
-                    .unwrap(),
+                    ),
                     ..Default::default()
                 },
                 &WorkspaceBuildScripts::default(),
@@ -1623,8 +1622,7 @@ fn sysroot_to_crate_graph(
                             CfgAtom::Flag(sym::miri.clone()),
                         ],
                         vec![],
-                    )
-                    .unwrap(),
+                    ),
                     ..Default::default()
                 },
                 false,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 4fc6180920f..b9e4457fc98 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -69,7 +69,7 @@ impl flags::AnalysisStats {
             all_targets: true,
             set_test: !self.no_test,
             cfg_overrides: CfgOverrides {
-                global: CfgDiff::new(vec![CfgAtom::Flag(hir::sym::miri.clone())], vec![]).unwrap(),
+                global: CfgDiff::new(vec![CfgAtom::Flag(hir::sym::miri.clone())], vec![]),
                 selective: Default::default(),
             },
             ..Default::default()
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 713e28c87cb..45ac68339b3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -18,7 +18,7 @@ use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
     SnippetCap,
 };
-use itertools::Itertools;
+use itertools::{Either, Itertools};
 use paths::{Utf8Path, Utf8PathBuf};
 use project_model::{
     CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand,
@@ -589,6 +589,10 @@ config_data! {
         /// avoid checking unnecessary things.
         cargo_buildScripts_useRustcWrapper: bool = true,
         /// List of cfg options to enable with the given values.
+        ///
+        /// To enable a name without a value, use `"key"`.
+        /// To enable a name with a value, use `"key=value"`.
+        /// To disable, prefix the entry with a `!`.
         cargo_cfgs: Vec<String> = {
             vec!["debug_assertions".into(), "miri".into()]
         },
@@ -1980,27 +1984,35 @@ impl Config {
             rustc_source,
             extra_includes,
             cfg_overrides: project_model::CfgOverrides {
-                global: CfgDiff::new(
-                    self.cargo_cfgs(source_root)
-                        .iter()
-                        // parse any cfg setting formatted as key=value or just key (without value)
-                        .filter_map(|s| {
-                            let mut sp = s.splitn(2, "=");
-                            let key = sp.next();
-                            let val = sp.next();
-                            key.map(|key| (key, val))
-                        })
-                        .map(|(key, val)| match val {
-                            Some(val) => CfgAtom::KeyValue {
-                                key: Symbol::intern(key),
-                                value: Symbol::intern(val),
-                            },
-                            None => CfgAtom::Flag(Symbol::intern(key)),
-                        })
-                        .collect(),
-                    vec![],
-                )
-                .unwrap(),
+                global: {
+                    let (enabled, disabled): (Vec<_>, Vec<_>) =
+                        self.cargo_cfgs(source_root).iter().partition_map(|s| {
+                            s.strip_prefix("!").map_or(Either::Left(s), Either::Right)
+                        });
+                    CfgDiff::new(
+                        enabled
+                            .into_iter()
+                            // parse any cfg setting formatted as key=value or just key (without value)
+                            .map(|s| match s.split_once("=") {
+                                Some((key, val)) => CfgAtom::KeyValue {
+                                    key: Symbol::intern(key),
+                                    value: Symbol::intern(val),
+                                },
+                                None => CfgAtom::Flag(Symbol::intern(s)),
+                            })
+                            .collect(),
+                        disabled
+                            .into_iter()
+                            .map(|s| match s.split_once("=") {
+                                Some((key, val)) => CfgAtom::KeyValue {
+                                    key: Symbol::intern(key),
+                                    value: Symbol::intern(val),
+                                },
+                                None => CfgAtom::Flag(Symbol::intern(s)),
+                            })
+                            .collect(),
+                    )
+                },
                 selective: Default::default(),
             },
             wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(source_root),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 2309f94a742..7529e7c188f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -244,8 +244,14 @@ struct FlycheckActor {
     /// The receiver side of the channel mentioned above.
     command_receiver: Option<Receiver<CargoCheckMessage>>,
     diagnostics_cleared_for: FxHashSet<Arc<PackageId>>,
-    diagnostics_cleared_for_all: bool,
-    diagnostics_received: bool,
+    diagnostics_received: DiagnosticsReceived,
+}
+
+#[derive(PartialEq)]
+enum DiagnosticsReceived {
+    Yes,
+    No,
+    YesAndClearedForAll,
 }
 
 #[allow(clippy::large_enum_variant)]
@@ -276,8 +282,7 @@ impl FlycheckActor {
             command_handle: None,
             command_receiver: None,
             diagnostics_cleared_for: Default::default(),
-            diagnostics_cleared_for_all: false,
-            diagnostics_received: false,
+            diagnostics_received: DiagnosticsReceived::No,
         }
     }
 
@@ -354,7 +359,7 @@ impl FlycheckActor {
                             error
                         );
                     }
-                    if !self.diagnostics_received {
+                    if self.diagnostics_received == DiagnosticsReceived::No {
                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
                         // We finished without receiving any diagnostics.
                         // Clear everything for good measure
@@ -396,7 +401,7 @@ impl FlycheckActor {
                             package_id = package_id.as_ref().map(|it| &it.repr),
                             "diagnostic received"
                         );
-                        self.diagnostics_received = true;
+                        self.diagnostics_received = DiagnosticsReceived::Yes;
                         if let Some(package_id) = &package_id {
                             if self.diagnostics_cleared_for.insert(package_id.clone()) {
                                 tracing::trace!(
@@ -409,8 +414,10 @@ impl FlycheckActor {
                                     package_id: Some(package_id.clone()),
                                 });
                             }
-                        } else if !self.diagnostics_cleared_for_all {
-                            self.diagnostics_cleared_for_all = true;
+                        } else if self.diagnostics_received
+                            != DiagnosticsReceived::YesAndClearedForAll
+                        {
+                            self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll;
                             self.send(FlycheckMessage::ClearDiagnostics {
                                 id: self.id,
                                 package_id: None,
@@ -445,8 +452,7 @@ impl FlycheckActor {
 
     fn clear_diagnostics_state(&mut self) {
         self.diagnostics_cleared_for.clear();
-        self.diagnostics_cleared_for_all = false;
-        self.diagnostics_received = false;
+        self.diagnostics_received = DiagnosticsReceived::No;
     }
 
     /// Construct a `Command` object for checking the user's code. If the user
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 1cbe51836f4..0a612d20b9c 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -102,6 +102,10 @@ Default:
 
  List of cfg options to enable with the given values.
 
+To enable a name without a value, use `"key"`.
+To enable a name with a value, use `"key=value"`.
+To disable, prefix the entry with a `!`.
+
 
  **rust-analyzer.cargo.extraArgs** (default: [])
 
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 587ae92520b..9df41c7487c 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -825,7 +825,7 @@
                 "title": "cargo",
                 "properties": {
                     "rust-analyzer.cargo.cfgs": {
-                        "markdownDescription": "List of cfg options to enable with the given values.",
+                        "markdownDescription": "List of cfg options to enable with the given values.\n\nTo enable a name without a value, use `\"key\"`.\nTo enable a name with a value, use `\"key=value\"`.\nTo disable, prefix the entry with a `!`.",
                         "default": [
                             "debug_assertions",
                             "miri"