Use references instead of cloning

This commit is contained in:
2024-11-10 18:39:24 +01:00
parent 9a6b84e080
commit f1f4ea0a47

View File

@@ -77,10 +77,16 @@ impl LintLevel {
} }
} }
#[derive(Clone, Debug, Deserialize)] #[derive(Debug)]
struct Lint<'a> {
id: LintId<'a>,
group: LintGroup,
}
#[derive(Debug, Deserialize)]
#[expect(dead_code, reason = "this is an external data definition")] #[expect(dead_code, reason = "this is an external data definition")]
struct Lint { struct LintResponse {
id: LintId, id: String,
group: LintGroup, group: LintGroup,
#[serde(rename = "level")] #[serde(rename = "level")]
default_level: LintLevel, default_level: LintLevel,
@@ -93,26 +99,41 @@ enum PrioritySetting {
Unspecified, Unspecified,
} }
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] impl From<Option<isize>> for PrioritySetting {
struct LintId(String); fn from(value: Option<isize>) -> Self {
match value {
Some(i) => Self::Explicit(i),
None => Self::Unspecified,
}
}
}
impl fmt::Display for LintId { #[derive(Debug, Deserialize, PartialEq, Eq)]
struct LintId<'a>(&'a str);
impl From<&'static str> for LintId<'static> {
fn from(value: &'static str) -> Self {
Self(value)
}
}
impl fmt::Display for LintId<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0) write!(f, "{}", self.0)
} }
} }
struct LintList(Vec<LintId>); struct LintList<'a>(Vec<LintId<'a>>);
impl From<Vec<&str>> for LintList { impl<'a> From<Vec<&'a str>> for LintList<'a> {
fn from(value: Vec<&str>) -> Self { fn from(value: Vec<&'a str>) -> Self {
Self(value.into_iter().map(|s| LintId(s.to_owned())).collect()) Self(value.into_iter().map(|s| LintId(s)).collect())
} }
} }
#[derive(Debug)] #[derive(Debug)]
struct SingleLintConfig { struct SingleLintConfig<'a> {
lint: LintId, lint: &'a LintId<'a>,
priority: PrioritySetting, priority: PrioritySetting,
level: LintLevel, level: LintLevel,
} }
@@ -125,8 +146,8 @@ struct GroupConfig {
} }
#[derive(Debug)] #[derive(Debug)]
enum Setting { enum Setting<'a> {
Single(SingleLintConfig), Single(SingleLintConfig<'a>),
Group(GroupConfig), Group(GroupConfig),
} }
@@ -137,38 +158,37 @@ enum ExhaustiveGroupClassification {
} }
#[derive(Debug)] #[derive(Debug)]
struct ExhausiveGroup { struct ExhausiveGroup<'a> {
defaults: Vec<Setting>, defaults: Vec<Setting<'a>>,
exceptions: Vec<Setting>, exceptions: Vec<Setting<'a>>,
} }
struct Exceptions { struct Exceptions<'a> {
level: LintLevel, level: LintLevel,
lints: LintList, lints: LintList<'a>,
} }
impl Setting { impl<'a> Setting<'a> {
fn set_group(group: LintGroup, priority: PrioritySetting, level: LintLevel) -> Self { fn group(group: LintGroup, level: LintLevel, priority: impl Into<PrioritySetting>) -> Self {
Self::Group(GroupConfig { Self::Group(GroupConfig {
group, group,
priority, priority: priority.into(),
level, level,
}) })
} }
fn warn_group(group: LintGroup, priority: PrioritySetting) -> Self {
Self::set_group(group, priority, LintLevel::Warn)
}
fn deny_group(group: LintGroup, priority: PrioritySetting) -> Self { fn allow(
Self::set_group(group, priority, LintLevel::Deny) all_lints: &'a AllLints,
} group: LintGroup,
lints: &'a [LintId<'a>],
fn allow(response: &Response, group: LintGroup, lints: &[&str]) -> Result<Vec<Self>> { ) -> Result<Vec<Self>> {
lints lints
.iter() .iter()
.map(|lint| { .map(|lint| {
let lint = LintId((*lint).to_owned()); let found = all_lints
let found = response.0.iter().find(|r| r.id == lint && r.group == group); .0
.iter()
.find(|r| r.id == *lint && r.group == group);
if found.is_none() { if found.is_none() {
Err(anyhow!("lint {} not in group {}", lint, group.as_str())) Err(anyhow!("lint {} not in group {}", lint, group.as_str()))
} else { } else {
@@ -183,37 +203,32 @@ impl Setting {
} }
fn split_group_exhaustive( fn split_group_exhaustive(
response: &Response, all_lints: &'a AllLints,
group: LintGroup, group: LintGroup,
default_level: LintLevel, default_level: LintLevel,
exceptions: &Exceptions, exceptions: &Exceptions<'a>,
) -> Result<ExhausiveGroup> { ) -> Result<ExhausiveGroup<'a>> {
let all_lints_in_group: Vec<LintId> = response let all_lints_in_group: Vec<&LintId> = all_lints
.0 .0
.iter() .iter()
.filter_map(|lint| { .filter(|lint| lint.group == group)
if lint.group == group { .map(|lint| &lint.id)
Some(lint.id.clone())
} else {
None
}
})
.collect(); .collect();
if let Some(err) = exceptions.lints.0.iter().find_map(|lint| { let all_lints_in_group_len = all_lints_in_group.len();
if !all_lints_in_group.contains(lint) {
Some(anyhow!("lint {lint} not part of group {group}")) exceptions
} else { .lints
None .0
} .iter()
}) { .find(|lint| (!all_lints_in_group.contains(lint)))
return Err(err); .map(|lint| Err(anyhow!("lint {lint} not part of group {group}")))
}; .unwrap_or(Ok(()))?;
Ok(all_lints_in_group Ok(all_lints_in_group
.into_iter() .into_iter()
.map(|lint| { .map(|lint| {
if exceptions.lints.0.contains(&lint) { if exceptions.lints.0.contains(lint) {
( (
ExhaustiveGroupClassification::Exception, ExhaustiveGroupClassification::Exception,
Self::Single(SingleLintConfig { Self::Single(SingleLintConfig {
@@ -234,9 +249,16 @@ impl Setting {
} }
}) })
.fold( .fold(
ExhausiveGroup { {
defaults: Vec::new(), let len_1 = exceptions.lints.0.len();
exceptions: Vec::new(), ExhausiveGroup {
defaults: Vec::with_capacity(
all_lints_in_group_len.checked_sub(len_1).expect(
"exceptions are a subset of of all lints in group, checked above",
),
),
exceptions: Vec::with_capacity(len_1),
}
}, },
|mut acc, (classification, setting)| { |mut acc, (classification, setting)| {
match classification { match classification {
@@ -250,15 +272,15 @@ impl Setting {
} }
#[derive(Debug)] #[derive(Debug)]
struct ConfigGroup { struct ConfigGroup<'a> {
comment: Option<String>, comment: Option<String>,
settings: Vec<Setting>, settings: Vec<Setting<'a>>,
} }
#[derive(Debug)] #[derive(Debug)]
struct Config(Vec<ConfigGroup>); struct Config<'a>(Vec<ConfigGroup<'a>>);
impl Config { impl Config<'_> {
fn to_toml(&self, args: &Args) -> String { fn to_toml(&self, args: &Args) -> String {
let mut output = if args.workspace { let mut output = if args.workspace {
String::from("[workspace.lints.clippy]\n") String::from("[workspace.lints.clippy]\n")
@@ -330,17 +352,37 @@ impl Config {
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct Response(Vec<Lint>); struct Response(Vec<LintResponse>);
#[derive(Debug)]
struct AllLints<'a>(Vec<Lint<'a>>);
impl<'a> AllLints<'a> {
fn from_response(response: &'a Response) -> Self {
Self(
response
.0
.iter()
.map(|lint| Lint {
id: LintId(&lint.id),
group: lint.group,
})
.collect(),
)
}
}
fn main() -> Result<()> { fn main() -> Result<()> {
let args = Args::parse(); let args = Args::parse();
let response: Response = ureq::get("https://rust-lang.github.io/rust-clippy/stable/lints.json") let response: Response = ureq::get("https://rust-lang.github.io/rust-clippy/stable/lints.json")
.call()? .call()?
.into_json()?; .into_json::<Response>()?;
let all_lints = AllLints::from_response(&response);
let restriction_group = Setting::split_group_exhaustive( let restriction_group = Setting::split_group_exhaustive(
&response, &all_lints,
LintGroup::Restriction, LintGroup::Restriction,
LintLevel::Allow, LintLevel::Allow,
&Exceptions { &Exceptions {
@@ -429,60 +471,62 @@ fn main() -> Result<()> {
}, },
)?; )?;
let cargo_lints = {
let mut v = vec!["multiple_crate_versions".into()];
match args.profile {
Profile::Publish => (),
Profile::Personal => v.push("cargo_common_metadata".into()),
}
v
};
let pedantic_allows = &[
"too_many_lines".into(),
"must_use_candidate".into(),
"map_unwrap_or".into(),
"missing_errors_doc".into(),
"if_not_else".into(),
];
let nursery_allows = &["missing_const_for_fn".into(), "option_if_let_else".into()];
let complexity_allows = &["too_many_arguments".into()];
let style_allows = &["new_without_default".into(), "redundant_closure".into()];
let config = Config(vec![ let config = Config(vec![
ConfigGroup { ConfigGroup {
comment: Some("enabled groups".to_owned()), comment: Some("enabled groups".to_owned()),
settings: vec![ settings: vec![
Setting::deny_group(LintGroup::Correctness, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Correctness, LintLevel::Deny, Some(-1)),
Setting::warn_group(LintGroup::Suspicious, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Suspicious, LintLevel::Warn, Some(-1)),
Setting::warn_group(LintGroup::Style, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Style, LintLevel::Warn, Some(-1)),
Setting::warn_group(LintGroup::Complexity, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Complexity, LintLevel::Warn, Some(-1)),
Setting::warn_group(LintGroup::Perf, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Perf, LintLevel::Warn, Some(-1)),
Setting::warn_group(LintGroup::Cargo, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Cargo, LintLevel::Warn, Some(-1)),
Setting::warn_group(LintGroup::Pedantic, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Pedantic, LintLevel::Warn, Some(-1)),
Setting::warn_group(LintGroup::Nursery, PrioritySetting::Explicit(-1)), Setting::group(LintGroup::Nursery, LintLevel::Warn, Some(-1)),
], ],
}, },
ConfigGroup { ConfigGroup {
comment: Some("pedantic overrides".to_owned()), comment: Some("pedantic overrides".to_owned()),
settings: Setting::allow( settings: Setting::allow(&all_lints, LintGroup::Pedantic, pedantic_allows)?,
&response,
LintGroup::Pedantic,
&[
"too_many_lines",
"must_use_candidate",
"map_unwrap_or",
"missing_errors_doc",
"if_not_else",
],
)?,
}, },
ConfigGroup { ConfigGroup {
comment: Some("nursery overrides".to_owned()), comment: Some("nursery overrides".to_owned()),
settings: Setting::allow( settings: Setting::allow(&all_lints, LintGroup::Nursery, nursery_allows)?,
&response,
LintGroup::Nursery,
&["missing_const_for_fn", "option_if_let_else"],
)?,
}, },
ConfigGroup { ConfigGroup {
comment: Some("complexity overrides".to_owned()), comment: Some("complexity overrides".to_owned()),
settings: Setting::allow(&response, LintGroup::Complexity, &["too_many_arguments"])?, settings: Setting::allow(&all_lints, LintGroup::Complexity, complexity_allows)?,
}, },
ConfigGroup { ConfigGroup {
comment: Some("style overrides".to_owned()), comment: Some("style overrides".to_owned()),
settings: Setting::allow(&response, LintGroup::Style, &["new_without_default"])?, settings: Setting::allow(&all_lints, LintGroup::Style, style_allows)?,
}, },
ConfigGroup { ConfigGroup {
comment: Some("cargo overrides".to_owned()), comment: Some("cargo overrides".to_owned()),
settings: Setting::allow(&response, LintGroup::Cargo, &{ settings: Setting::allow(&all_lints, LintGroup::Cargo, &cargo_lints)?,
let mut v = vec!["multiple_crate_versions"];
match args.profile {
Profile::Publish => (),
Profile::Personal => v.push("cargo_common_metadata"),
}
v
})?,
}, },
ConfigGroup { ConfigGroup {
comment: Some("selected restrictions".to_owned()), comment: Some("selected restrictions".to_owned()),