17e2e9c0cSopenharmony_ciuse crate::internals::ast::{Container, Data, Field, Style};
27e2e9c0cSopenharmony_ciuse crate::internals::attr::{Default, Identifier, TagType};
37e2e9c0cSopenharmony_ciuse crate::internals::{ungroup, Ctxt, Derive};
47e2e9c0cSopenharmony_ciuse syn::{Member, Type};
57e2e9c0cSopenharmony_ci
67e2e9c0cSopenharmony_ci// Cross-cutting checks that require looking at more than a single attrs object.
77e2e9c0cSopenharmony_ci// Simpler checks should happen when parsing and building the attrs.
87e2e9c0cSopenharmony_cipub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
97e2e9c0cSopenharmony_ci    check_default_on_tuple(cx, cont);
107e2e9c0cSopenharmony_ci    check_remote_generic(cx, cont);
117e2e9c0cSopenharmony_ci    check_getter(cx, cont);
127e2e9c0cSopenharmony_ci    check_flatten(cx, cont);
137e2e9c0cSopenharmony_ci    check_identifier(cx, cont);
147e2e9c0cSopenharmony_ci    check_variant_skip_attrs(cx, cont);
157e2e9c0cSopenharmony_ci    check_internal_tag_field_name_conflict(cx, cont);
167e2e9c0cSopenharmony_ci    check_adjacent_tag_conflict(cx, cont);
177e2e9c0cSopenharmony_ci    check_transparent(cx, cont, derive);
187e2e9c0cSopenharmony_ci    check_from_and_try_from(cx, cont);
197e2e9c0cSopenharmony_ci}
207e2e9c0cSopenharmony_ci
217e2e9c0cSopenharmony_ci// If some field of a tuple struct is marked #[serde(default)] then all fields
227e2e9c0cSopenharmony_ci// after it must also be marked with that attribute, or the struct must have a
237e2e9c0cSopenharmony_ci// container-level serde(default) attribute. A field's default value is only
247e2e9c0cSopenharmony_ci// used for tuple fields if the sequence is exhausted at that point; that means
257e2e9c0cSopenharmony_ci// all subsequent fields will fail to deserialize if they don't have their own
267e2e9c0cSopenharmony_ci// default.
277e2e9c0cSopenharmony_cifn check_default_on_tuple(cx: &Ctxt, cont: &Container) {
287e2e9c0cSopenharmony_ci    if let Default::None = cont.attrs.default() {
297e2e9c0cSopenharmony_ci        if let Data::Struct(Style::Tuple, fields) = &cont.data {
307e2e9c0cSopenharmony_ci            let mut first_default_index = None;
317e2e9c0cSopenharmony_ci            for (i, field) in fields.iter().enumerate() {
327e2e9c0cSopenharmony_ci                // Skipped fields automatically get the #[serde(default)]
337e2e9c0cSopenharmony_ci                // attribute. We are interested only on non-skipped fields here.
347e2e9c0cSopenharmony_ci                if field.attrs.skip_deserializing() {
357e2e9c0cSopenharmony_ci                    continue;
367e2e9c0cSopenharmony_ci                }
377e2e9c0cSopenharmony_ci                if let Default::None = field.attrs.default() {
387e2e9c0cSopenharmony_ci                    if let Some(first) = first_default_index {
397e2e9c0cSopenharmony_ci                        cx.error_spanned_by(
407e2e9c0cSopenharmony_ci                            field.ty,
417e2e9c0cSopenharmony_ci                            format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first),
427e2e9c0cSopenharmony_ci                        );
437e2e9c0cSopenharmony_ci                    }
447e2e9c0cSopenharmony_ci                    continue;
457e2e9c0cSopenharmony_ci                }
467e2e9c0cSopenharmony_ci                if first_default_index.is_none() {
477e2e9c0cSopenharmony_ci                    first_default_index = Some(i);
487e2e9c0cSopenharmony_ci                }
497e2e9c0cSopenharmony_ci            }
507e2e9c0cSopenharmony_ci        }
517e2e9c0cSopenharmony_ci    }
527e2e9c0cSopenharmony_ci}
537e2e9c0cSopenharmony_ci
547e2e9c0cSopenharmony_ci// Remote derive definition type must have either all of the generics of the
557e2e9c0cSopenharmony_ci// remote type:
567e2e9c0cSopenharmony_ci//
577e2e9c0cSopenharmony_ci//     #[serde(remote = "Generic")]
587e2e9c0cSopenharmony_ci//     struct Generic<T> {…}
597e2e9c0cSopenharmony_ci//
607e2e9c0cSopenharmony_ci// or none of them, i.e. defining impls for one concrete instantiation of the
617e2e9c0cSopenharmony_ci// remote type only:
627e2e9c0cSopenharmony_ci//
637e2e9c0cSopenharmony_ci//     #[serde(remote = "Generic<T>")]
647e2e9c0cSopenharmony_ci//     struct ConcreteDef {…}
657e2e9c0cSopenharmony_ci//
667e2e9c0cSopenharmony_cifn check_remote_generic(cx: &Ctxt, cont: &Container) {
677e2e9c0cSopenharmony_ci    if let Some(remote) = cont.attrs.remote() {
687e2e9c0cSopenharmony_ci        let local_has_generic = !cont.generics.params.is_empty();
697e2e9c0cSopenharmony_ci        let remote_has_generic = !remote.segments.last().unwrap().arguments.is_none();
707e2e9c0cSopenharmony_ci        if local_has_generic && remote_has_generic {
717e2e9c0cSopenharmony_ci            cx.error_spanned_by(remote, "remove generic parameters from this path");
727e2e9c0cSopenharmony_ci        }
737e2e9c0cSopenharmony_ci    }
747e2e9c0cSopenharmony_ci}
757e2e9c0cSopenharmony_ci
767e2e9c0cSopenharmony_ci// Getters are only allowed inside structs (not enums) with the `remote`
777e2e9c0cSopenharmony_ci// attribute.
787e2e9c0cSopenharmony_cifn check_getter(cx: &Ctxt, cont: &Container) {
797e2e9c0cSopenharmony_ci    match cont.data {
807e2e9c0cSopenharmony_ci        Data::Enum(_) => {
817e2e9c0cSopenharmony_ci            if cont.data.has_getter() {
827e2e9c0cSopenharmony_ci                cx.error_spanned_by(
837e2e9c0cSopenharmony_ci                    cont.original,
847e2e9c0cSopenharmony_ci                    "#[serde(getter = \"...\")] is not allowed in an enum",
857e2e9c0cSopenharmony_ci                );
867e2e9c0cSopenharmony_ci            }
877e2e9c0cSopenharmony_ci        }
887e2e9c0cSopenharmony_ci        Data::Struct(_, _) => {
897e2e9c0cSopenharmony_ci            if cont.data.has_getter() && cont.attrs.remote().is_none() {
907e2e9c0cSopenharmony_ci                cx.error_spanned_by(
917e2e9c0cSopenharmony_ci                    cont.original,
927e2e9c0cSopenharmony_ci                    "#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]",
937e2e9c0cSopenharmony_ci                );
947e2e9c0cSopenharmony_ci            }
957e2e9c0cSopenharmony_ci        }
967e2e9c0cSopenharmony_ci    }
977e2e9c0cSopenharmony_ci}
987e2e9c0cSopenharmony_ci
997e2e9c0cSopenharmony_ci// Flattening has some restrictions we can test.
1007e2e9c0cSopenharmony_cifn check_flatten(cx: &Ctxt, cont: &Container) {
1017e2e9c0cSopenharmony_ci    match &cont.data {
1027e2e9c0cSopenharmony_ci        Data::Enum(variants) => {
1037e2e9c0cSopenharmony_ci            for variant in variants {
1047e2e9c0cSopenharmony_ci                for field in &variant.fields {
1057e2e9c0cSopenharmony_ci                    check_flatten_field(cx, variant.style, field);
1067e2e9c0cSopenharmony_ci                }
1077e2e9c0cSopenharmony_ci            }
1087e2e9c0cSopenharmony_ci        }
1097e2e9c0cSopenharmony_ci        Data::Struct(style, fields) => {
1107e2e9c0cSopenharmony_ci            for field in fields {
1117e2e9c0cSopenharmony_ci                check_flatten_field(cx, *style, field);
1127e2e9c0cSopenharmony_ci            }
1137e2e9c0cSopenharmony_ci        }
1147e2e9c0cSopenharmony_ci    }
1157e2e9c0cSopenharmony_ci}
1167e2e9c0cSopenharmony_ci
1177e2e9c0cSopenharmony_cifn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
1187e2e9c0cSopenharmony_ci    if !field.attrs.flatten() {
1197e2e9c0cSopenharmony_ci        return;
1207e2e9c0cSopenharmony_ci    }
1217e2e9c0cSopenharmony_ci    match style {
1227e2e9c0cSopenharmony_ci        Style::Tuple => {
1237e2e9c0cSopenharmony_ci            cx.error_spanned_by(
1247e2e9c0cSopenharmony_ci                field.original,
1257e2e9c0cSopenharmony_ci                "#[serde(flatten)] cannot be used on tuple structs",
1267e2e9c0cSopenharmony_ci            );
1277e2e9c0cSopenharmony_ci        }
1287e2e9c0cSopenharmony_ci        Style::Newtype => {
1297e2e9c0cSopenharmony_ci            cx.error_spanned_by(
1307e2e9c0cSopenharmony_ci                field.original,
1317e2e9c0cSopenharmony_ci                "#[serde(flatten)] cannot be used on newtype structs",
1327e2e9c0cSopenharmony_ci            );
1337e2e9c0cSopenharmony_ci        }
1347e2e9c0cSopenharmony_ci        _ => {}
1357e2e9c0cSopenharmony_ci    }
1367e2e9c0cSopenharmony_ci}
1377e2e9c0cSopenharmony_ci
1387e2e9c0cSopenharmony_ci// The `other` attribute must be used at most once and it must be the last
1397e2e9c0cSopenharmony_ci// variant of an enum.
1407e2e9c0cSopenharmony_ci//
1417e2e9c0cSopenharmony_ci// Inside a `variant_identifier` all variants must be unit variants. Inside a
1427e2e9c0cSopenharmony_ci// `field_identifier` all but possibly one variant must be unit variants. The
1437e2e9c0cSopenharmony_ci// last variant may be a newtype variant which is an implicit "other" case.
1447e2e9c0cSopenharmony_cifn check_identifier(cx: &Ctxt, cont: &Container) {
1457e2e9c0cSopenharmony_ci    let variants = match &cont.data {
1467e2e9c0cSopenharmony_ci        Data::Enum(variants) => variants,
1477e2e9c0cSopenharmony_ci        Data::Struct(_, _) => return,
1487e2e9c0cSopenharmony_ci    };
1497e2e9c0cSopenharmony_ci
1507e2e9c0cSopenharmony_ci    for (i, variant) in variants.iter().enumerate() {
1517e2e9c0cSopenharmony_ci        match (
1527e2e9c0cSopenharmony_ci            variant.style,
1537e2e9c0cSopenharmony_ci            cont.attrs.identifier(),
1547e2e9c0cSopenharmony_ci            variant.attrs.other(),
1557e2e9c0cSopenharmony_ci            cont.attrs.tag(),
1567e2e9c0cSopenharmony_ci        ) {
1577e2e9c0cSopenharmony_ci            // The `other` attribute may not be used in a variant_identifier.
1587e2e9c0cSopenharmony_ci            (_, Identifier::Variant, true, _) => {
1597e2e9c0cSopenharmony_ci                cx.error_spanned_by(
1607e2e9c0cSopenharmony_ci                    variant.original,
1617e2e9c0cSopenharmony_ci                    "#[serde(other)] may not be used on a variant identifier",
1627e2e9c0cSopenharmony_ci                );
1637e2e9c0cSopenharmony_ci            }
1647e2e9c0cSopenharmony_ci
1657e2e9c0cSopenharmony_ci            // Variant with `other` attribute cannot appear in untagged enum
1667e2e9c0cSopenharmony_ci            (_, Identifier::No, true, &TagType::None) => {
1677e2e9c0cSopenharmony_ci                cx.error_spanned_by(
1687e2e9c0cSopenharmony_ci                    variant.original,
1697e2e9c0cSopenharmony_ci                    "#[serde(other)] cannot appear on untagged enum",
1707e2e9c0cSopenharmony_ci                );
1717e2e9c0cSopenharmony_ci            }
1727e2e9c0cSopenharmony_ci
1737e2e9c0cSopenharmony_ci            // Variant with `other` attribute must be the last one.
1747e2e9c0cSopenharmony_ci            (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => {
1757e2e9c0cSopenharmony_ci                if i < variants.len() - 1 {
1767e2e9c0cSopenharmony_ci                    cx.error_spanned_by(
1777e2e9c0cSopenharmony_ci                        variant.original,
1787e2e9c0cSopenharmony_ci                        "#[serde(other)] must be on the last variant",
1797e2e9c0cSopenharmony_ci                    );
1807e2e9c0cSopenharmony_ci                }
1817e2e9c0cSopenharmony_ci            }
1827e2e9c0cSopenharmony_ci
1837e2e9c0cSopenharmony_ci            // Variant with `other` attribute must be a unit variant.
1847e2e9c0cSopenharmony_ci            (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => {
1857e2e9c0cSopenharmony_ci                cx.error_spanned_by(
1867e2e9c0cSopenharmony_ci                    variant.original,
1877e2e9c0cSopenharmony_ci                    "#[serde(other)] must be on a unit variant",
1887e2e9c0cSopenharmony_ci                );
1897e2e9c0cSopenharmony_ci            }
1907e2e9c0cSopenharmony_ci
1917e2e9c0cSopenharmony_ci            // Any sort of variant is allowed if this is not an identifier.
1927e2e9c0cSopenharmony_ci            (_, Identifier::No, false, _) => {}
1937e2e9c0cSopenharmony_ci
1947e2e9c0cSopenharmony_ci            // Unit variant without `other` attribute is always fine.
1957e2e9c0cSopenharmony_ci            (Style::Unit, _, false, _) => {}
1967e2e9c0cSopenharmony_ci
1977e2e9c0cSopenharmony_ci            // The last field is allowed to be a newtype catch-all.
1987e2e9c0cSopenharmony_ci            (Style::Newtype, Identifier::Field, false, _) => {
1997e2e9c0cSopenharmony_ci                if i < variants.len() - 1 {
2007e2e9c0cSopenharmony_ci                    cx.error_spanned_by(
2017e2e9c0cSopenharmony_ci                        variant.original,
2027e2e9c0cSopenharmony_ci                        format!("`{}` must be the last variant", variant.ident),
2037e2e9c0cSopenharmony_ci                    );
2047e2e9c0cSopenharmony_ci                }
2057e2e9c0cSopenharmony_ci            }
2067e2e9c0cSopenharmony_ci
2077e2e9c0cSopenharmony_ci            (_, Identifier::Field, false, _) => {
2087e2e9c0cSopenharmony_ci                cx.error_spanned_by(
2097e2e9c0cSopenharmony_ci                    variant.original,
2107e2e9c0cSopenharmony_ci                    "#[serde(field_identifier)] may only contain unit variants",
2117e2e9c0cSopenharmony_ci                );
2127e2e9c0cSopenharmony_ci            }
2137e2e9c0cSopenharmony_ci
2147e2e9c0cSopenharmony_ci            (_, Identifier::Variant, false, _) => {
2157e2e9c0cSopenharmony_ci                cx.error_spanned_by(
2167e2e9c0cSopenharmony_ci                    variant.original,
2177e2e9c0cSopenharmony_ci                    "#[serde(variant_identifier)] may only contain unit variants",
2187e2e9c0cSopenharmony_ci                );
2197e2e9c0cSopenharmony_ci            }
2207e2e9c0cSopenharmony_ci        }
2217e2e9c0cSopenharmony_ci    }
2227e2e9c0cSopenharmony_ci}
2237e2e9c0cSopenharmony_ci
2247e2e9c0cSopenharmony_ci// Skip-(de)serializing attributes are not allowed on variants marked
2257e2e9c0cSopenharmony_ci// (de)serialize_with.
2267e2e9c0cSopenharmony_cifn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
2277e2e9c0cSopenharmony_ci    let variants = match &cont.data {
2287e2e9c0cSopenharmony_ci        Data::Enum(variants) => variants,
2297e2e9c0cSopenharmony_ci        Data::Struct(_, _) => return,
2307e2e9c0cSopenharmony_ci    };
2317e2e9c0cSopenharmony_ci
2327e2e9c0cSopenharmony_ci    for variant in variants {
2337e2e9c0cSopenharmony_ci        if variant.attrs.serialize_with().is_some() {
2347e2e9c0cSopenharmony_ci            if variant.attrs.skip_serializing() {
2357e2e9c0cSopenharmony_ci                cx.error_spanned_by(
2367e2e9c0cSopenharmony_ci                    variant.original,
2377e2e9c0cSopenharmony_ci                    format!(
2387e2e9c0cSopenharmony_ci                        "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]",
2397e2e9c0cSopenharmony_ci                        variant.ident
2407e2e9c0cSopenharmony_ci                    ),
2417e2e9c0cSopenharmony_ci                );
2427e2e9c0cSopenharmony_ci            }
2437e2e9c0cSopenharmony_ci
2447e2e9c0cSopenharmony_ci            for field in &variant.fields {
2457e2e9c0cSopenharmony_ci                let member = member_message(&field.member);
2467e2e9c0cSopenharmony_ci
2477e2e9c0cSopenharmony_ci                if field.attrs.skip_serializing() {
2487e2e9c0cSopenharmony_ci                    cx.error_spanned_by(
2497e2e9c0cSopenharmony_ci                        variant.original,
2507e2e9c0cSopenharmony_ci                        format!(
2517e2e9c0cSopenharmony_ci                            "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]",
2527e2e9c0cSopenharmony_ci                            variant.ident, member
2537e2e9c0cSopenharmony_ci                        ),
2547e2e9c0cSopenharmony_ci                    );
2557e2e9c0cSopenharmony_ci                }
2567e2e9c0cSopenharmony_ci
2577e2e9c0cSopenharmony_ci                if field.attrs.skip_serializing_if().is_some() {
2587e2e9c0cSopenharmony_ci                    cx.error_spanned_by(
2597e2e9c0cSopenharmony_ci                        variant.original,
2607e2e9c0cSopenharmony_ci                        format!(
2617e2e9c0cSopenharmony_ci                            "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]",
2627e2e9c0cSopenharmony_ci                            variant.ident, member
2637e2e9c0cSopenharmony_ci                        ),
2647e2e9c0cSopenharmony_ci                    );
2657e2e9c0cSopenharmony_ci                }
2667e2e9c0cSopenharmony_ci            }
2677e2e9c0cSopenharmony_ci        }
2687e2e9c0cSopenharmony_ci
2697e2e9c0cSopenharmony_ci        if variant.attrs.deserialize_with().is_some() {
2707e2e9c0cSopenharmony_ci            if variant.attrs.skip_deserializing() {
2717e2e9c0cSopenharmony_ci                cx.error_spanned_by(
2727e2e9c0cSopenharmony_ci                    variant.original,
2737e2e9c0cSopenharmony_ci                    format!(
2747e2e9c0cSopenharmony_ci                        "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]",
2757e2e9c0cSopenharmony_ci                        variant.ident
2767e2e9c0cSopenharmony_ci                    ),
2777e2e9c0cSopenharmony_ci                );
2787e2e9c0cSopenharmony_ci            }
2797e2e9c0cSopenharmony_ci
2807e2e9c0cSopenharmony_ci            for field in &variant.fields {
2817e2e9c0cSopenharmony_ci                if field.attrs.skip_deserializing() {
2827e2e9c0cSopenharmony_ci                    let member = member_message(&field.member);
2837e2e9c0cSopenharmony_ci
2847e2e9c0cSopenharmony_ci                    cx.error_spanned_by(
2857e2e9c0cSopenharmony_ci                        variant.original,
2867e2e9c0cSopenharmony_ci                        format!(
2877e2e9c0cSopenharmony_ci                            "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]",
2887e2e9c0cSopenharmony_ci                            variant.ident, member
2897e2e9c0cSopenharmony_ci                        ),
2907e2e9c0cSopenharmony_ci                    );
2917e2e9c0cSopenharmony_ci                }
2927e2e9c0cSopenharmony_ci            }
2937e2e9c0cSopenharmony_ci        }
2947e2e9c0cSopenharmony_ci    }
2957e2e9c0cSopenharmony_ci}
2967e2e9c0cSopenharmony_ci
2977e2e9c0cSopenharmony_ci// The tag of an internally-tagged struct variant must not be the same as either
2987e2e9c0cSopenharmony_ci// one of its fields, as this would result in duplicate keys in the serialized
2997e2e9c0cSopenharmony_ci// output and/or ambiguity in the to-be-deserialized input.
3007e2e9c0cSopenharmony_cifn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
3017e2e9c0cSopenharmony_ci    let variants = match &cont.data {
3027e2e9c0cSopenharmony_ci        Data::Enum(variants) => variants,
3037e2e9c0cSopenharmony_ci        Data::Struct(_, _) => return,
3047e2e9c0cSopenharmony_ci    };
3057e2e9c0cSopenharmony_ci
3067e2e9c0cSopenharmony_ci    let tag = match cont.attrs.tag() {
3077e2e9c0cSopenharmony_ci        TagType::Internal { tag } => tag.as_str(),
3087e2e9c0cSopenharmony_ci        TagType::External | TagType::Adjacent { .. } | TagType::None => return,
3097e2e9c0cSopenharmony_ci    };
3107e2e9c0cSopenharmony_ci
3117e2e9c0cSopenharmony_ci    let diagnose_conflict = || {
3127e2e9c0cSopenharmony_ci        cx.error_spanned_by(
3137e2e9c0cSopenharmony_ci            cont.original,
3147e2e9c0cSopenharmony_ci            format!("variant field name `{}` conflicts with internal tag", tag),
3157e2e9c0cSopenharmony_ci        );
3167e2e9c0cSopenharmony_ci    };
3177e2e9c0cSopenharmony_ci
3187e2e9c0cSopenharmony_ci    for variant in variants {
3197e2e9c0cSopenharmony_ci        match variant.style {
3207e2e9c0cSopenharmony_ci            Style::Struct => {
3217e2e9c0cSopenharmony_ci                if variant.attrs.untagged() {
3227e2e9c0cSopenharmony_ci                    continue;
3237e2e9c0cSopenharmony_ci                }
3247e2e9c0cSopenharmony_ci                for field in &variant.fields {
3257e2e9c0cSopenharmony_ci                    let check_ser =
3267e2e9c0cSopenharmony_ci                        !(field.attrs.skip_serializing() || variant.attrs.skip_serializing());
3277e2e9c0cSopenharmony_ci                    let check_de =
3287e2e9c0cSopenharmony_ci                        !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing());
3297e2e9c0cSopenharmony_ci                    let name = field.attrs.name();
3307e2e9c0cSopenharmony_ci                    let ser_name = name.serialize_name();
3317e2e9c0cSopenharmony_ci
3327e2e9c0cSopenharmony_ci                    if check_ser && ser_name == tag {
3337e2e9c0cSopenharmony_ci                        diagnose_conflict();
3347e2e9c0cSopenharmony_ci                        return;
3357e2e9c0cSopenharmony_ci                    }
3367e2e9c0cSopenharmony_ci
3377e2e9c0cSopenharmony_ci                    for de_name in field.attrs.aliases() {
3387e2e9c0cSopenharmony_ci                        if check_de && de_name == tag {
3397e2e9c0cSopenharmony_ci                            diagnose_conflict();
3407e2e9c0cSopenharmony_ci                            return;
3417e2e9c0cSopenharmony_ci                        }
3427e2e9c0cSopenharmony_ci                    }
3437e2e9c0cSopenharmony_ci                }
3447e2e9c0cSopenharmony_ci            }
3457e2e9c0cSopenharmony_ci            Style::Unit | Style::Newtype | Style::Tuple => {}
3467e2e9c0cSopenharmony_ci        }
3477e2e9c0cSopenharmony_ci    }
3487e2e9c0cSopenharmony_ci}
3497e2e9c0cSopenharmony_ci
3507e2e9c0cSopenharmony_ci// In the case of adjacently-tagged enums, the type and the contents tag must
3517e2e9c0cSopenharmony_ci// differ, for the same reason.
3527e2e9c0cSopenharmony_cifn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
3537e2e9c0cSopenharmony_ci    let (type_tag, content_tag) = match cont.attrs.tag() {
3547e2e9c0cSopenharmony_ci        TagType::Adjacent { tag, content } => (tag, content),
3557e2e9c0cSopenharmony_ci        TagType::Internal { .. } | TagType::External | TagType::None => return,
3567e2e9c0cSopenharmony_ci    };
3577e2e9c0cSopenharmony_ci
3587e2e9c0cSopenharmony_ci    if type_tag == content_tag {
3597e2e9c0cSopenharmony_ci        cx.error_spanned_by(
3607e2e9c0cSopenharmony_ci            cont.original,
3617e2e9c0cSopenharmony_ci            format!(
3627e2e9c0cSopenharmony_ci                "enum tags `{}` for type and content conflict with each other",
3637e2e9c0cSopenharmony_ci                type_tag
3647e2e9c0cSopenharmony_ci            ),
3657e2e9c0cSopenharmony_ci        );
3667e2e9c0cSopenharmony_ci    }
3677e2e9c0cSopenharmony_ci}
3687e2e9c0cSopenharmony_ci
3697e2e9c0cSopenharmony_ci// Enums and unit structs cannot be transparent.
3707e2e9c0cSopenharmony_cifn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
3717e2e9c0cSopenharmony_ci    if !cont.attrs.transparent() {
3727e2e9c0cSopenharmony_ci        return;
3737e2e9c0cSopenharmony_ci    }
3747e2e9c0cSopenharmony_ci
3757e2e9c0cSopenharmony_ci    if cont.attrs.type_from().is_some() {
3767e2e9c0cSopenharmony_ci        cx.error_spanned_by(
3777e2e9c0cSopenharmony_ci            cont.original,
3787e2e9c0cSopenharmony_ci            "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]",
3797e2e9c0cSopenharmony_ci        );
3807e2e9c0cSopenharmony_ci    }
3817e2e9c0cSopenharmony_ci
3827e2e9c0cSopenharmony_ci    if cont.attrs.type_try_from().is_some() {
3837e2e9c0cSopenharmony_ci        cx.error_spanned_by(
3847e2e9c0cSopenharmony_ci            cont.original,
3857e2e9c0cSopenharmony_ci            "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]",
3867e2e9c0cSopenharmony_ci        );
3877e2e9c0cSopenharmony_ci    }
3887e2e9c0cSopenharmony_ci
3897e2e9c0cSopenharmony_ci    if cont.attrs.type_into().is_some() {
3907e2e9c0cSopenharmony_ci        cx.error_spanned_by(
3917e2e9c0cSopenharmony_ci            cont.original,
3927e2e9c0cSopenharmony_ci            "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]",
3937e2e9c0cSopenharmony_ci        );
3947e2e9c0cSopenharmony_ci    }
3957e2e9c0cSopenharmony_ci
3967e2e9c0cSopenharmony_ci    let fields = match &mut cont.data {
3977e2e9c0cSopenharmony_ci        Data::Enum(_) => {
3987e2e9c0cSopenharmony_ci            cx.error_spanned_by(
3997e2e9c0cSopenharmony_ci                cont.original,
4007e2e9c0cSopenharmony_ci                "#[serde(transparent)] is not allowed on an enum",
4017e2e9c0cSopenharmony_ci            );
4027e2e9c0cSopenharmony_ci            return;
4037e2e9c0cSopenharmony_ci        }
4047e2e9c0cSopenharmony_ci        Data::Struct(Style::Unit, _) => {
4057e2e9c0cSopenharmony_ci            cx.error_spanned_by(
4067e2e9c0cSopenharmony_ci                cont.original,
4077e2e9c0cSopenharmony_ci                "#[serde(transparent)] is not allowed on a unit struct",
4087e2e9c0cSopenharmony_ci            );
4097e2e9c0cSopenharmony_ci            return;
4107e2e9c0cSopenharmony_ci        }
4117e2e9c0cSopenharmony_ci        Data::Struct(_, fields) => fields,
4127e2e9c0cSopenharmony_ci    };
4137e2e9c0cSopenharmony_ci
4147e2e9c0cSopenharmony_ci    let mut transparent_field = None;
4157e2e9c0cSopenharmony_ci
4167e2e9c0cSopenharmony_ci    for field in fields {
4177e2e9c0cSopenharmony_ci        if allow_transparent(field, derive) {
4187e2e9c0cSopenharmony_ci            if transparent_field.is_some() {
4197e2e9c0cSopenharmony_ci                cx.error_spanned_by(
4207e2e9c0cSopenharmony_ci                    cont.original,
4217e2e9c0cSopenharmony_ci                    "#[serde(transparent)] requires struct to have at most one transparent field",
4227e2e9c0cSopenharmony_ci                );
4237e2e9c0cSopenharmony_ci                return;
4247e2e9c0cSopenharmony_ci            }
4257e2e9c0cSopenharmony_ci            transparent_field = Some(field);
4267e2e9c0cSopenharmony_ci        }
4277e2e9c0cSopenharmony_ci    }
4287e2e9c0cSopenharmony_ci
4297e2e9c0cSopenharmony_ci    match transparent_field {
4307e2e9c0cSopenharmony_ci        Some(transparent_field) => transparent_field.attrs.mark_transparent(),
4317e2e9c0cSopenharmony_ci        None => match derive {
4327e2e9c0cSopenharmony_ci            Derive::Serialize => {
4337e2e9c0cSopenharmony_ci                cx.error_spanned_by(
4347e2e9c0cSopenharmony_ci                    cont.original,
4357e2e9c0cSopenharmony_ci                    "#[serde(transparent)] requires at least one field that is not skipped",
4367e2e9c0cSopenharmony_ci                );
4377e2e9c0cSopenharmony_ci            }
4387e2e9c0cSopenharmony_ci            Derive::Deserialize => {
4397e2e9c0cSopenharmony_ci                cx.error_spanned_by(
4407e2e9c0cSopenharmony_ci                    cont.original,
4417e2e9c0cSopenharmony_ci                    "#[serde(transparent)] requires at least one field that is neither skipped nor has a default",
4427e2e9c0cSopenharmony_ci                );
4437e2e9c0cSopenharmony_ci            }
4447e2e9c0cSopenharmony_ci        },
4457e2e9c0cSopenharmony_ci    }
4467e2e9c0cSopenharmony_ci}
4477e2e9c0cSopenharmony_ci
4487e2e9c0cSopenharmony_cifn member_message(member: &Member) -> String {
4497e2e9c0cSopenharmony_ci    match member {
4507e2e9c0cSopenharmony_ci        Member::Named(ident) => format!("`{}`", ident),
4517e2e9c0cSopenharmony_ci        Member::Unnamed(i) => format!("#{}", i.index),
4527e2e9c0cSopenharmony_ci    }
4537e2e9c0cSopenharmony_ci}
4547e2e9c0cSopenharmony_ci
4557e2e9c0cSopenharmony_cifn allow_transparent(field: &Field, derive: Derive) -> bool {
4567e2e9c0cSopenharmony_ci    if let Type::Path(ty) = ungroup(field.ty) {
4577e2e9c0cSopenharmony_ci        if let Some(seg) = ty.path.segments.last() {
4587e2e9c0cSopenharmony_ci            if seg.ident == "PhantomData" {
4597e2e9c0cSopenharmony_ci                return false;
4607e2e9c0cSopenharmony_ci            }
4617e2e9c0cSopenharmony_ci        }
4627e2e9c0cSopenharmony_ci    }
4637e2e9c0cSopenharmony_ci
4647e2e9c0cSopenharmony_ci    match derive {
4657e2e9c0cSopenharmony_ci        Derive::Serialize => !field.attrs.skip_serializing(),
4667e2e9c0cSopenharmony_ci        Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(),
4677e2e9c0cSopenharmony_ci    }
4687e2e9c0cSopenharmony_ci}
4697e2e9c0cSopenharmony_ci
4707e2e9c0cSopenharmony_cifn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) {
4717e2e9c0cSopenharmony_ci    if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() {
4727e2e9c0cSopenharmony_ci        cx.error_spanned_by(
4737e2e9c0cSopenharmony_ci            cont.original,
4747e2e9c0cSopenharmony_ci            "#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other",
4757e2e9c0cSopenharmony_ci        );
4767e2e9c0cSopenharmony_ci    }
4777e2e9c0cSopenharmony_ci}
478