Skip to content

Commit 540a052

Browse files
committed
feat: Parse [lints] table on nightly
1 parent 1e5a797 commit 540a052

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

src/cargo/util/toml/mod.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ pub struct TomlManifest {
355355
patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>,
356356
workspace: Option<TomlWorkspace>,
357357
badges: Option<MaybeWorkspaceBtreeMap>,
358+
lints: Option<MaybeWorkspaceLints>,
358359
}
359360

360361
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
@@ -1421,6 +1422,29 @@ impl<'de> de::Deserialize<'de> for MaybeWorkspaceBtreeMap {
14211422
}
14221423
}
14231424

1425+
type MaybeWorkspaceLints = MaybeWorkspace<TomlLints, TomlWorkspaceField>;
1426+
1427+
impl<'de> de::Deserialize<'de> for MaybeWorkspaceLints {
1428+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1429+
where
1430+
D: de::Deserializer<'de>,
1431+
{
1432+
let value = serde_value::Value::deserialize(deserializer)?;
1433+
1434+
if let Ok(w) = TomlWorkspaceField::deserialize(
1435+
serde_value::ValueDeserializer::<D::Error>::new(value.clone()),
1436+
) {
1437+
return if w.workspace() {
1438+
Ok(MaybeWorkspace::Workspace(w))
1439+
} else {
1440+
Err(de::Error::custom("`workspace` cannot be false"))
1441+
};
1442+
}
1443+
BTreeMap::deserialize(serde_value::ValueDeserializer::<D::Error>::new(value))
1444+
.map(MaybeWorkspace::Defined)
1445+
}
1446+
}
1447+
14241448
#[derive(Deserialize, Serialize, Clone, Debug)]
14251449
pub struct TomlWorkspaceField {
14261450
#[serde(deserialize_with = "bool_no_false")]
@@ -1507,6 +1531,7 @@ pub struct TomlWorkspace {
15071531
// Properties that can be inherited by members.
15081532
package: Option<InheritableFields>,
15091533
dependencies: Option<BTreeMap<String, TomlDependency>>,
1534+
lints: Option<TomlLints>,
15101535

15111536
// Note that this field must come last due to the way toml serialization
15121537
// works which requires tables to be emitted after all values.
@@ -1520,6 +1545,9 @@ pub struct InheritableFields {
15201545
// and we don't want it present when serializing
15211546
#[serde(skip)]
15221547
dependencies: Option<BTreeMap<String, TomlDependency>>,
1548+
#[serde(skip)]
1549+
lints: Option<TomlLints>,
1550+
15231551
version: Option<semver::Version>,
15241552
authors: Option<Vec<String>>,
15251553
description: Option<String>,
@@ -1550,6 +1578,10 @@ impl InheritableFields {
15501578
self.dependencies = deps;
15511579
}
15521580

1581+
pub fn update_lints(&mut self, lints: Option<TomlLints>) {
1582+
self.lints = lints;
1583+
}
1584+
15531585
pub fn update_ws_path(&mut self, ws_root: PathBuf) {
15541586
self.ws_root = ws_root;
15551587
}
@@ -1561,6 +1593,12 @@ impl InheritableFields {
15611593
)
15621594
}
15631595

1596+
pub fn lints(&self) -> CargoResult<TomlLints> {
1597+
self.lints
1598+
.clone()
1599+
.map_or(Err(anyhow!("`workspace.lints` was not defined")), |d| Ok(d))
1600+
}
1601+
15641602
pub fn get_dependency(&self, name: &str, package_root: &Path) -> CargoResult<TomlDependency> {
15651603
self.dependencies.clone().map_or(
15661604
Err(anyhow!("`workspace.dependencies` was not defined")),
@@ -1878,6 +1916,7 @@ impl TomlManifest {
18781916
workspace: None,
18791917
badges: self.badges.clone(),
18801918
cargo_features: self.cargo_features.clone(),
1919+
lints: self.lints.clone(),
18811920
});
18821921

18831922
fn map_deps(
@@ -2006,6 +2045,8 @@ impl TomlManifest {
20062045
let mut inheritable = toml_config.package.clone().unwrap_or_default();
20072046
inheritable.update_ws_path(package_root.to_path_buf());
20082047
inheritable.update_deps(toml_config.dependencies.clone());
2048+
verify_lints(toml_config.lints.as_ref(), &features)?;
2049+
inheritable.update_lints(toml_config.lints.clone());
20092050
if let Some(ws_deps) = &inheritable.dependencies {
20102051
for (name, dep) in ws_deps {
20112052
unused_dep_keys(
@@ -2269,6 +2310,13 @@ impl TomlManifest {
22692310
&inherit_cell,
22702311
)?;
22712312

2313+
let lints = me
2314+
.lints
2315+
.clone()
2316+
.map(|mw| mw.resolve("lints", || inherit()?.lints()))
2317+
.transpose()?;
2318+
verify_lints(lints.as_ref(), &features)?;
2319+
22722320
let mut target: BTreeMap<String, TomlPlatform> = BTreeMap::new();
22732321
for (name, platform) in me.target.iter().flatten() {
22742322
cx.platform = {
@@ -2566,6 +2614,7 @@ impl TomlManifest {
25662614
.badges
25672615
.as_ref()
25682616
.map(|_| MaybeWorkspace::Defined(metadata.badges.clone())),
2617+
lints: lints.map(|lints| MaybeWorkspace::Defined(lints)),
25692618
};
25702619
let mut manifest = Manifest::new(
25712620
summary,
@@ -2695,6 +2744,8 @@ impl TomlManifest {
26952744
let mut inheritable = toml_config.package.clone().unwrap_or_default();
26962745
inheritable.update_ws_path(root.to_path_buf());
26972746
inheritable.update_deps(toml_config.dependencies.clone());
2747+
verify_lints(toml_config.lints.as_ref(), &features)?;
2748+
inheritable.update_lints(toml_config.lints.clone());
26982749
let ws_root_config = WorkspaceRootConfig::new(
26992750
root,
27002751
&toml_config.members,
@@ -2839,6 +2890,16 @@ impl TomlManifest {
28392890
}
28402891
}
28412892

2893+
fn verify_lints(lints: Option<&TomlLints>, features: &Features) -> CargoResult<()> {
2894+
if lints.is_none() {
2895+
return Ok(());
2896+
};
2897+
2898+
features.require(Feature::lints())?;
2899+
2900+
Ok(())
2901+
}
2902+
28422903
fn unused_dep_keys(
28432904
dep_name: &str,
28442905
kind: &str,
@@ -3396,3 +3457,31 @@ impl fmt::Debug for PathValue {
33963457
self.0.fmt(f)
33973458
}
33983459
}
3460+
3461+
pub type TomlLints = BTreeMap<String, TomlToolLints>;
3462+
3463+
pub type TomlToolLints = BTreeMap<String, TomlLint>;
3464+
3465+
#[derive(Serialize, Deserialize, Debug, Clone)]
3466+
#[serde(untagged)]
3467+
pub enum TomlLint {
3468+
Level(TomlLintLevel),
3469+
Config(TomlLintConfig),
3470+
}
3471+
3472+
#[derive(Serialize, Deserialize, Debug, Clone)]
3473+
#[serde(rename_all = "kebab-case")]
3474+
pub struct TomlLintConfig {
3475+
level: TomlLintLevel,
3476+
#[serde(default)]
3477+
priority: i8,
3478+
}
3479+
3480+
#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
3481+
#[serde(rename_all = "kebab-case")]
3482+
pub enum TomlLintLevel {
3483+
Forbid,
3484+
Deny,
3485+
Warn,
3486+
Allow,
3487+
}

tests/testsuite/lints.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//! Tests for `[lints]`
2+
3+
use cargo_test_support::project;
4+
5+
#[cargo_test]
6+
fn package_requires_option() {
7+
let foo = project()
8+
.file(
9+
"Cargo.toml",
10+
r#"
11+
[package]
12+
name = "foo"
13+
version = "0.0.1"
14+
authors = []
15+
16+
[lints.rust]
17+
unsafe_code = "forbid"
18+
"#,
19+
)
20+
.file("src/lib.rs", "")
21+
.build();
22+
23+
foo.cargo("check")
24+
.with_status(101)
25+
.with_stderr("\
26+
[..]
27+
28+
Caused by:
29+
feature `lints` is required
30+
31+
The package requires the Cargo feature called `lints`, but that feature is not stabilized in this version of Cargo ([..]).
32+
Consider trying a newer version of Cargo (this may require the nightly release).
33+
See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#lints for more information about the status of this feature.
34+
")
35+
.run();
36+
}
37+
38+
#[cargo_test]
39+
fn workspace_requires_option() {
40+
let foo = project()
41+
.file(
42+
"Cargo.toml",
43+
r#"
44+
[package]
45+
name = "foo"
46+
version = "0.0.1"
47+
authors = []
48+
49+
[workspace.lints.rust]
50+
unsafe_code = "forbid"
51+
"#,
52+
)
53+
.file("src/lib.rs", "")
54+
.build();
55+
56+
foo.cargo("check")
57+
.with_status(101)
58+
.with_stderr("\
59+
[..]
60+
61+
Caused by:
62+
feature `lints` is required
63+
64+
The package requires the Cargo feature called `lints`, but that feature is not stabilized in this version of Cargo ([..]).
65+
Consider trying a newer version of Cargo (this may require the nightly release).
66+
See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#lints for more information about the status of this feature.
67+
")
68+
.run();
69+
}

tests/testsuite/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ mod init;
6868
mod install;
6969
mod install_upgrade;
7070
mod jobserver;
71+
mod lints;
7172
mod list_availables;
7273
mod local_registry;
7374
mod locate_project;

0 commit comments

Comments
 (0)