Skip to content
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

Allow unsetting default cfgs #19243

Merged
merged 1 commit into from
Mar 3, 2025
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
19 changes: 19 additions & 0 deletions crates/cfg/src/cfg_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
19 changes: 4 additions & 15 deletions crates/cfg/src/dnf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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 {
Expand Down
20 changes: 12 additions & 8 deletions crates/cfg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions crates/project-model/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) =
Expand All @@ -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(),
};
Expand Down
8 changes: 3 additions & 5 deletions crates/project-model/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1522,7 +1522,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());
Expand Down Expand Up @@ -1596,8 +1596,7 @@ fn sysroot_to_crate_graph(
CfgAtom::Flag(sym::miri.clone()),
],
vec![],
)
.unwrap(),
),
..Default::default()
},
&WorkspaceBuildScripts::default(),
Expand All @@ -1620,8 +1619,7 @@ fn sysroot_to_crate_graph(
CfgAtom::Flag(sym::miri.clone()),
],
vec![],
)
.unwrap(),
),
..Default::default()
},
false,
Expand Down
2 changes: 1 addition & 1 deletion crates/rust-analyzer/src/cli/analysis_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
56 changes: 34 additions & 22 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()]
},
Expand Down Expand Up @@ -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),
Expand Down
26 changes: 16 additions & 10 deletions crates/rust-analyzer/src/flycheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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,
}
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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!(
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions docs/book/src/configuration_generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: [])

Expand Down
2 changes: 1 addition & 1 deletion editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,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"
Expand Down