Error on duplicate attributes

This commit is contained in:
David Tolnay 2016-06-14 11:22:49 -07:00
parent 8e4da7f36b
commit 28589620f6
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
5 changed files with 199 additions and 129 deletions

View File

@ -1,7 +1,7 @@
use std::rc::Rc; use std::rc::Rc;
use syntax::ast::{self, TokenTree}; use syntax::ast::{self, TokenTree};
use syntax::attr; use syntax::attr;
use syntax::codemap::Span; use syntax::codemap::{Span, Spanned, respan};
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::fold::Folder; use syntax::fold::Folder;
use syntax::parse::parser::{Parser, PathStyle}; use syntax::parse::parser::{Parser, PathStyle};
@ -11,9 +11,68 @@ use syntax::print::pprust::{lit_to_string, meta_item_to_string};
use syntax::ptr::P; use syntax::ptr::P;
use aster::AstBuilder; use aster::AstBuilder;
use aster::ident::ToIdent;
use error::Error; use error::Error;
struct Attr<'a, 'b: 'a, T> {
cx: &'a ExtCtxt<'b>,
name: &'static str,
value: Option<Spanned<T>>,
}
impl<'a, 'b, T> Attr<'a, 'b, T> {
fn none(cx: &'a ExtCtxt<'b>, name: &'static str) -> Self {
Attr {
cx: cx,
name: name,
value: None,
}
}
fn set(&mut self, span: Span, t: T) {
if let Some(Spanned { span: prev_span, .. }) = self.value {
let mut err = self.cx.struct_span_err(
span,
&format!("duplicate serde attribute `{}`", self.name));
err.span_help(prev_span, "previously set here");
err.emit();
} else {
self.value = Some(respan(span, t));
}
}
fn set_opt(&mut self, v: Option<Spanned<T>>) {
if let Some(v) = v {
self.set(v.span, v.node);
}
}
fn set_if_none(&mut self, span: Span, t: T) {
if self.value.is_none() {
self.value = Some(respan(span, t));
}
}
fn get(self) -> Option<T> {
self.value.map(|spanned| spanned.node)
}
}
struct BoolAttr<'a, 'b: 'a>(Attr<'a, 'b, ()>);
impl<'a, 'b> BoolAttr<'a, 'b> {
fn none(cx: &'a ExtCtxt<'b>, name: &'static str) -> Self {
BoolAttr(Attr::none(cx, name))
}
fn set_true(&mut self, span: Span) {
self.0.set(span, ());
}
fn get(&self) -> bool {
self.0.value.is_some()
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Name { pub struct Name {
ident: ast::Ident, ident: ast::Ident,
@ -22,14 +81,6 @@ pub struct Name {
} }
impl Name { impl Name {
fn new(ident: ast::Ident) -> Self {
Name {
ident: ident,
serialize_name: None,
deserialize_name: None,
}
}
/// Return the container name for the container when serializing. /// Return the container name for the container when serializing.
pub fn serialize_name(&self) -> InternedString { pub fn serialize_name(&self) -> InternedString {
match self.serialize_name { match self.serialize_name {
@ -69,55 +120,47 @@ pub struct ContainerAttrs {
impl ContainerAttrs { impl ContainerAttrs {
/// Extract out the `#[serde(...)]` attributes from an item. /// Extract out the `#[serde(...)]` attributes from an item.
pub fn from_item(cx: &ExtCtxt, item: &ast::Item) -> Result<Self, Error> { pub fn from_item(cx: &ExtCtxt, item: &ast::Item) -> Result<Self, Error> {
let mut container_attrs = ContainerAttrs { let mut ser_name = Attr::none(cx, "rename");
name: Name::new(item.ident), let mut de_name = Attr::none(cx, "rename");
deny_unknown_fields: false, let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields");
ser_bound: None, let mut ser_bound = Attr::none(cx, "bound");
de_bound: None, let mut de_bound = Attr::none(cx, "bound");
};
for meta_items in item.attrs().iter().filter_map(get_serde_meta_items) { for meta_items in item.attrs().iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items { for meta_item in meta_items {
let span = meta_item.span;
match meta_item.node { match meta_item.node {
// Parse `#[serde(rename="foo")]` // Parse `#[serde(rename="foo")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => {
let s = try!(get_str_from_lit(cx, name, lit)); let s = try!(get_str_from_lit(cx, name, lit));
container_attrs.name.serialize_name = Some(s.clone()); ser_name.set(span, s.clone());
container_attrs.name.deserialize_name = Some(s); de_name.set(span, s);
} }
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => { ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => {
let (ser_name, de_name) = try!(get_renames(cx, meta_items)); let (ser, de) = try!(get_renames(cx, meta_items));
if ser_name.is_some() { ser_name.set_opt(ser);
container_attrs.name.serialize_name = ser_name; de_name.set_opt(de);
}
if de_name.is_some() {
container_attrs.name.deserialize_name = de_name;
}
} }
// Parse `#[serde(deny_unknown_fields)]` // Parse `#[serde(deny_unknown_fields)]`
ast::MetaItemKind::Word(ref name) if name == &"deny_unknown_fields" => { ast::MetaItemKind::Word(ref name) if name == &"deny_unknown_fields" => {
container_attrs.deny_unknown_fields = true; deny_unknown_fields.set_true(span);
} }
// Parse `#[serde(bound="D: Serialize")]` // Parse `#[serde(bound="D: Serialize")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => {
let where_predicates = try!(parse_lit_into_where(cx, name, lit)); let where_predicates = try!(parse_lit_into_where(cx, name, lit));
container_attrs.ser_bound = Some(where_predicates.clone()); ser_bound.set(span, where_predicates.clone());
container_attrs.de_bound = Some(where_predicates); de_bound.set(span, where_predicates);
} }
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` // Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => { ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => {
let (ser_bound, de_bound) = try!(get_where_predicates(cx, meta_items)); let (ser, de) = try!(get_where_predicates(cx, meta_items));
if ser_bound.is_some() { ser_bound.set_opt(ser);
container_attrs.ser_bound = ser_bound; de_bound.set_opt(de);
}
if de_bound.is_some() {
container_attrs.de_bound = de_bound;
}
} }
_ => { _ => {
@ -132,7 +175,16 @@ impl ContainerAttrs {
} }
} }
Ok(container_attrs) Ok(ContainerAttrs {
name: Name {
ident: item.ident,
serialize_name: ser_name.get(),
deserialize_name: de_name.get(),
},
deny_unknown_fields: deny_unknown_fields.get(),
ser_bound: ser_bound.get(),
de_bound: de_bound.get(),
})
} }
pub fn name(&self) -> &Name { pub fn name(&self) -> &Name {
@ -160,29 +212,25 @@ pub struct VariantAttrs {
impl VariantAttrs { impl VariantAttrs {
pub fn from_variant(cx: &ExtCtxt, variant: &ast::Variant) -> Result<Self, Error> { pub fn from_variant(cx: &ExtCtxt, variant: &ast::Variant) -> Result<Self, Error> {
let mut variant_attrs = VariantAttrs { let mut ser_name = Attr::none(cx, "rename");
name: Name::new(variant.node.name), let mut de_name = Attr::none(cx, "rename");
};
for meta_items in variant.node.attrs.iter().filter_map(get_serde_meta_items) { for meta_items in variant.node.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items { for meta_item in meta_items {
let span = meta_item.span;
match meta_item.node { match meta_item.node {
// Parse `#[serde(rename="foo")]` // Parse `#[serde(rename="foo")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => {
let s = try!(get_str_from_lit(cx, name, lit)); let s = try!(get_str_from_lit(cx, name, lit));
variant_attrs.name.serialize_name = Some(s.clone()); ser_name.set(span, s.clone());
variant_attrs.name.deserialize_name = Some(s); de_name.set(span, s);
} }
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => { ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => {
let (ser_name, de_name) = try!(get_renames(cx, meta_items)); let (ser, de) = try!(get_renames(cx, meta_items));
if ser_name.is_some() { ser_name.set_opt(ser);
variant_attrs.name.serialize_name = ser_name; de_name.set_opt(de);
}
if de_name.is_some() {
variant_attrs.name.deserialize_name = de_name;
}
} }
_ => { _ => {
@ -197,7 +245,13 @@ impl VariantAttrs {
} }
} }
Ok(variant_attrs) Ok(VariantAttrs {
name: Name {
ident: variant.node.name,
serialize_name: ser_name.get(),
deserialize_name: de_name.get(),
},
})
} }
pub fn name(&self) -> &Name { pub fn name(&self) -> &Name {
@ -209,8 +263,8 @@ impl VariantAttrs {
#[derive(Debug)] #[derive(Debug)]
pub struct FieldAttrs { pub struct FieldAttrs {
name: Name, name: Name,
skip_serializing_field: bool, skip_serializing: bool,
skip_deserializing_field: bool, skip_deserializing: bool,
skip_serializing_if: Option<ast::Path>, skip_serializing_if: Option<ast::Path>,
default: FieldDefault, default: FieldDefault,
serialize_with: Option<ast::Path>, serialize_with: Option<ast::Path>,
@ -235,107 +289,91 @@ impl FieldAttrs {
pub fn from_field(cx: &ExtCtxt, pub fn from_field(cx: &ExtCtxt,
index: usize, index: usize,
field: &ast::StructField) -> Result<Self, Error> { field: &ast::StructField) -> Result<Self, Error> {
let builder = AstBuilder::new(); let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
let mut skip_serializing_if = Attr::none(cx, "skip_serializing_if");
let mut default = Attr::none(cx, "default");
let mut serialize_with = Attr::none(cx, "serialize_with");
let mut deserialize_with = Attr::none(cx, "deserialize_with");
let mut ser_bound = Attr::none(cx, "bound");
let mut de_bound = Attr::none(cx, "bound");
let field_ident = match field.ident { let field_ident = match field.ident {
Some(ident) => ident, Some(ident) => ident,
None => builder.id(index.to_string()), None => index.to_string().to_ident(),
};
let mut field_attrs = FieldAttrs {
name: Name::new(field_ident),
skip_serializing_field: false,
skip_deserializing_field: false,
skip_serializing_if: None,
default: FieldDefault::None,
serialize_with: None,
deserialize_with: None,
ser_bound: None,
de_bound: None,
}; };
for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) { for meta_items in field.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items { for meta_item in meta_items {
let span = meta_item.span;
match meta_item.node { match meta_item.node {
// Parse `#[serde(rename="foo")]` // Parse `#[serde(rename="foo")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"rename" => {
let s = try!(get_str_from_lit(cx, name, lit)); let s = try!(get_str_from_lit(cx, name, lit));
field_attrs.name.serialize_name = Some(s.clone()); ser_name.set(span, s.clone());
field_attrs.name.deserialize_name = Some(s); de_name.set(span, s);
} }
// Parse `#[serde(rename(serialize="foo", deserialize="bar"))]` // Parse `#[serde(rename(serialize="foo", deserialize="bar"))]`
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => { ast::MetaItemKind::List(ref name, ref meta_items) if name == &"rename" => {
let (ser_name, de_name) = try!(get_renames(cx, meta_items)); let (ser, de) = try!(get_renames(cx, meta_items));
if ser_name.is_some() { ser_name.set_opt(ser);
field_attrs.name.serialize_name = ser_name; de_name.set_opt(de);
}
if de_name.is_some() {
field_attrs.name.deserialize_name = de_name;
}
} }
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
ast::MetaItemKind::Word(ref name) if name == &"default" => { ast::MetaItemKind::Word(ref name) if name == &"default" => {
field_attrs.default = FieldDefault::Default; default.set(span, FieldDefault::Default);
} }
// Parse `#[serde(default="...")]` // Parse `#[serde(default="...")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"default" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"default" => {
let path = try!(parse_lit_into_path(cx, name, lit)); let path = try!(parse_lit_into_path(cx, name, lit));
field_attrs.default = FieldDefault::Path(path); default.set(span, FieldDefault::Path(path));
} }
// Parse `#[serde(skip_serializing)]` // Parse `#[serde(skip_serializing)]`
ast::MetaItemKind::Word(ref name) if name == &"skip_serializing" => { ast::MetaItemKind::Word(ref name) if name == &"skip_serializing" => {
field_attrs.skip_serializing_field = true; skip_serializing.set_true(span);
} }
// Parse `#[serde(skip_deserializing)]` // Parse `#[serde(skip_deserializing)]`
ast::MetaItemKind::Word(ref name) if name == &"skip_deserializing" => { ast::MetaItemKind::Word(ref name) if name == &"skip_deserializing" => {
field_attrs.skip_deserializing_field = true; skip_deserializing.set_true(span);
// Initialize field to Default::default() unless a different
// default is specified by `#[serde(default="...")]`
if field_attrs.default == FieldDefault::None {
field_attrs.default = FieldDefault::Default;
}
} }
// Parse `#[serde(skip_serializing_if="...")]` // Parse `#[serde(skip_serializing_if="...")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => {
let path = try!(parse_lit_into_path(cx, name, lit)); let path = try!(parse_lit_into_path(cx, name, lit));
field_attrs.skip_serializing_if = Some(path); skip_serializing_if.set(span, path);
} }
// Parse `#[serde(serialize_with="...")]` // Parse `#[serde(serialize_with="...")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize_with" => {
let path = try!(parse_lit_into_path(cx, name, lit)); let path = try!(parse_lit_into_path(cx, name, lit));
field_attrs.serialize_with = Some(path); serialize_with.set(span, path);
} }
// Parse `#[serde(deserialize_with="...")]` // Parse `#[serde(deserialize_with="...")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize_with" => {
let path = try!(parse_lit_into_path(cx, name, lit)); let path = try!(parse_lit_into_path(cx, name, lit));
field_attrs.deserialize_with = Some(path); deserialize_with.set(span, path);
} }
// Parse `#[serde(bound="D: Serialize")]` // Parse `#[serde(bound="D: Serialize")]`
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"bound" => {
let where_predicates = try!(parse_lit_into_where(cx, name, lit)); let where_predicates = try!(parse_lit_into_where(cx, name, lit));
field_attrs.ser_bound = Some(where_predicates.clone()); ser_bound.set(span, where_predicates.clone());
field_attrs.de_bound = Some(where_predicates); de_bound.set(span, where_predicates);
} }
// Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]` // Parse `#[serde(bound(serialize="D: Serialize", deserialize="D: Deserialize"))]`
ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => { ast::MetaItemKind::List(ref name, ref meta_items) if name == &"bound" => {
let (ser_bound, de_bound) = try!(get_where_predicates(cx, meta_items)); let (ser, de) = try!(get_where_predicates(cx, meta_items));
if ser_bound.is_some() { ser_bound.set_opt(ser);
field_attrs.ser_bound = ser_bound; de_bound.set_opt(de);
}
if de_bound.is_some() {
field_attrs.de_bound = de_bound;
}
} }
_ => { _ => {
@ -350,19 +388,39 @@ impl FieldAttrs {
} }
} }
Ok(field_attrs) // Is skip_deserializing, initialize the field to Default::default()
// unless a different default is specified by `#[serde(default="...")]`
if let Some(Spanned { span, .. }) = skip_deserializing.0.value {
default.set_if_none(span, FieldDefault::Default);
}
Ok(FieldAttrs {
name: Name {
ident: field_ident,
serialize_name: ser_name.get(),
deserialize_name: de_name.get(),
},
skip_serializing: skip_serializing.get(),
skip_deserializing: skip_deserializing.get(),
skip_serializing_if: skip_serializing_if.get(),
default: default.get().unwrap_or(FieldDefault::None),
serialize_with: serialize_with.get(),
deserialize_with: deserialize_with.get(),
ser_bound: ser_bound.get(),
de_bound: de_bound.get(),
})
} }
pub fn name(&self) -> &Name { pub fn name(&self) -> &Name {
&self.name &self.name
} }
pub fn skip_serializing_field(&self) -> bool { pub fn skip_serializing(&self) -> bool {
self.skip_serializing_field self.skip_serializing
} }
pub fn skip_deserializing_field(&self) -> bool { pub fn skip_deserializing(&self) -> bool {
self.skip_deserializing_field self.skip_deserializing
} }
pub fn skip_serializing_if(&self) -> Option<&ast::Path> { pub fn skip_serializing_if(&self) -> Option<&ast::Path> {
@ -410,7 +468,7 @@ fn get_ser_and_de<T, F>(
attribute: &str, attribute: &str,
items: &[P<ast::MetaItem>], items: &[P<ast::MetaItem>],
f: F f: F
) -> Result<(Option<T>, Option<T>), Error> ) -> Result<(Option<Spanned<T>>, Option<Spanned<T>>), Error>
where F: Fn(&ExtCtxt, &str, &ast::Lit) -> Result<T, Error>, where F: Fn(&ExtCtxt, &str, &ast::Lit) -> Result<T, Error>,
{ {
let mut ser_item = None; let mut ser_item = None;
@ -420,12 +478,12 @@ fn get_ser_and_de<T, F>(
match item.node { match item.node {
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"serialize" => {
let s = try!(f(cx, name, lit)); let s = try!(f(cx, name, lit));
ser_item = Some(s); ser_item = Some(respan(item.span, s));
} }
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize" => { ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"deserialize" => {
let s = try!(f(cx, name, lit)); let s = try!(f(cx, name, lit));
de_item = Some(s); de_item = Some(respan(item.span, s));
} }
_ => { _ => {
@ -446,14 +504,14 @@ fn get_ser_and_de<T, F>(
fn get_renames( fn get_renames(
cx: &ExtCtxt, cx: &ExtCtxt,
items: &[P<ast::MetaItem>], items: &[P<ast::MetaItem>],
) -> Result<(Option<InternedString>, Option<InternedString>), Error> { ) -> Result<(Option<Spanned<InternedString>>, Option<Spanned<InternedString>>), Error> {
get_ser_and_de(cx, "rename", items, get_str_from_lit) get_ser_and_de(cx, "rename", items, get_str_from_lit)
} }
fn get_where_predicates( fn get_where_predicates(
cx: &ExtCtxt, cx: &ExtCtxt,
items: &[P<ast::MetaItem>], items: &[P<ast::MetaItem>],
) -> Result<(Option<Vec<ast::WherePredicate>>, Option<Vec<ast::WherePredicate>>), Error> { ) -> Result<(Option<Spanned<Vec<ast::WherePredicate>>>, Option<Spanned<Vec<ast::WherePredicate>>>), Error> {
get_ser_and_de(cx, "bound", items, parse_lit_into_where) get_ser_and_de(cx, "bound", items, parse_lit_into_where)
} }

View File

@ -135,7 +135,7 @@ fn build_impl_generics(
// attribute specify their own bound so we do not generate one. All other fields // attribute specify their own bound so we do not generate one. All other fields
// may need a `T: Deserialize` bound where T is the type of the field. // may need a `T: Deserialize` bound where T is the type of the field.
fn needs_deserialize_bound(attrs: &attr::FieldAttrs) -> bool { fn needs_deserialize_bound(attrs: &attr::FieldAttrs) -> bool {
!attrs.skip_deserializing_field() !attrs.skip_deserializing()
&& attrs.deserialize_with().is_none() && attrs.deserialize_with().is_none()
&& attrs.de_bound().is_none() && attrs.de_bound().is_none()
} }
@ -450,7 +450,7 @@ fn deserialize_seq(
.enumerate() .enumerate()
.map(|(i, &(ref field, ref attrs))| { .map(|(i, &(ref field, ref attrs))| {
let name = builder.id(format!("__field{}", i)); let name = builder.id(format!("__field{}", i));
if attrs.skip_deserializing_field() { if attrs.skip_deserializing() {
let default = expr_is_missing(cx, attrs); let default = expr_is_missing(cx, attrs);
quote_stmt!(cx, quote_stmt!(cx,
let $name = $default; let $name = $default;
@ -1049,7 +1049,7 @@ fn deserialize_map(
// Declare each field that will be deserialized. // Declare each field that will be deserialized.
let let_values: Vec<ast::Stmt> = fields_attrs_names.iter() let let_values: Vec<ast::Stmt> = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing())
.map(|&(field, _, name)| { .map(|&(field, _, name)| {
let field_ty = &field.ty; let field_ty = &field.ty;
quote_stmt!(cx, let mut $name: Option<$field_ty> = None;).unwrap() quote_stmt!(cx, let mut $name: Option<$field_ty> = None;).unwrap()
@ -1058,7 +1058,7 @@ fn deserialize_map(
// Match arms to extract a value for a field. // Match arms to extract a value for a field.
let value_arms = fields_attrs_names.iter() let value_arms = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing())
.map(|&(ref field, ref attrs, name)| { .map(|&(ref field, ref attrs, name)| {
let deser_name = attrs.name().deserialize_name(); let deser_name = attrs.name().deserialize_name();
let name_str = builder.expr().lit().str(deser_name); let name_str = builder.expr().lit().str(deser_name);
@ -1092,7 +1092,7 @@ fn deserialize_map(
// Match arms to ignore value for fields that have `skip_deserializing`. // Match arms to ignore value for fields that have `skip_deserializing`.
// Ignored even if `deny_unknown_fields` is set. // Ignored even if `deny_unknown_fields` is set.
let skipped_arms = fields_attrs_names.iter() let skipped_arms = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| attrs.skip_deserializing())
.map(|&(_, _, name)| { .map(|&(_, _, name)| {
quote_arm!(cx, quote_arm!(cx,
__Field::$name => { __Field::$name => {
@ -1112,7 +1112,7 @@ fn deserialize_map(
}; };
let extract_values = fields_attrs_names.iter() let extract_values = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing())
.map(|&(_, ref attrs, name)| { .map(|&(_, ref attrs, name)| {
let missing_expr = expr_is_missing(cx, attrs); let missing_expr = expr_is_missing(cx, attrs);
@ -1138,7 +1138,7 @@ fn deserialize_map(
cx.span_bug(field.span, "struct contains unnamed fields") cx.span_bug(field.span, "struct contains unnamed fields")
} }
}, },
if attrs.skip_deserializing_field() { if attrs.skip_deserializing() {
expr_is_missing(cx, attrs) expr_is_missing(cx, attrs)
} else { } else {
builder.expr().id(name) builder.expr().id(name)
@ -1258,7 +1258,7 @@ fn check_no_str(
}; };
for &(ref field, ref attrs) in fields { for &(ref field, ref attrs) in fields {
if attrs.skip_deserializing_field() if attrs.skip_deserializing()
|| attrs.deserialize_with().is_some() { continue } || attrs.deserialize_with().is_some() { continue }
if let ast::TyKind::Rptr(_, ref inner) = field.ty.node { if let ast::TyKind::Rptr(_, ref inner) = field.ty.node {

View File

@ -129,7 +129,7 @@ fn build_impl_generics(
// attribute specify their own bound so we do not generate one. All other fields // attribute specify their own bound so we do not generate one. All other fields
// may need a `T: Serialize` bound where T is the type of the field. // may need a `T: Serialize` bound where T is the type of the field.
fn needs_serialize_bound(attrs: &attr::FieldAttrs) -> bool { fn needs_serialize_bound(attrs: &attr::FieldAttrs) -> bool {
!attrs.skip_serializing_field() !attrs.skip_serializing()
&& attrs.serialize_with().is_none() && attrs.serialize_with().is_none()
&& attrs.ser_bound().is_none() && attrs.ser_bound().is_none()
} }
@ -749,7 +749,7 @@ fn serialize_struct_visitor(
let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields)); let fields_with_attrs = try!(attr::fields_with_attrs(cx, fields));
let arms: Vec<ast::Arm> = fields_with_attrs.iter() let arms: Vec<ast::Arm> = fields_with_attrs.iter()
.filter(|&&(_, ref attrs)| !attrs.skip_serializing_field()) .filter(|&&(_, ref attrs)| !attrs.skip_serializing())
.enumerate() .enumerate()
.map(|(i, &(ref field, ref attrs))| { .map(|(i, &(ref field, ref attrs))| {
let ident = field.ident.expect("struct has unnamed field"); let ident = field.ident.expect("struct has unnamed field");
@ -794,7 +794,7 @@ fn serialize_struct_visitor(
.build(); .build();
let len = fields_with_attrs.iter() let len = fields_with_attrs.iter()
.filter(|&&(_, ref attrs)| !attrs.skip_serializing_field()) .filter(|&&(_, ref attrs)| !attrs.skip_serializing())
.map(|&(ref field, ref attrs)| { .map(|&(ref field, ref attrs)| {
let ident = field.ident.expect("struct has unnamed fields"); let ident = field.ident.expect("struct has unnamed fields");
let mut field_expr = quote_expr!(cx, self.value.$ident); let mut field_expr = quote_expr!(cx, self.value.$ident);

View File

@ -0,0 +1,25 @@
#![feature(custom_attribute, custom_derive, plugin)]
#![plugin(serde_macros)]
#[derive(Serialize)]
struct S {
#[serde(rename(serialize="x"))]
#[serde(rename(serialize="y"))] //~ ERROR: duplicate serde attribute `rename`
a: (), //~^ ERROR: duplicate serde attribute `rename`
//~^^ ERROR: duplicate serde attribute `rename`
#[serde(rename(serialize="x"))]
#[serde(rename="y")] //~ ERROR: duplicate serde attribute `rename`
b: (), //~^ ERROR: duplicate serde attribute `rename`
//~^^ ERROR: duplicate serde attribute `rename`
#[serde(rename(serialize="x"))]
#[serde(rename(deserialize="y"))] // ok
c: (),
#[serde(rename="x")]
#[serde(rename(deserialize="y"))] //~ ERROR: duplicate serde attribute `rename`
d: (), //~^ ERROR: duplicate serde attribute `rename`
} //~^^ ERROR: duplicate serde attribute `rename`
fn main() {}

View File

@ -1,13 +0,0 @@
#![feature(custom_attribute, custom_derive, plugin)]
#![plugin(serde_macros)]
#[derive(Serialize, Deserialize)]
struct S {
#[serde(rename(serialize="x"))]
#[serde(rename(serialize="y"))] //~ ERROR buldternua
#[serde(rename(deserialize="y"))] // ok
#[serde(rename="y")] // error
z: i32,
}
fn main() {}