Round trip testing

This commit is contained in:
David Tolnay 2016-10-01 00:40:31 -07:00
parent 590cdfd074
commit 4a51dc70fc
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
11 changed files with 836 additions and 617 deletions

View File

@ -20,3 +20,8 @@ visit = []
clippy = { version = "0.*", optional = true }
quote = { version = "0.2", optional = true }
unicode-xid = { version = "0.0.3", optional = true }
[dev-dependencies]
syntex_pos = "0.44.0"
syntex_syntax = "0.44.0"
walkdir = "0.1.8"

View File

@ -1,12 +1,24 @@
use super::*;
use std::iter;
/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Attribute {
pub style: AttrStyle,
pub value: MetaItem,
pub is_sugared_doc: bool,
}
/// Distinguishes between Attributes that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AttrStyle {
Outer,
Inner,
}
/// A compile-time attribute item.
///
/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
@ -36,6 +48,31 @@ impl MetaItem {
}
}
pub trait FilterAttrs<'a> {
type Ret: Iterator<Item = &'a Attribute>;
fn outer(self) -> Self::Ret;
fn inner(self) -> Self::Ret;
}
impl<'a, T> FilterAttrs<'a> for T where T: IntoIterator<Item = &'a Attribute> {
type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;
fn outer(self) -> Self::Ret {
fn is_outer(attr: &&Attribute) -> bool {
attr.style == AttrStyle::Outer
}
self.into_iter().filter(is_outer)
}
fn inner(self) -> Self::Ret {
fn is_inner(attr: &&Attribute) -> bool {
attr.style == AttrStyle::Inner
}
self.into_iter().filter(is_inner)
}
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
@ -43,13 +80,27 @@ pub mod parsing {
use lit::{Lit, StrStyle};
use lit::parsing::lit;
named!(pub attribute -> Attribute, alt!(
named!(pub inner_attr -> Attribute, do_parse!(
punct!("#") >>
punct!("!") >>
punct!("[") >>
meta_item: meta_item >>
punct!("]") >>
(Attribute {
style: AttrStyle::Inner,
value: meta_item,
is_sugared_doc: false,
})
));
named!(pub outer_attr -> Attribute, alt!(
do_parse!(
punct!("#") >>
punct!("[") >>
meta_item: meta_item >>
punct!("]") >>
(Attribute {
style: AttrStyle::Outer,
value: meta_item,
is_sugared_doc: false,
})
@ -60,6 +111,7 @@ pub mod parsing {
not!(peek!(tag!("/"))) >>
content: take_until!("\n") >>
(Attribute {
style: AttrStyle::Outer,
value: MetaItem::NameValue(
"doc".into(),
Lit::Str(
@ -102,6 +154,7 @@ mod printing {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
Attribute {
style: AttrStyle::Outer,
value: MetaItem::NameValue(
ref name,
Lit::Str(ref value, StrStyle::Cooked),
@ -112,6 +165,9 @@ mod printing {
}
_ => {
tokens.append("#");
if let AttrStyle::Inner = self.style {
tokens.append("!");
}
tokens.append("[");
self.value.to_tokens(tokens);
tokens.append("]");

View File

@ -49,7 +49,7 @@ pub struct Discriminant {
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use attr::parsing::attribute;
use attr::parsing::outer_attr;
use ident::parsing::ident;
use lit::parsing::int;
use ty::parsing::ty;
@ -71,7 +71,7 @@ pub mod parsing {
));
named!(variant -> Variant, do_parse!(
attrs: many0!(attribute) >>
attrs: many0!(outer_attr) >>
id: ident >>
data: alt!(
struct_like_body => { VariantData::Struct }
@ -106,7 +106,7 @@ pub mod parsing {
));
named!(struct_field -> Field, do_parse!(
attrs: many0!(attribute) >>
attrs: many0!(outer_attr) >>
vis: visibility >>
id: ident >>
punct!(":") >>
@ -120,7 +120,7 @@ pub mod parsing {
));
named!(tuple_field -> Field, do_parse!(
attrs: many0!(attribute) >>
attrs: many0!(outer_attr) >>
vis: visibility >>
ty: ty >>
(Field {

View File

@ -209,7 +209,7 @@ pub struct MethodSig {
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use attr::parsing::attribute;
use attr::parsing::outer_attr;
use data::parsing::visibility;
use ident::parsing::ident;
use macro_input::{Body, MacroInput};
@ -234,7 +234,7 @@ pub mod parsing {
));
named!(item_extern_crate -> Item, do_parse!(
attrs: many0!(attribute) >>
attrs: many0!(outer_attr) >>
vis: visibility >>
keyword!("extern") >>
keyword!("crate") >>
@ -275,3 +275,73 @@ pub mod parsing {
}
));
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use attr::FilterAttrs;
use data::{VariantData, Visibility};
use quote::{Tokens, ToTokens};
impl ToTokens for Item {
fn to_tokens(&self, tokens: &mut Tokens) {
for attr in self.attrs.outer() {
attr.to_tokens(tokens);
}
match self.node {
ItemKind::ExternCrate(ref original) => {
tokens.append("extern");
tokens.append("crate");
if let Some(ref original) = *original {
original.to_tokens(tokens);
tokens.append("as");
}
self.ident.to_tokens(tokens);
tokens.append(";");
}
ItemKind::Use(ref _view_path) => unimplemented!(),
ItemKind::Static(ref _ty, ref _mutability, ref _expr) => unimplemented!(),
ItemKind::Const(ref _ty, ref _expr) => unimplemented!(),
ItemKind::Fn(ref _decl, _unsafety, _constness, ref _abi, ref _generics, ref _block) => unimplemented!(),
ItemKind::Mod(ref _items) => unimplemented!(),
ItemKind::ForeignMod(ref _foreign_mod) => unimplemented!(),
ItemKind::Ty(ref _ty, ref _generics) => unimplemented!(),
ItemKind::Enum(ref variants, ref generics) => {
if let Visibility::Public = self.vis {
tokens.append("pub");
}
tokens.append("enum");
self.ident.to_tokens(tokens);
generics.to_tokens(tokens);
generics.where_clause.to_tokens(tokens);
tokens.append("{");
for variant in variants {
variant.to_tokens(tokens);
tokens.append(",");
}
tokens.append("}");
}
ItemKind::Struct(ref variant_data, ref generics) => {
if let Visibility::Public = self.vis {
tokens.append("pub");
}
tokens.append("struct");
self.ident.to_tokens(tokens);
generics.to_tokens(tokens);
generics.where_clause.to_tokens(tokens);
variant_data.to_tokens(tokens);
match *variant_data {
VariantData::Struct(_) => { /* no semicolon */ }
VariantData::Tuple(_) |
VariantData::Unit => tokens.append(";"),
}
}
ItemKind::Union(ref _variant_data, ref _generics) => unimplemented!(),
ItemKind::Trait(_unsafety, ref _generics, ref _bound, ref _item) => unimplemented!(),
ItemKind::DefaultImpl(_unsafety, ref _path) => unimplemented!(),
ItemKind::Impl(_unsafety, _polarity, ref _generics, ref _path, ref _ty, ref _item) => unimplemented!(),
ItemKind::Mac(ref _mac) => unimplemented!(),
}
}
}
}

43
src/krate.rs Normal file
View File

@ -0,0 +1,43 @@
use super::*;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Crate {
attrs: Vec<Attribute>,
items: Vec<Item>,
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use attr::parsing::inner_attr;
use item::parsing::item;
use nom::multispace;
named!(pub krate -> Crate, do_parse!(
attrs: many0!(inner_attr) >>
items: many0!(item) >>
option!(multispace) >>
(Crate {
attrs: attrs,
items: items,
})
));
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use attr::FilterAttrs;
use quote::{Tokens, ToTokens};
impl ToTokens for Crate {
fn to_tokens(&self, tokens: &mut Tokens) {
for attr in self.attrs.inner() {
attr.to_tokens(tokens);
}
for item in &self.items {
item.to_tokens(tokens);
}
}
}
}

View File

@ -19,6 +19,7 @@ mod escape;
mod attr;
pub use attr::{
Attribute,
AttrStyle,
MetaItem,
};
@ -65,6 +66,11 @@ pub use generics::{
WhereRegionPredicate,
};
#[cfg(feature = "full")]
mod krate;
#[cfg(feature = "full")]
pub use krate::Crate;
mod ident;
pub use ident::{
Ident,
@ -155,12 +161,17 @@ mod parsing {
use nom;
#[cfg(feature = "full")]
use {expr, item};
use {expr, item, krate};
pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
unwrap("macro input", macro_input::parsing::macro_input, input)
}
#[cfg(feature = "full")]
pub fn parse_crate(input: &str) -> Result<Crate, String> {
unwrap("crate", krate::parsing::krate, input)
}
#[cfg(feature = "full")]
pub fn parse_item(input: &str) -> Result<Item, String> {
unwrap("item", item::parsing::item, input)

View File

@ -18,14 +18,14 @@ pub enum Body {
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use attr::parsing::attribute;
use attr::parsing::outer_attr;
use data::parsing::{visibility, struct_body, enum_body};
use generics::parsing::generics;
use ident::parsing::ident;
use nom::multispace;
named!(pub macro_input -> MacroInput, do_parse!(
attrs: many0!(attribute) >>
attrs: many0!(outer_attr) >>
vis: visibility >>
which: alt!(keyword!("struct") | keyword!("enum")) >>
id: ident >>
@ -55,12 +55,13 @@ pub mod parsing {
#[cfg(feature = "printing")]
mod printing {
use super::*;
use attr::FilterAttrs;
use data::{Visibility, VariantData};
use quote::{Tokens, ToTokens};
impl ToTokens for MacroInput {
fn to_tokens(&self, tokens: &mut Tokens) {
for attr in &self.attrs {
for attr in self.attrs.outer() {
attr.to_tokens(tokens);
}
if let Visibility::Public = self.vis {

View File

@ -0,0 +1,529 @@
#![feature(rustc_macro)]
#[macro_use]
extern crate serde_derive;
#[derive(Serialize)]
#[derive(Deserialize)]
struct DefaultStruct<A, B, C, D, E> where C: MyDefault, E: MyDefault {
a1: A,
#[serde(default)]
a2: B,
#[serde(default = "MyDefault::my_default")]
a3: C,
#[serde(skip_deserializing)]
a4: D,
#[serde(skip_deserializing, default = "MyDefault::my_default")]
a5: E,
}
#[derive(Serialize)]
#[derive(Deserialize)]
enum DefaultEnum<A, B, C, D, E> where C: MyDefault, E: MyDefault {
Struct {
a1: A,
#[serde(default)]
a2: B,
#[serde(default = "MyDefault::my_default")]
a3: C,
#[serde(skip_deserializing)]
a4: D,
#[serde(skip_deserializing, default = "MyDefault::my_default")]
a5: E,
},
}
#[derive(Deserialize)]
struct NoStdDefault(i8);
#[derive(Deserialize)]
struct ContainsNoStdDefault<A: MyDefault> {
#[serde(default = "MyDefault::my_default")]
a: A,
}
#[derive(Deserialize)]
struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
#[serde(skip_deserializing)]
a: A,
#[serde(skip_deserializing, default)]
b: B,
#[serde(deserialize_with = "DeserializeWith::deserialize_with", default)]
c: C,
#[serde(skip_deserializing, default = "MyDefault::my_default")]
e: E,
}
#[derive(Serialize)]
#[serde(deny_unknown_fields)]
#[derive(Deserialize)]
struct DenyUnknown {
a1: i32,
}
#[derive(Serialize)]
#[serde(rename = "Superhero")]
#[derive(Deserialize)]
struct RenameStruct {
a1: i32,
#[serde(rename = "a3")]
a2: i32,
}
#[derive(Serialize)]
#[serde(rename(serialize = "SuperheroSer", deserialize = "SuperheroDe"))]
#[derive(Deserialize)]
struct RenameStructSerializeDeserialize {
a1: i32,
#[serde(rename(serialize = "a4", deserialize = "a5"))]
a2: i32,
}
#[derive(Serialize)]
#[serde(rename = "Superhero")]
#[derive(Deserialize)]
enum RenameEnum {
#[serde(rename = "bruce_wayne")]
Batman ,
#[serde(rename = "clark_kent")]
Superman ( i8 ) ,
#[serde(rename = "diana_prince")]
WonderWoman ( i8 , i8 ) ,
#[serde(rename = "barry_allan")]
Flash {
#[serde(rename = "b")]
a : i32,
} ,
}
#[derive(Deserialize)]
#[serde ( rename ( serialize = "SuperheroSer" , deserialize = "SuperheroDe" ) ) ]
#[derive(Serialize)]
enum RenameEnumSerializeDeserialize<A> {
#[serde(rename(serialize = "dick_grayson", deserialize = "jason_todd"))]
Robin {
a: i8,
#[serde(rename(serialize = "c"))]
#[serde(rename(deserialize = "d"))]
b: A,
},
}
#[derive(Serialize)]
struct SkipSerializingStruct< 'a , B, C> where C : ShouldSkip {
a: & 'a i8,
#[serde(skip_serializing)]
b: B,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
c: C,
}
#[derive(Serialize)]
enum SkipSerializingEnum<'a, B, C> where C: ShouldSkip {
Struct {
a: &'a i8,
#[serde(skip_serializing)]
_b: B,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
c: C,
},
}
#[derive(Serialize)]
struct ContainsNotSerialize<'a, B, C, D> where B: 'a , D: SerializeWith {
a: &'a Option<i8>,
#[serde(skip_serializing)]
b: &'a B,
#[serde(skip_serializing)]
c: Option<C>,
#[serde(serialize_with = "SerializeWith::serialize_with")]
d: D,
}
#[derive(Serialize)]
struct SerializeWithStruct<'a, B> where B: SerializeWith {
a: &'a i8,
#[serde(serialize_with = "SerializeWith::serialize_with")]
b: B,
}
#[derive(Serialize)]
enum SerializeWithEnum<'a, B> where B: SerializeWith {
Struct {
a: &'a i8,
#[serde(serialize_with = "SerializeWith::serialize_with")]
b: B,
},
}
#[derive(Deserialize)]
struct DeserializeWithStruct<B> where B: DeserializeWith {
a: i8,
#[serde(deserialize_with = "DeserializeWith::deserialize_with")]
b: B,
}
#[derive(Deserialize)]
enum DeserializeWithEnum<B> where B: DeserializeWith {
Struct {
a: i8,
#[serde(deserialize_with = "DeserializeWith::deserialize_with")]
b: B,
},
}
#[derive(Deserialize)]
enum InvalidLengthEnum {
A(i32, i32, i32),
B(
#[serde(skip_deserializing)]
i32, i32, i32),
}
#[derive(Deserialize)]
struct TupleStruct(i32, i32, i32);
#[derive(Deserialize)]
struct Struct {
a: i32,
b: i32,
#[serde(skip_deserializing)]
c: i32,
}
#[derive(Deserialize)]
enum Enum {
Unit,
Simple(i32),
Seq(i32, i32, i32),
Map {
a: i32,
b: i32,
c: i32,
},
}
#[derive(Deserialize)]
struct IgnoreBase {
a: i32,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct With<T> {
t: T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct WithRef<'a, T: 'a> {
#[serde(skip_deserializing)]
t: Option<&'a T>,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct PhantomX {
x: PhantomData<X>,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct PhantomT<T> {
t: PhantomData<T>,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct NoBounds<T> {
t: T,
option: Option<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
}
#[derive(Serialize)]
#[derive(Deserialize)]
enum EnumWith<T> {
Unit,
Newtype(
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X),
Tuple(T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X),
Struct {
t: T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
},
}
#[derive(Serialize)]
struct MultipleRef<'a, 'b, 'c, T> where T: 'c, 'c: 'b, 'b: 'a {
t: T,
rrrt: &'a &'b &'c T,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct Newtype(
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X);
#[derive(Serialize)]
#[derive(Deserialize)]
struct Tuple<T>(T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X);
#[derive(Serialize)]
#[derive(Deserialize)]
enum TreeNode<D> {
Split {
left: Box<TreeNode<D>>,
right: Box<TreeNode<D>>,
},
Leaf {
data: D,
},
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct ListNode<D> {
data: D,
next: Box<ListNode<D>>,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct RecursiveA {
b: Box<RecursiveB>,
}
#[derive(Serialize)]
#[derive(Deserialize)]
enum RecursiveB { A(RecursiveA), }
#[derive(Serialize)]
#[derive(Deserialize)]
struct RecursiveGenericA<T> {
t: T,
b: Box<RecursiveGenericB<T>>,
}
#[derive(Serialize)]
#[derive(Deserialize)]
enum RecursiveGenericB<T> { T(T), A(RecursiveGenericA<T>), }
#[derive(Serialize)]
struct OptionStatic<'a> {
a: Option<&'a str>,
b: Option<&'static str>,
}
#[derive(Serialize)]
#[serde(bound = "D: SerializeWith + DeserializeWith")]
#[derive(Deserialize)]
struct WithTraits1<D, E> {
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with")]
d: D,
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with",
bound = "E: SerializeWith + DeserializeWith")]
e: E,
}
#[derive(Serialize)]
#[serde(bound(serialize = "D: SerializeWith",
deserialize = "D: DeserializeWith"))]
#[derive(Deserialize)]
struct WithTraits2<D, E> {
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with")]
d: D,
#[serde(serialize_with = "SerializeWith::serialize_with",
bound(serialize = "E: SerializeWith"))]
#[serde(deserialize_with = "DeserializeWith::deserialize_with",
bound(deserialize = "E: DeserializeWith"))]
e: E,
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct CowStr<'a>(Cow<'a, str>);
#[derive(Serialize)]
#[serde(bound(deserialize = "T::Owned: Deserialize"))]
#[derive(Deserialize)]
struct CowT < 'a , T : ? Sized + 'a + ToOwned > ( Cow < 'a , T > ) ;
#[derive(Serialize)]
struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);
#[derive(Deserialize)]
struct DeNamedTuple<A, B, C>(A, B, C);
#[derive(Serialize)]
struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> {
a: &'a A,
b: &'b mut B,
c: C,
}
#[derive(Deserialize)]
struct DeNamedMap<A, B, C> {
a: A,
b: < Vec < T > as a :: b :: Trait > :: AssociatedItem,
c: < Vec < T > > :: AssociatedItem,
}
#[derive(Serialize)]
enum SerEnum<'a, B: 'a, C: 'a, D> where for < 'a > D: 'a {
Unit,
Seq(i8, B, &'a C, &'a mut D),
Map {
a: i8,
b: B,
c: &'a C,
d: &'a mut D,
},
_Unit2,
_Seq2(i8, B, &'a C, &'a mut D),
_Map2 {
a: i8,
b: B,
c: &'a C,
d: &'a mut D,
},
}
#[derive(Serialize)]
#[derive(Deserialize)]
enum DeEnum<B, C, D> {
Unit,
Seq(i8, B, C, D),
Map {
a: i8,
b: B,
c: C,
d: D,
},
_Unit2,
_Seq2(i8, B, C, D),
_Map2 {
a: i8,
b: B,
c: C,
d: D,
},
}
#[derive(Serialize)]
enum Lifetimes<'a> {
LifetimeSeq(&'a i32),
NoLifetimeSeq(i32),
LifetimeMap {
a: &'a i32,
},
NoLifetimeMap {
a: i32,
},
}
#[derive(Serialize)]
#[derive(Deserialize)]
pub struct GenericStruct<T> {
x: T,
}
#[derive(Serialize)]
#[derive(Deserialize)]
pub struct GenericNewTypeStruct<T>(T);
#[derive(Serialize)]
#[derive(Deserialize)]
pub struct GenericTupleStruct<T, U>(T, U);
#[derive(Serialize)]
#[derive(Deserialize)]
pub enum GenericEnum<T, U: for < 'a > F<'a>> {
Unit,
NewType(T),
Seq(T, U),
Map {
x: T,
y: U,
},
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct DefaultTyParam<T: AssociatedType<X = i32> = i32> {
phantom: std :: marker :: PhantomData<T>,
}
#[derive(Serialize)]
struct UnitStruct;
#[derive(Serialize)]
struct TupleStruct(i32, i32, i32);
#[derive(Serialize)]
struct Struct {
a: i32,
b: i32,
c: i32,
}
#[derive(Serialize)]
enum Enum {
Unit,
One(i32),
Seq(i32, i32),
Map {
a: i32,
b: i32,
},
}
#[derive(Serialize)]
#[derive(Deserialize)]
struct Bounds<T: Serialize + Deserialize> {
t: T,
option: Option<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
}
#[derive(Deserialize)]
#[rustc_copy_clone_marker]
struct UnitStruct;
#[derive(Serialize)]
#[allow(dead_code)]
#[deny(unused_variables)]
enum Void { }
#[derive(Serialize)]
#[derive(Deserialize)]
struct NamedUnit;
#[derive(Deserialize)]
#[doc = r" A custom basic event not covered by the Matrix specification."]
#[derive(Debug, Serialize)]
pub struct CustomEvent {
/// The event's content.
content: String,
}

View File

@ -38,6 +38,7 @@ fn test_struct() {
vis: Visibility::Public,
attrs: vec![
Attribute {
style: AttrStyle::Outer,
value: MetaItem::List("derive".into(), vec![
MetaItem::Word("Debug".into()),
MetaItem::Word("Clone".into()),
@ -96,6 +97,7 @@ fn test_enum() {
vis: Visibility::Public,
attrs: vec![
Attribute {
style: AttrStyle::Outer,
value: MetaItem::NameValue(
"doc".into(),
Lit::Str(
@ -106,6 +108,7 @@ fn test_enum() {
is_sugared_doc: true,
},
Attribute {
style: AttrStyle::Outer,
value: MetaItem::Word("must_use".into()),
is_sugared_doc: false,
},

107
tests/test_round_trip.rs Normal file
View File

@ -0,0 +1,107 @@
#![cfg(feature = "full")]
#[macro_use]
extern crate quote;
extern crate syn;
extern crate syntex_pos;
extern crate syntex_syntax;
extern crate walkdir;
use syntex_pos::Span;
use syntex_syntax::ast::{self, Attribute, TyParam};
use syntex_syntax::fold::{self, Folder};
use syntex_syntax::parse::{self, ParseSess, PResult};
use std::fs::File;
use std::io::{self, Read, Write};
macro_rules! errorf {
($($tt:tt)*) => {
write!(io::stderr(), $($tt)*).unwrap();
};
}
#[test]
fn test_round_trip() {
let mut success = true;
for entry in walkdir::WalkDir::new("tests/cases").into_iter() {
let entry = entry.unwrap();
let path = entry.path();
if path.extension().map(|e| e != "rs").unwrap_or(true) {
continue;
}
errorf!("=== {}: ", path.display());
let mut file = File::open(path).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
let krate = match syn::parse_crate(&content) {
Ok(krate) => krate,
Err(msg) => {
errorf!("syn failed to parse\n{}\n", msg);
success = false;
continue;
}
};
let back = quote!(#krate).to_string();
let sess = ParseSess::new();
let before = syntex_parse(content, &sess).unwrap();
let after = match syntex_parse(back, &sess) {
Ok(after) => after,
Err(mut diagnostic) => {
errorf!("syntex failed to parse");
diagnostic.emit();
success = false;
continue;
}
};
if before == after {
errorf!("pass\n");
} else {
errorf!("FAIL\nbefore: {:?}\nafter: {:?}\n", before, after);
success = false;
}
}
assert!(success);
}
fn syntex_parse<'a>(content: String, sess: &'a ParseSess) -> PResult<'a, ast::Crate> {
let name = "test_round_trip".to_string();
let cfg = Vec::new();
parse::parse_crate_from_source_str(name, content, cfg, sess).map(respan_crate)
}
fn respan_crate(krate: ast::Crate) -> ast::Crate {
struct Respanner;
impl Folder for Respanner {
fn new_span(&mut self, _: Span) -> Span {
syntex_pos::DUMMY_SP
}
fn fold_ty_param(&mut self, tp: TyParam) -> TyParam {
TyParam {
// default fold_ty_param does not fold the span
span: self.new_span(tp.span),
.. fold::noop_fold_ty_param(tp, self)
}
}
fn fold_attribute(&mut self, mut at: Attribute) -> Option<Attribute> {
at.node.id.0 = 0;
fold::noop_fold_attribute(at, self)
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
}
}
Respanner.fold_crate(krate)
}

View File

@ -1,606 +0,0 @@
extern crate syn;
#[macro_use]
extern crate quote;
/// These are all of the items from serde_codegen's test suite.
/// Obnoxious whitespace has been added in an attempt to fool the parser.
#[test]
fn test_all() {
for s in ITEMS {
let ast = syn::parse_macro_input(s).unwrap();
let tokens = quote!(#ast).to_string();
assert_eq!(ast, syn::parse_macro_input(&tokens).unwrap());
}
static ITEMS: &'static [&'static str] = &[
r#"
# [ derive ( Serialize ) ]
#[derive(Deserialize)]
struct DefaultStruct <A , B, C, D, E> where C : MyDefault , E: MyDefault {
a1 : A,
#[serde(default)]
a2: B,
#[serde(default = "MyDefault::my_default")]
a3: C,
#[serde(skip_deserializing)]
a4: D,
#[serde(skip_deserializing, default = "MyDefault::my_default")]
a5: E,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
enum DefaultEnum<A, B, C, D, E> where C: MyDefault, E: MyDefault {
Struct {
a1: A,
#[serde(default)]
a2: B,
#[serde(default = "MyDefault::my_default")]
a3: C,
#[serde(skip_deserializing)]
a4: D,
#[serde(skip_deserializing, default = "MyDefault::my_default")]
a5: E,
},
}
"#,
r#"
#[derive(Deserialize)]
struct NoStdDefault(i8);
"#,
r#"
#[derive(Deserialize)]
struct ContainsNoStdDefault <A : MyDefault> {
#[serde(default = "MyDefault::my_default")]
a: A,
}
"#,
r#"
#[derive(Deserialize)]
struct ContainsNotDeserialize<A, B, C: DeserializeWith, E: MyDefault> {
#[serde(skip_deserializing)]
a: A,
#[serde(skip_deserializing, default)]
b: B,
#[serde(deserialize_with = "DeserializeWith::deserialize_with", default)]
c: C,
#[serde(skip_deserializing, default = "MyDefault::my_default")]
e: E,
}
"#,
r#"
#[derive(Serialize)]
#[serde(deny_unknown_fields)]
#[derive(Deserialize)]
struct DenyUnknown {
a1: i32,
}
"#,
r#"
#[derive(Serialize)]
#[serde(rename = "Superhero")]
#[derive(Deserialize)]
struct RenameStruct {
a1: i32,
#[serde(rename = "a3")]
a2: i32,
}
"#,
r#"
#[derive(Serialize)]
#[serde(rename(serialize = "SuperheroSer", deserialize = "SuperheroDe"))]
#[derive(Deserialize)]
struct RenameStructSerializeDeserialize {
a1: i32,
#[serde(rename(serialize = "a4", deserialize = "a5"))]
a2: i32,
}
"#,
r#"
#[derive(Serialize)]
#[serde(rename = "Superhero")]
#[derive(Deserialize)]
enum RenameEnum {
#[serde(rename = "bruce_wayne")]
Batman ,
#[serde(rename = "clark_kent")]
Superman ( i8 ) ,
#[serde(rename = "diana_prince")]
WonderWoman ( i8 , i8 ) ,
#[serde(rename = "barry_allan")]
Flash {
#[serde(rename = "b")]
a : i32,
} ,
}
"#,
r#"
#[derive(Deserialize)]
#[serde ( rename ( serialize = "SuperheroSer" , deserialize = "SuperheroDe" ) ) ]
#[derive(Serialize)]
enum RenameEnumSerializeDeserialize<A> {
#[serde(rename(serialize = "dick_grayson", deserialize = "jason_todd"))]
Robin {
a: i8,
#[serde(rename(serialize = "c"))]
#[serde(rename(deserialize = "d"))]
b: A,
},
}
"#,
r#"
#[derive(Serialize)]
struct SkipSerializingStruct< 'a , B, C> where C : ShouldSkip {
a: & 'a i8,
#[serde(skip_serializing)]
b: B,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
c: C,
}
"#,
r#"
#[derive(Serialize)]
enum SkipSerializingEnum<'a, B, C> where C: ShouldSkip {
Struct {
a: &'a i8,
#[serde(skip_serializing)]
_b: B,
#[serde(skip_serializing_if = "ShouldSkip::should_skip")]
c: C,
},
}
"#,
r#"
#[derive(Serialize)]
struct ContainsNotSerialize<'a, B, C, D> where B: 'a , D: SerializeWith {
a: &'a Option<i8>,
#[serde(skip_serializing)]
b: &'a B,
#[serde(skip_serializing)]
c: Option<C>,
#[serde(serialize_with = "SerializeWith::serialize_with")]
d: D,
}
"#,
r#"
#[derive(Serialize)]
struct SerializeWithStruct<'a, B> where B: SerializeWith {
a: &'a i8,
#[serde(serialize_with = "SerializeWith::serialize_with")]
b: B,
}
"#,
r#"
#[derive(Serialize)]
enum SerializeWithEnum<'a, B> where B: SerializeWith {
Struct {
a: &'a i8,
#[serde(serialize_with = "SerializeWith::serialize_with")]
b: B,
},
}
"#,
r#"
#[derive(Deserialize)]
struct DeserializeWithStruct<B> where B: DeserializeWith {
a: i8,
#[serde(deserialize_with = "DeserializeWith::deserialize_with")]
b: B,
}
"#,
r#"
#[derive(Deserialize)]
enum DeserializeWithEnum<B> where B: DeserializeWith {
Struct {
a: i8,
#[serde(deserialize_with = "DeserializeWith::deserialize_with")]
b: B,
},
}
"#,
r#"
#[derive(Deserialize)]
enum InvalidLengthEnum {
A(i32, i32, i32),
B(
#[serde(skip_deserializing)]
i32, i32, i32),
}
"#,
r#"
#[derive(Deserialize)]
struct TupleStruct(i32, i32, i32);
"#,
r#"
#[derive(Deserialize)]
struct Struct {
a: i32,
b: i32,
#[serde(skip_deserializing)]
c: i32,
}
"#,
r#"
#[derive(Deserialize)]
enum Enum {
Unit,
Simple(i32),
Seq(i32, i32, i32),
Map {
a: i32,
b: i32,
c: i32,
},
}
"#,
r#"
#[derive(Deserialize)]
struct IgnoreBase {
a: i32,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct With<T> {
t: T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct WithRef<'a, T: 'a> {
#[serde(skip_deserializing)]
t: Option<&'a T>,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct PhantomX {
x: PhantomData<X>,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct PhantomT<T> {
t: PhantomData<T>,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct NoBounds<T> {
t: T,
option: Option<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
enum EnumWith<T> {
Unit,
Newtype(
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X),
Tuple(T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X),
Struct {
t: T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
x: X,
},
}
"#,
r#"
#[derive(Serialize)]
struct MultipleRef<'a, 'b, 'c, T> where T: 'c, 'c: 'b, 'b: 'a {
t: T,
rrrt: &'a &'b &'c T,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct Newtype(
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X);
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct Tuple<T>(T,
#[serde(serialize_with = "ser_x", deserialize_with = "de_x")]
X);
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
enum TreeNode<D> {
Split {
left: Box<TreeNode<D>>,
right: Box<TreeNode<D>>,
},
Leaf {
data: D,
},
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct ListNode<D> {
data: D,
next: Box<ListNode<D>>,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct RecursiveA {
b: Box<RecursiveB>,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
enum RecursiveB { A(RecursiveA), }
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct RecursiveGenericA<T> {
t: T,
b: Box<RecursiveGenericB<T>>,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
enum RecursiveGenericB<T> { T(T), A(RecursiveGenericA<T>), }
"#,
r#"
#[derive(Serialize)]
struct OptionStatic<'a> {
a: Option<&'a str>,
b: Option<&'static str>,
}
"#,
r#"
#[derive(Serialize)]
#[serde(bound = "D: SerializeWith + DeserializeWith")]
#[derive(Deserialize)]
struct WithTraits1<D, E> {
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with")]
d: D,
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with",
bound = "E: SerializeWith + DeserializeWith")]
e: E,
}
"#,
r#"
#[derive(Serialize)]
#[serde(bound(serialize = "D: SerializeWith",
deserialize = "D: DeserializeWith"))]
#[derive(Deserialize)]
struct WithTraits2<D, E> {
#[serde(serialize_with = "SerializeWith::serialize_with",
deserialize_with = "DeserializeWith::deserialize_with")]
d: D,
#[serde(serialize_with = "SerializeWith::serialize_with",
bound(serialize = "E: SerializeWith"))]
#[serde(deserialize_with = "DeserializeWith::deserialize_with",
bound(deserialize = "E: DeserializeWith"))]
e: E,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct CowStr<'a>(Cow<'a, str>);
"#,
r#"
#[derive(Serialize)]
#[serde(bound(deserialize = "T::Owned: Deserialize"))]
#[derive(Deserialize)]
struct CowT < 'a , T : ? Sized + 'a + ToOwned > ( Cow < 'a , T > ) ;
"#,
r#"
#[derive(Serialize)]
struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);
"#,
r#"
#[derive(Deserialize)]
struct DeNamedTuple<A, B, C>(A, B, C);
"#,
r#"
#[derive(Serialize)]
struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> {
a: &'a A,
b: &'b mut B,
c: C,
}
"#,
r#"
#[derive(Deserialize)]
struct DeNamedMap<A, B, C> {
a: A,
b: < Vec < T > as a :: b :: Trait > :: AssociatedItem,
c: < Vec < T > > :: AssociatedItem,
}
"#,
r#"
#[derive(Serialize)]
enum SerEnum<'a, B: 'a, C: 'a, D> where for < 'a > D: 'a {
Unit,
Seq(i8, B, &'a C, &'a mut D),
Map {
a: i8,
b: B,
c: &'a C,
d: &'a mut D,
},
_Unit2,
_Seq2(i8, B, &'a C, &'a mut D),
_Map2 {
a: i8,
b: B,
c: &'a C,
d: &'a mut D,
},
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
enum DeEnum<B, C, D> {
Unit,
Seq(i8, B, C, D),
Map {
a: i8,
b: B,
c: C,
d: D,
},
_Unit2,
_Seq2(i8, B, C, D),
_Map2 {
a: i8,
b: B,
c: C,
d: D,
},
}
"#,
r#"
#[derive(Serialize)]
enum Lifetimes<'a> {
LifetimeSeq(&'a i32),
NoLifetimeSeq(i32),
LifetimeMap {
a: &'a i32,
},
NoLifetimeMap {
a: i32,
},
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
pub struct GenericStruct<T> {
x: T,
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
pub struct GenericNewTypeStruct<T>(T);
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
pub struct GenericTupleStruct<T, U>(T, U);
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
pub enum GenericEnum<T, U: for < 'a > F<'a>> {
Unit,
NewType(T),
Seq(T, U),
Map {
x: T,
y: U,
},
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct DefaultTyParam<T: AssociatedType<X = i32> = i32> {
phantom: std :: marker :: PhantomData<T>,
}
"#,
r#"
#[derive(Serialize)]
struct UnitStruct;
"#,
r#"
#[derive(Serialize)]
struct TupleStruct(i32, i32, i32);
"#,
r#"
#[derive(Serialize)]
struct Struct {
a: i32,
b: i32,
c: i32,
}
"#,
r#"
#[derive(Serialize)]
enum Enum {
Unit,
One(i32),
Seq(i32, i32),
Map {
a: i32,
b: i32,
},
}
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct Bounds<T: Serialize + Deserialize> {
t: T,
option: Option<T>,
boxed: Box<T>,
option_boxed: Option<Box<T>>,
}
"#,
r#"
#[derive(Deserialize)]
#[rustc_copy_clone_marker]
struct UnitStruct;
"#,
r#"
#[derive(Serialize)]
#[allow(dead_code)]
#[deny(unused_variables)]
enum Void { }
"#,
r#"
#[derive(Serialize)]
#[derive(Deserialize)]
struct NamedUnit;
"#,
r#"
#[derive(Deserialize)]
#[doc = r" A custom basic event not covered by the Matrix specification."]
#[derive(Debug, Serialize)]
pub struct CustomEvent {
/// The event's content.
content: String,
}
"#,
];
}