Allow unsetting default cfgs

This commit is contained in:
Lukas Wirth 2025-02-27 16:49:37 +01:00
parent 505b52da5f
commit 5e18ad0770
10 changed files with 96 additions and 64 deletions

View File

@ -18,6 +18,25 @@ pub enum CfgAtom {
KeyValue { key: Symbol, value: Symbol }, 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 { impl fmt::Display for CfgAtom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {

View File

@ -66,9 +66,9 @@ impl DnfExpr {
} }
} }
res.enabled.sort_unstable_by(compare); res.enabled.sort_unstable();
res.enabled.dedup(); res.enabled.dedup();
res.disabled.sort_unstable_by(compare); res.disabled.sort_unstable();
res.disabled.dedup(); res.disabled.dedup();
Some(res) Some(res)
} }
@ -114,25 +114,14 @@ impl DnfExpr {
}; };
// Undo the FxHashMap randomization for consistent output. // Undo the FxHashMap randomization for consistent output.
diff.enable.sort_unstable_by(compare); diff.enable.sort_unstable();
diff.disable.sort_unstable_by(compare); diff.disable.sort_unstable();
Some(diff) 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 { impl fmt::Display for DnfExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.conjunctions.len() != 1 { if self.conjunctions.len() != 1 {

View File

@ -148,16 +148,20 @@ pub struct CfgDiff {
} }
impl CfgDiff { impl CfgDiff {
/// Create a new CfgDiff. Will return None if the same item appears more than once in the set /// Create a new CfgDiff.
/// of both. pub fn new(mut enable: Vec<CfgAtom>, mut disable: Vec<CfgAtom>) -> CfgDiff {
pub fn new(enable: Vec<CfgAtom>, disable: Vec<CfgAtom>) -> Option<CfgDiff> { enable.sort();
let mut occupied = FxHashSet::default(); enable.dedup();
if enable.iter().chain(disable.iter()).any(|item| !occupied.insert(item)) { disable.sort();
// was present disable.dedup();
return None; 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. /// Returns the total number of atoms changed by this diff.

View File

@ -166,7 +166,7 @@ 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 { 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(), selective: Default::default(),
}; };
let (crate_graph, _proc_macros) = let (crate_graph, _proc_macros) =
@ -185,7 +185,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
global: Default::default(), global: Default::default(),
selective: std::iter::once(( selective: std::iter::once((
"libc".to_owned(), "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(), .collect(),
}; };

View File

@ -1522,7 +1522,7 @@ fn extend_crate_graph_with_sysroot(
) -> (SysrootPublicDeps, Option<CrateId>) { ) -> (SysrootPublicDeps, Option<CrateId>) {
let mut pub_deps = vec![]; let mut pub_deps = vec![];
let mut libproc_macro = None; 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() { for (cid, c) in sysroot_crate_graph.iter_mut() {
// uninject `test` flag so `core` keeps working. // uninject `test` flag so `core` keeps working.
Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone()); Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone());
@ -1596,8 +1596,7 @@ fn sysroot_to_crate_graph(
CfgAtom::Flag(sym::miri.clone()), CfgAtom::Flag(sym::miri.clone()),
], ],
vec![], vec![],
) ),
.unwrap(),
..Default::default() ..Default::default()
}, },
&WorkspaceBuildScripts::default(), &WorkspaceBuildScripts::default(),
@ -1620,8 +1619,7 @@ fn sysroot_to_crate_graph(
CfgAtom::Flag(sym::miri.clone()), CfgAtom::Flag(sym::miri.clone()),
], ],
vec![], vec![],
) ),
.unwrap(),
..Default::default() ..Default::default()
}, },
false, false,

View File

@ -69,7 +69,7 @@ impl flags::AnalysisStats {
all_targets: true, all_targets: true,
set_test: !self.no_test, set_test: !self.no_test,
cfg_overrides: CfgOverrides { 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(), selective: Default::default(),
}, },
..Default::default() ..Default::default()

View File

@ -18,7 +18,7 @@ use ide_db::{
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
SnippetCap, SnippetCap,
}; };
use itertools::Itertools; use itertools::{Either, Itertools};
use paths::{Utf8Path, Utf8PathBuf}; use paths::{Utf8Path, Utf8PathBuf};
use project_model::{ use project_model::{
CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand, CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectJsonFromCommand,
@ -589,6 +589,10 @@ config_data! {
/// 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. /// 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> = { cargo_cfgs: Vec<String> = {
vec!["debug_assertions".into(), "miri".into()] vec!["debug_assertions".into(), "miri".into()]
}, },
@ -1980,27 +1984,35 @@ impl Config {
rustc_source, rustc_source,
extra_includes, extra_includes,
cfg_overrides: project_model::CfgOverrides { cfg_overrides: project_model::CfgOverrides {
global: CfgDiff::new( global: {
self.cargo_cfgs(source_root) let (enabled, disabled): (Vec<_>, Vec<_>) =
.iter() self.cargo_cfgs(source_root).iter().partition_map(|s| {
// parse any cfg setting formatted as key=value or just key (without value) s.strip_prefix("!").map_or(Either::Left(s), Either::Right)
.filter_map(|s| { });
let mut sp = s.splitn(2, "="); CfgDiff::new(
let key = sp.next(); enabled
let val = sp.next(); .into_iter()
key.map(|key| (key, val)) // parse any cfg setting formatted as key=value or just key (without value)
}) .map(|s| match s.split_once("=") {
.map(|(key, val)| match val { Some((key, val)) => CfgAtom::KeyValue {
Some(val) => CfgAtom::KeyValue { key: Symbol::intern(key),
key: Symbol::intern(key), value: Symbol::intern(val),
value: Symbol::intern(val), },
}, None => CfgAtom::Flag(Symbol::intern(s)),
None => CfgAtom::Flag(Symbol::intern(key)), })
}) .collect(),
.collect(), disabled
vec![], .into_iter()
) .map(|s| match s.split_once("=") {
.unwrap(), Some((key, val)) => CfgAtom::KeyValue {
key: Symbol::intern(key),
value: Symbol::intern(val),
},
None => CfgAtom::Flag(Symbol::intern(s)),
})
.collect(),
)
},
selective: Default::default(), selective: Default::default(),
}, },
wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(source_root), wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(source_root),

View File

@ -244,8 +244,14 @@ struct FlycheckActor {
/// The receiver side of the channel mentioned above. /// The receiver side of the channel mentioned above.
command_receiver: Option<Receiver<CargoCheckMessage>>, command_receiver: Option<Receiver<CargoCheckMessage>>,
diagnostics_cleared_for: FxHashSet<Arc<PackageId>>, diagnostics_cleared_for: FxHashSet<Arc<PackageId>>,
diagnostics_cleared_for_all: bool, diagnostics_received: DiagnosticsReceived,
diagnostics_received: bool, }
#[derive(PartialEq)]
enum DiagnosticsReceived {
Yes,
No,
YesAndClearedForAll,
} }
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
@ -276,8 +282,7 @@ impl FlycheckActor {
command_handle: None, command_handle: None,
command_receiver: None, command_receiver: None,
diagnostics_cleared_for: Default::default(), diagnostics_cleared_for: Default::default(),
diagnostics_cleared_for_all: false, diagnostics_received: DiagnosticsReceived::No,
diagnostics_received: false,
} }
} }
@ -354,7 +359,7 @@ impl FlycheckActor {
error error
); );
} }
if !self.diagnostics_received { if self.diagnostics_received == DiagnosticsReceived::No {
tracing::trace!(flycheck_id = self.id, "clearing diagnostics"); tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
// We finished without receiving any diagnostics. // We finished without receiving any diagnostics.
// Clear everything for good measure // Clear everything for good measure
@ -396,7 +401,7 @@ impl FlycheckActor {
package_id = package_id.as_ref().map(|it| &it.repr), package_id = package_id.as_ref().map(|it| &it.repr),
"diagnostic received" "diagnostic received"
); );
self.diagnostics_received = true; self.diagnostics_received = DiagnosticsReceived::Yes;
if let Some(package_id) = &package_id { if let Some(package_id) = &package_id {
if self.diagnostics_cleared_for.insert(package_id.clone()) { if self.diagnostics_cleared_for.insert(package_id.clone()) {
tracing::trace!( tracing::trace!(
@ -409,8 +414,10 @@ impl FlycheckActor {
package_id: Some(package_id.clone()), package_id: Some(package_id.clone()),
}); });
} }
} else if !self.diagnostics_cleared_for_all { } else if self.diagnostics_received
self.diagnostics_cleared_for_all = true; != DiagnosticsReceived::YesAndClearedForAll
{
self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll;
self.send(FlycheckMessage::ClearDiagnostics { self.send(FlycheckMessage::ClearDiagnostics {
id: self.id, id: self.id,
package_id: None, package_id: None,
@ -445,8 +452,7 @@ impl FlycheckActor {
fn clear_diagnostics_state(&mut self) { fn clear_diagnostics_state(&mut self) {
self.diagnostics_cleared_for.clear(); self.diagnostics_cleared_for.clear();
self.diagnostics_cleared_for_all = false; self.diagnostics_received = DiagnosticsReceived::No;
self.diagnostics_received = false;
} }
/// Construct a `Command` object for checking the user's code. If the user /// Construct a `Command` object for checking the user's code. If the user

View File

@ -102,6 +102,10 @@ Default:
List of cfg options to enable with the given values. 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: []) **rust-analyzer.cargo.extraArgs** (default: [])

View File

@ -818,7 +818,7 @@
"title": "cargo", "title": "cargo",
"properties": { "properties": {
"rust-analyzer.cargo.cfgs": { "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": [ "default": [
"debug_assertions", "debug_assertions",
"miri" "miri"