Disallow variant field names to conflict with tag of internally-tagged enum

This commit is contained in:
Árpád Goretity 2018-03-08 00:43:35 +01:00
parent d6f07f2f47
commit a799ea171c

View File

@ -7,7 +7,7 @@
// except according to those terms. // except according to those terms.
use ast::{Data, Container, Style}; use ast::{Data, Container, Style};
use attr::Identifier; use attr::{Identifier, EnumTag};
use Ctxt; use Ctxt;
/// Cross-cutting checks that require looking at more than a single attrs /// Cross-cutting checks that require looking at more than a single attrs
@ -16,6 +16,7 @@ pub fn check(cx: &Ctxt, cont: &Container) {
check_getter(cx, cont); check_getter(cx, cont);
check_identifier(cx, cont); check_identifier(cx, cont);
check_variant_skip_attrs(cx, cont); check_variant_skip_attrs(cx, cont);
check_internally_tagged_variant_name_conflict(cx, cont);
} }
/// Getters are only allowed inside structs (not enums) with the `remote` /// Getters are only allowed inside structs (not enums) with the `remote`
@ -169,3 +170,46 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
} }
} }
} }
fn check_internally_tagged_variant_name_conflict(
cx: &Ctxt,
cont: &Container,
) {
let variants = match cont.data {
Data::Enum(ref variants) => variants,
Data::Struct(_, _) => return,
};
let tag = match *cont.attrs.tag() {
EnumTag::Internal { ref tag } => tag.as_str(),
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
};
let diagnose_conflict = || {
let message = format!(
"variant field name `{}` conflicts with internal tag",
tag
);
cx.error(message);
};
for variant in variants {
match variant.style {
Style::Struct => {
for field in &variant.fields {
let check_ser = !field.attrs.skip_serializing();
let check_de = !field.attrs.skip_deserializing();
let name = field.attrs.name();
let ser_name = name.serialize_name();
let de_name = name.deserialize_name();
if check_ser && ser_name == tag || check_de && de_name == tag {
diagnose_conflict();
return;
}
}
},
_ => {},
}
}
}