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

Error on duplicate fields in fields and variants #130

Merged
merged 1 commit into from
Apr 20, 2021
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
39 changes: 31 additions & 8 deletions core/src/options/input_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ pub struct InputField {

/// If `true`, generated code will not look for this field in the input meta item,
/// instead always falling back to either `InputField::default` or `Default::default`.
pub skip: bool,
pub skip: Option<bool>,
pub post_transform: Option<codegen::PostfixTransform>,
pub multiple: bool,
pub multiple: Option<bool>,
}

impl InputField {
Expand All @@ -34,9 +34,9 @@ impl InputField {
|| Cow::Owned(parse_quote!(::darling::FromMeta::from_meta)),
Cow::Borrowed,
),
skip: self.skip,
skip: self.skip.unwrap_or_default(),
post_transform: self.post_transform.as_ref(),
multiple: self.multiple,
multiple: self.multiple.unwrap_or_default(),
}
}

Expand All @@ -57,9 +57,9 @@ impl InputField {
attr_name: None,
default: None,
with: None,
skip: false,
skip: None,
post_transform: Default::default(),
multiple: false,
multiple: None,
}
}

Expand Down Expand Up @@ -91,7 +91,11 @@ impl InputField {
// 1. Will we look for this field in the attribute?
// 1. Is there a locally-defined default?
// 1. Did the parent define a default?
self.default = match (self.skip, self.default.is_some(), parent.default.is_some()) {
self.default = match (
self.skip.unwrap_or_default(),
self.default.is_some(),
parent.default.is_some(),
) {
// If we have a default, use it.
(_, true, _) => self.default,

Expand All @@ -116,18 +120,33 @@ impl ParseAttribute for InputField {
let path = mi.path();

if path.is_ident("rename") {
if self.attr_name.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}

self.attr_name = FromMeta::from_meta(mi)?;
} else if path.is_ident("default") {
if self.default.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}
self.default = FromMeta::from_meta(mi)?;
} else if path.is_ident("with") {
if self.with.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}

self.with = Some(FromMeta::from_meta(mi)?);
} else if path.is_ident("skip") {
if self.skip.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}

self.skip = FromMeta::from_meta(mi)?;
} else if path.is_ident("map") || path.is_ident("and_then") {
let transformer = path.get_ident().unwrap().clone();
if let Some(post_transform) = &self.post_transform {
if transformer == post_transform.transformer {
return Err(Error::duplicate_field(&transformer.to_string()).with_span(mi));
return Err(Error::duplicate_field_path(path).with_span(mi));
} else {
return Err(Error::custom(format!(
"Options `{}` and `{}` are mutually exclusive",
Expand All @@ -142,6 +161,10 @@ impl ParseAttribute for InputField {
FromMeta::from_meta(mi)?,
));
} else if path.is_ident("multiple") {
if self.multiple.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}

self.multiple = FromMeta::from_meta(mi)?;
} else {
return Err(Error::unknown_field_path(path).with_span(mi));
Expand Down
18 changes: 13 additions & 5 deletions core/src/options/input_variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct InputVariant {
ident: syn::Ident,
attr_name: Option<String>,
data: Fields<InputField>,
skip: bool,
skip: Option<bool>,
/// Whether or not unknown fields are acceptable in this
allow_unknown_fields: Option<bool>,
}
Expand All @@ -25,7 +25,7 @@ impl InputVariant {
.as_ref()
.map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed),
data: self.data.as_ref().map(InputField::as_codegen_field),
skip: self.skip,
skip: self.skip.unwrap_or_default(),
allow_unknown_fields: self.allow_unknown_fields.unwrap_or_default(),
}
}
Expand Down Expand Up @@ -84,13 +84,21 @@ impl ParseAttribute for InputVariant {
fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
let path = mi.path();
if path.is_ident("rename") {
if self.attr_name.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}

self.attr_name = FromMeta::from_meta(mi)?;
Ok(())
} else if path.is_ident("skip") {
if self.skip.is_some() {
return Err(Error::duplicate_field_path(path).with_span(mi));
}

self.skip = FromMeta::from_meta(mi)?;
Ok(())
} else {
Err(Error::unknown_field_path(&path).with_span(mi))
return Err(Error::unknown_field_path(&path).with_span(mi));
}

Ok(())
}
}