From 309abccc87a05d13e88a7a4d6bef692c84547c0d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 8 Jan 2024 09:12:46 -0600 Subject: [PATCH] fix(manifest): Provide unused key warnings for lints table The use of `flatten` was getting in the way of `serde_ignored`. A common workaround is to add our own `unused` tracking but that would cause duplicates with `workspace.lints` (or we'd just ignore it). Since the manual deserializer was relatively simple, I went that route. Fixes #12917 --- crates/cargo-util-schemas/src/manifest.rs | 62 ++++++++++++++++++----- tests/testsuite/lints.rs | 1 + 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/crates/cargo-util-schemas/src/manifest.rs b/crates/cargo-util-schemas/src/manifest.rs index 2c0048d8bad7..c17b47d3c6ff 100644 --- a/crates/cargo-util-schemas/src/manifest.rs +++ b/crates/cargo-util-schemas/src/manifest.rs @@ -437,15 +437,6 @@ impl Default for TomlInheritedField { } } -fn bool_no_false<'de, D: de::Deserializer<'de>>(deserializer: D) -> Result { - let b: bool = Deserialize::deserialize(deserializer)?; - if b { - Ok(b) - } else { - Err(de::Error::custom("`workspace` cannot be false")) - } -} - #[derive(Deserialize, Serialize, Copy, Clone, Debug)] #[serde(try_from = "bool")] #[serde(into = "bool")] @@ -1269,12 +1260,9 @@ impl TomlPlatform { } } -#[derive(Deserialize, Serialize, Debug, Clone)] -#[serde(expecting = "a lints table")] -#[serde(rename_all = "kebab-case")] +#[derive(Serialize, Debug, Clone)] pub struct InheritableLints { #[serde(skip_serializing_if = "is_false")] - #[serde(deserialize_with = "bool_no_false", default)] pub workspace: bool, #[serde(flatten)] pub lints: TomlLints, @@ -1284,6 +1272,54 @@ fn is_false(b: &bool) -> bool { !b } +impl<'de> Deserialize<'de> for InheritableLints { + fn deserialize(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct InheritableLintsVisitor; + + impl<'de> de::Visitor<'de> for InheritableLintsVisitor { + // The type that our Visitor is going to produce. + type Value = InheritableLints; + + // Format a message stating what data this Visitor expects to receive. + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a lints table") + } + + // Deserialize MyMap from an abstract "map" provided by the + // Deserializer. The MapAccess input is a callback provided by + // the Deserializer to let us see each entry in the map. + fn visit_map(self, mut access: M) -> Result + where + M: de::MapAccess<'de>, + { + let mut lints = TomlLints::new(); + let mut workspace = false; + + // While there are entries remaining in the input, add them + // into our map. + while let Some(key) = access.next_key()? { + if key == "workspace" { + workspace = match access.next_value()? { + Some(WorkspaceValue) => true, + None => false, + }; + } else { + let value = access.next_value()?; + lints.insert(key, value); + } + } + + Ok(InheritableLints { workspace, lints }) + } + } + + deserializer.deserialize_map(InheritableLintsVisitor) + } +} + pub type TomlLints = BTreeMap; pub type TomlToolLints = BTreeMap; diff --git a/tests/testsuite/lints.rs b/tests/testsuite/lints.rs index 69ac8fb2db89..980ec0919470 100644 --- a/tests/testsuite/lints.rs +++ b/tests/testsuite/lints.rs @@ -170,6 +170,7 @@ fn warn_on_unused_key() { foo.cargo("check") .with_stderr( "\ +[WARNING] [CWD]/Cargo.toml: unused manifest key: lints.rust.rust-2018-idioms.unused [WARNING] [CWD]/Cargo.toml: unused manifest key: workspace.lints.rust.rust-2018-idioms.unused [CHECKING] foo v0.0.1 ([CWD]) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s