-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
[WIP] Configure lints in Cargo.toml #5728
Changes from all commits
d82c203
c53c0cc
5ac592f
286ec71
f4408a1
54ffb7d
e6a64ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
use std::collections::BTreeMap; | ||
use std::collections::HashSet; | ||
use std::str::FromStr; | ||
|
||
use util::{Cfg, CfgExpr, ProcessBuilder}; | ||
use util::errors::CargoResult; | ||
|
||
#[derive(Clone, PartialEq, Debug)] | ||
enum LintKind { | ||
Allow, | ||
Warn, | ||
Deny, | ||
Forbid, | ||
} | ||
|
||
impl LintKind { | ||
pub fn try_from_string(lint_state: &str) -> Option<LintKind> { | ||
match lint_state.as_ref() { | ||
"allow" => Some(LintKind::Allow), | ||
"warn" => Some(LintKind::Warn), | ||
"deny" => Some(LintKind::Deny), | ||
"forbid" => Some(LintKind::Forbid), | ||
_ => None, | ||
} | ||
} | ||
|
||
pub fn flag(&self) -> char { | ||
match self { | ||
LintKind::Allow => 'A', | ||
LintKind::Warn => 'W', | ||
LintKind::Deny => 'D', | ||
LintKind::Forbid => 'F', | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct Lints { | ||
lints: Vec<(String, LintKind)>, | ||
cfg: Option<CfgExpr>, | ||
} | ||
|
||
impl Lints { | ||
pub fn new( | ||
cfg: Option<&String>, | ||
manifest_lints: &BTreeMap<String, String>, | ||
warnings: &mut Vec<String>, | ||
) -> CargoResult<Lints> { | ||
let cfg = if let Some(t) = cfg { | ||
if t.starts_with("cfg(") && t.ends_with(')') { | ||
Some(CfgExpr::from_str(&t[4..t.len() - 1])?) | ||
} else { | ||
bail!("expected `cfg(...)`, found {}", t) | ||
} | ||
} else { | ||
None | ||
}; | ||
|
||
let mut lints = vec![]; | ||
for (lint_name, lint_state) in manifest_lints.iter() { | ||
if let Some(state) = LintKind::try_from_string(lint_state) { | ||
lints.push((lint_name.to_string(), state)); | ||
} else { | ||
warnings.push(format!( | ||
"invalid lint state for `{}` (expected `warn`, `allow`, `deny` or `forbid`)", | ||
lint_name | ||
)); | ||
} | ||
} | ||
Ok(Lints { lints, cfg }) | ||
} | ||
|
||
pub fn set_lint_flags(&self, unit_cfg: &[Cfg], features: &HashSet<String>, cmd: &mut ProcessBuilder) { | ||
match self.cfg { | ||
None => self.set_flags(cmd), | ||
Some(CfgExpr::Value(Cfg::KeyPair(ref key, ref value))) | ||
if key == "feature" && features.contains(value) => self.set_flags(cmd), | ||
Some(ref cfg) if cfg.matches(unit_cfg) => self.set_flags(cmd), | ||
_ => (), | ||
} | ||
} | ||
|
||
fn set_flags(&self, cmd: &mut ProcessBuilder) { | ||
for (lint_name, state) in self.lints.iter() { | ||
cmd.arg(format!("-{}", state.flag())).arg(lint_name); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ use url::Url; | |
|
||
use core::dependency::{Kind, Platform}; | ||
use core::manifest::{LibKind, ManifestMetadata, TargetSourcePath, Warnings}; | ||
use core::lints::Lints; | ||
use core::profiles::Profiles; | ||
use core::{Dependency, Manifest, PackageId, Summary, Target}; | ||
use core::{Edition, EitherManifest, Feature, Features, VirtualManifest}; | ||
|
@@ -240,6 +241,9 @@ pub struct TomlManifest { | |
patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>, | ||
workspace: Option<TomlWorkspace>, | ||
badges: Option<BTreeMap<String, BTreeMap<String, String>>>, | ||
lints: Option<BTreeMap<String, String>>, | ||
#[serde(rename = "lints2")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not entirely clear on what the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I haven't figured out yet how to deserialize both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm ok, I'm not really sure we'd want to support There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, let's simplify to just a |
||
feature_lints: Option<BTreeMap<String, BTreeMap<String, String>>>, | ||
} | ||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)] | ||
|
@@ -748,6 +752,8 @@ impl TomlManifest { | |
workspace: None, | ||
badges: self.badges.clone(), | ||
cargo_features: self.cargo_features.clone(), | ||
lints: self.lints.clone(), | ||
feature_lints: self.feature_lints.clone(), | ||
}); | ||
|
||
fn map_deps( | ||
|
@@ -997,6 +1003,7 @@ impl TomlManifest { | |
), | ||
}; | ||
let profiles = Profiles::new(me.profile.as_ref(), config, &features, &mut warnings)?; | ||
let lints = lints(me.lints.as_ref(), me.feature_lints.as_ref(), &mut warnings)?; | ||
let publish = match project.publish { | ||
Some(VecStringOrBool::VecString(ref vecstring)) => { | ||
features | ||
|
@@ -1035,6 +1042,7 @@ impl TomlManifest { | |
workspace_config, | ||
features, | ||
edition, | ||
lints, | ||
project.im_a_teapot, | ||
project.default_run.clone(), | ||
Rc::clone(me), | ||
|
@@ -1109,6 +1117,7 @@ impl TomlManifest { | |
(me.replace(&mut cx)?, me.patch(&mut cx)?) | ||
}; | ||
let profiles = Profiles::new(me.profile.as_ref(), config, &features, &mut warnings)?; | ||
let lints = lints(me.lints.as_ref(), me.feature_lints.as_ref(), &mut warnings)?; | ||
let workspace_config = match me.workspace { | ||
Some(ref config) => WorkspaceConfig::Root(WorkspaceRootConfig::new( | ||
&root, | ||
|
@@ -1121,7 +1130,7 @@ impl TomlManifest { | |
} | ||
}; | ||
Ok(( | ||
VirtualManifest::new(replace, patch, workspace_config, profiles), | ||
VirtualManifest::new(replace, patch, workspace_config, profiles, lints), | ||
nested_paths, | ||
)) | ||
} | ||
|
@@ -1489,3 +1498,24 @@ impl fmt::Debug for PathValue { | |
self.0.fmt(f) | ||
} | ||
} | ||
|
||
fn lints( | ||
toml_lints: Option<&BTreeMap<String, String>>, | ||
toml_feature_lints: Option<&BTreeMap<String, BTreeMap<String, String>>>, | ||
warnings: &mut Vec<String> | ||
) -> CargoResult<Option<Vec<Lints>>> { | ||
let mut lints = vec![]; | ||
if let Some(toml_lints) = toml_lints { | ||
lints.push(Lints::new(None, toml_lints, warnings)?); | ||
} | ||
if let Some(toml_feature_lints) = toml_feature_lints { | ||
for (ref cfg, ref feature_lints) in toml_feature_lints.iter() { | ||
lints.push(Lints::new(Some(cfg), feature_lints, warnings)?); | ||
} | ||
} | ||
Ok(if !lints.is_empty() { | ||
Some(lints) | ||
} else { | ||
None | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we've already got a number of
#[cfg]
matching functions throughout Cargo, could those be reused here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see one that could be used here, except maybe the
CfgExpr::matches
function that is used in the next line. The way I wrote it seems simpler than wrapping all feature strings insideCfg::KeyPair
, unlessfeature = foo
keypairs can be nested inside otherCfgExpr
's?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll want to funnel everything through
matches
to ensure it's consistently appplied