diff options
Diffstat (limited to 'vendor/serde_derive/src/internals/check.rs')
-rw-r--r-- | vendor/serde_derive/src/internals/check.rs | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/vendor/serde_derive/src/internals/check.rs b/vendor/serde_derive/src/internals/check.rs deleted file mode 100644 index 52b0f37..0000000 --- a/vendor/serde_derive/src/internals/check.rs +++ /dev/null @@ -1,477 +0,0 @@ -use crate::internals::ast::{Container, Data, Field, Style}; -use crate::internals::attr::{Default, Identifier, TagType}; -use crate::internals::{ungroup, Ctxt, Derive}; -use syn::{Member, Type}; - -// Cross-cutting checks that require looking at more than a single attrs object. -// Simpler checks should happen when parsing and building the attrs. -pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { - check_default_on_tuple(cx, cont); - check_remote_generic(cx, cont); - check_getter(cx, cont); - check_flatten(cx, cont); - check_identifier(cx, cont); - check_variant_skip_attrs(cx, cont); - check_internal_tag_field_name_conflict(cx, cont); - check_adjacent_tag_conflict(cx, cont); - check_transparent(cx, cont, derive); - check_from_and_try_from(cx, cont); -} - -// If some field of a tuple struct is marked #[serde(default)] then all fields -// after it must also be marked with that attribute, or the struct must have a -// container-level serde(default) attribute. A field's default value is only -// used for tuple fields if the sequence is exhausted at that point; that means -// all subsequent fields will fail to deserialize if they don't have their own -// default. -fn check_default_on_tuple(cx: &Ctxt, cont: &Container) { - if let Default::None = cont.attrs.default() { - if let Data::Struct(Style::Tuple, fields) = &cont.data { - let mut first_default_index = None; - for (i, field) in fields.iter().enumerate() { - // Skipped fields automatically get the #[serde(default)] - // attribute. We are interested only on non-skipped fields here. - if field.attrs.skip_deserializing() { - continue; - } - if let Default::None = field.attrs.default() { - if let Some(first) = first_default_index { - cx.error_spanned_by( - field.ty, - format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first), - ); - } - continue; - } - if first_default_index.is_none() { - first_default_index = Some(i); - } - } - } - } -} - -// Remote derive definition type must have either all of the generics of the -// remote type: -// -// #[serde(remote = "Generic")] -// struct Generic<T> {…} -// -// or none of them, i.e. defining impls for one concrete instantiation of the -// remote type only: -// -// #[serde(remote = "Generic<T>")] -// struct ConcreteDef {…} -// -fn check_remote_generic(cx: &Ctxt, cont: &Container) { - if let Some(remote) = cont.attrs.remote() { - let local_has_generic = !cont.generics.params.is_empty(); - let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none(); - if local_has_generic && remote_has_generic { - cx.error_spanned_by(remote, "remove generic parameters from this path"); - } - } -} - -// Getters are only allowed inside structs (not enums) with the `remote` -// attribute. -fn check_getter(cx: &Ctxt, cont: &Container) { - match cont.data { - Data::Enum(_) => { - if cont.data.has_getter() { - cx.error_spanned_by( - cont.original, - "#[serde(getter = \"...\")] is not allowed in an enum", - ); - } - } - Data::Struct(_, _) => { - if cont.data.has_getter() && cont.attrs.remote().is_none() { - cx.error_spanned_by( - cont.original, - "#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]", - ); - } - } - } -} - -// Flattening has some restrictions we can test. -fn check_flatten(cx: &Ctxt, cont: &Container) { - match &cont.data { - Data::Enum(variants) => { - for variant in variants { - for field in &variant.fields { - check_flatten_field(cx, variant.style, field); - } - } - } - Data::Struct(style, fields) => { - for field in fields { - check_flatten_field(cx, *style, field); - } - } - } -} - -fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { - if !field.attrs.flatten() { - return; - } - match style { - Style::Tuple => { - cx.error_spanned_by( - field.original, - "#[serde(flatten)] cannot be used on tuple structs", - ); - } - Style::Newtype => { - cx.error_spanned_by( - field.original, - "#[serde(flatten)] cannot be used on newtype structs", - ); - } - _ => {} - } -} - -// The `other` attribute must be used at most once and it must be the last -// variant of an enum. -// -// Inside a `variant_identifier` all variants must be unit variants. Inside a -// `field_identifier` all but possibly one variant must be unit variants. The -// last variant may be a newtype variant which is an implicit "other" case. -fn check_identifier(cx: &Ctxt, cont: &Container) { - let variants = match &cont.data { - Data::Enum(variants) => variants, - Data::Struct(_, _) => return, - }; - - for (i, variant) in variants.iter().enumerate() { - match ( - variant.style, - cont.attrs.identifier(), - variant.attrs.other(), - cont.attrs.tag(), - ) { - // The `other` attribute may not be used in a variant_identifier. - (_, Identifier::Variant, true, _) => { - cx.error_spanned_by( - variant.original, - "#[serde(other)] may not be used on a variant identifier", - ); - } - - // Variant with `other` attribute cannot appear in untagged enum - (_, Identifier::No, true, &TagType::None) => { - cx.error_spanned_by( - variant.original, - "#[serde(other)] cannot appear on untagged enum", - ); - } - - // Variant with `other` attribute must be the last one. - (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => { - if i < variants.len() - 1 { - cx.error_spanned_by( - variant.original, - "#[serde(other)] must be on the last variant", - ); - } - } - - // Variant with `other` attribute must be a unit variant. - (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => { - cx.error_spanned_by( - variant.original, - "#[serde(other)] must be on a unit variant", - ); - } - - // Any sort of variant is allowed if this is not an identifier. - (_, Identifier::No, false, _) => {} - - // Unit variant without `other` attribute is always fine. - (Style::Unit, _, false, _) => {} - - // The last field is allowed to be a newtype catch-all. - (Style::Newtype, Identifier::Field, false, _) => { - if i < variants.len() - 1 { - cx.error_spanned_by( - variant.original, - format!("`{}` must be the last variant", variant.ident), - ); - } - } - - (_, Identifier::Field, false, _) => { - cx.error_spanned_by( - variant.original, - "#[serde(field_identifier)] may only contain unit variants", - ); - } - - (_, Identifier::Variant, false, _) => { - cx.error_spanned_by( - variant.original, - "#[serde(variant_identifier)] may only contain unit variants", - ); - } - } - } -} - -// Skip-(de)serializing attributes are not allowed on variants marked -// (de)serialize_with. -fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { - let variants = match &cont.data { - Data::Enum(variants) => variants, - Data::Struct(_, _) => return, - }; - - for variant in variants { - if variant.attrs.serialize_with().is_some() { - if variant.attrs.skip_serializing() { - cx.error_spanned_by( - variant.original, - format!( - "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]", - variant.ident - ), - ); - } - - for field in &variant.fields { - let member = member_message(&field.member); - - if field.attrs.skip_serializing() { - cx.error_spanned_by( - variant.original, - format!( - "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]", - variant.ident, member - ), - ); - } - - if field.attrs.skip_serializing_if().is_some() { - cx.error_spanned_by( - variant.original, - format!( - "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]", - variant.ident, member - ), - ); - } - } - } - - if variant.attrs.deserialize_with().is_some() { - if variant.attrs.skip_deserializing() { - cx.error_spanned_by( - variant.original, - format!( - "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]", - variant.ident - ), - ); - } - - for field in &variant.fields { - if field.attrs.skip_deserializing() { - let member = member_message(&field.member); - - cx.error_spanned_by( - variant.original, - format!( - "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]", - variant.ident, member - ), - ); - } - } - } - } -} - -// The tag of an internally-tagged struct variant must not be the same as either -// one of its fields, as this would result in duplicate keys in the serialized -// output and/or ambiguity in the to-be-deserialized input. -fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { - let variants = match &cont.data { - Data::Enum(variants) => variants, - Data::Struct(_, _) => return, - }; - - let tag = match cont.attrs.tag() { - TagType::Internal { tag } => tag.as_str(), - TagType::External | TagType::Adjacent { .. } | TagType::None => return, - }; - - let diagnose_conflict = || { - cx.error_spanned_by( - cont.original, - format!("variant field name `{}` conflicts with internal tag", tag), - ); - }; - - for variant in variants { - match variant.style { - Style::Struct => { - if variant.attrs.untagged() { - continue; - } - for field in &variant.fields { - let check_ser = - !(field.attrs.skip_serializing() || variant.attrs.skip_serializing()); - let check_de = - !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing()); - let name = field.attrs.name(); - let ser_name = name.serialize_name(); - - if check_ser && ser_name == tag { - diagnose_conflict(); - return; - } - - for de_name in field.attrs.aliases() { - if check_de && de_name == tag { - diagnose_conflict(); - return; - } - } - } - } - Style::Unit | Style::Newtype | Style::Tuple => {} - } - } -} - -// In the case of adjacently-tagged enums, the type and the contents tag must -// differ, for the same reason. -fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { - let (type_tag, content_tag) = match cont.attrs.tag() { - TagType::Adjacent { tag, content } => (tag, content), - TagType::Internal { .. } | TagType::External | TagType::None => return, - }; - - if type_tag == content_tag { - cx.error_spanned_by( - cont.original, - format!( - "enum tags `{}` for type and content conflict with each other", - type_tag - ), - ); - } -} - -// Enums and unit structs cannot be transparent. -fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { - if !cont.attrs.transparent() { - return; - } - - if cont.attrs.type_from().is_some() { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", - ); - } - - if cont.attrs.type_try_from().is_some() { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]", - ); - } - - if cont.attrs.type_into().is_some() { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", - ); - } - - let fields = match &mut cont.data { - Data::Enum(_) => { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] is not allowed on an enum", - ); - return; - } - Data::Struct(Style::Unit, _) => { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] is not allowed on a unit struct", - ); - return; - } - Data::Struct(_, fields) => fields, - }; - - let mut transparent_field = None; - - for field in fields { - if allow_transparent(field, derive) { - if transparent_field.is_some() { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] requires struct to have at most one transparent field", - ); - return; - } - transparent_field = Some(field); - } - } - - match transparent_field { - Some(transparent_field) => transparent_field.attrs.mark_transparent(), - None => match derive { - Derive::Serialize => { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] requires at least one field that is not skipped", - ); - } - Derive::Deserialize => { - cx.error_spanned_by( - cont.original, - "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", - ); - } - }, - } -} - -fn member_message(member: &Member) -> String { - match member { - Member::Named(ident) => format!("`{}`", ident), - Member::Unnamed(i) => format!("#{}", i.index), - } -} - -fn allow_transparent(field: &Field, derive: Derive) -> bool { - if let Type::Path(ty) = ungroup(field.ty) { - if let Some(seg) = ty.path.segments.last() { - if seg.ident == "PhantomData" { - return false; - } - } - } - - match derive { - Derive::Serialize => !field.attrs.skip_serializing(), - Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), - } -} - -fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) { - if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() { - cx.error_spanned_by( - cont.original, - "#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other", - ); - } -} |