diff --git a/.travis.yml b/.travis.yml index 769366c..9141a31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,12 @@ language: rust -rust: - - stable - - beta - - nightly +matrix: + include: + - rust: stable + - rust: beta + - rust: nightly + script: + - cargo test + - cargo test --manifest-path testcrate/Cargo.toml +script: + - cargo test diff --git a/Cargo.lock b/Cargo.lock index 9e7c575..ed99e14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,12 +1,3 @@ -[root] -name = "derive-new" -version = "0.5.0" -dependencies = [ - "compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cfg-if" version = "0.1.2" @@ -14,55 +5,118 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "compiletest_rs" -version = "0.3.1" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "derive-new" +version = "0.5.0" +dependencies = [ + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "diff" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "filetime" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "getopts" -version = "0.2.15" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "libc" -version = "0.2.32" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.8" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "quote" -version = "0.3.15" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "redox_syscall" -version = "0.1.31" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -72,38 +126,86 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "0.11.11" +version = "0.12.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "testcrate" +version = "0.1.0" dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.0", ] [[package]] name = "unicode-xid" -version = "0.0.4" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f4663adfd113e17109c35c2067194eca782a5baf9c90f4696ca13d04631adb" -"checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" -"checksum filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "aa75ec8f7927063335a9583e7fa87b0110bb888cf766dc01b54c0ff70d760c8e" -"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" -"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" +"checksum compiletest_rs 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5af251da1bdcfad5686d1c456c67673a66005ae0cb8cc683f16d011b8206e7e3" +"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" +"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum libc 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)" = "56aebce561378d99a0bb578f8cb15b6114d2a1814a6c7949bbe646d968bb4fa9" +"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" +"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" +"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" +"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)" = "517f6da31bc53bf080b9a77b29fbd0ff8da2f5a2ebd24c73c2238274a94ac7cb" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/Cargo.toml b/Cargo.toml index 7a3a4d9..d10dc4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,10 @@ repository = "https://github.com/nrc/derive-new" [lib] proc-macro = true -[features] -compiletest = ["compiletest_rs"] - [dependencies] -quote = "0.3" -compiletest_rs = { version = "0.3", optional = true } +proc-macro2 = "0.2" +quote = "0.4" +syn = "0.12" -[dependencies.syn] -version = "0.11" -features = ["full"] +[workspace] +members = ["testcrate"] diff --git a/src/lib.rs b/src/lib.rs index 3f466f5..d95fe12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -110,87 +110,97 @@ #![recursion_limit = "192"] extern crate proc_macro; +#[macro_use] extern crate syn; #[macro_use] extern crate quote; +extern crate proc_macro2; + +macro_rules! my_quote { + ($($t:tt)*) => (quote_spanned!(proc_macro2::Span::call_site() => $($t)*)) +} use proc_macro::TokenStream; #[proc_macro_derive(new, attributes(new))] pub fn derive(input: TokenStream) -> TokenStream { - let input: String = input.to_string(); - let ast = syn::parse_macro_input(&input).expect("Couldn't parse item"); - let result = match ast.body { - syn::Body::Enum(ref variants) => new_for_enum(&ast, &variants), - syn::Body::Struct(ref variant_data) => new_for_struct(&ast, &variant_data, None), + let ast: syn::DeriveInput = syn::parse(input).expect("Couldn't parse item"); + let result = match ast.data { + syn::Data::Enum(ref e) => new_for_enum(&ast, e), + syn::Data::Struct(ref s) => new_for_struct(&ast, &s.fields, None), + syn::Data::Union(_) => panic!("doesn't work with unions yet"), }; - result.to_string().parse().expect("Couldn't parse string to tokens") + result.into() } -fn new_for_struct(ast: &syn::MacroInput, variant_data: &syn::VariantData, +fn new_for_struct(ast: &syn::DeriveInput, + fields: &syn::Fields, variant: Option<&syn::Ident>) -> quote::Tokens { - match *variant_data { - syn::VariantData::Struct(ref fields) => { - new_impl(&ast, Some(&fields), true, variant) + match *fields { + syn::Fields::Named(ref fields) => { + new_impl(&ast, Some(&fields.named), true, variant) }, - syn::VariantData::Unit => { + syn::Fields::Unit => { new_impl(&ast, None, false, variant) }, - syn::VariantData::Tuple(ref fields) => { - new_impl(&ast, Some(&fields), false, variant) + syn::Fields::Unnamed(ref fields) => { + new_impl(&ast, Some(&fields.unnamed), false, variant) }, } } -fn new_for_enum(ast: &syn::MacroInput, variants: &[syn::Variant]) -> quote::Tokens { - if variants.is_empty() { +fn new_for_enum(ast: &syn::DeriveInput, data: &syn::DataEnum) -> quote::Tokens { + if data.variants.is_empty() { panic!("#[derive(new)] cannot be implemented for enums with zero variants"); } - let impls = variants.iter().map(|v| { + let impls = data.variants.iter().map(|v| { if v.discriminant.is_some() { panic!("#[derive(new)] cannot be implemented for enums with discriminants"); } - new_for_struct(ast, &v.data, Some(&v.ident)) + new_for_struct(ast, &v.fields, Some(&v.ident)) }); - quote!(#(#impls)*) + my_quote!(#(#impls)*) } -fn new_impl(ast: &syn::MacroInput, fields: Option<&[syn::Field]>, +fn new_impl(ast: &syn::DeriveInput, + fields: Option<&syn::punctuated::Punctuated>, named: bool, variant: Option<&syn::Ident>) -> quote::Tokens { let name = &ast.ident; let unit = fields.is_none(); - let fields: Vec<_> = fields.unwrap_or(&[]).iter() + let empty = Default::default(); + let fields: Vec<_> = fields.unwrap_or(&empty).iter() .enumerate().map(|(i, f)| FieldExt::new(f, i, named)).collect(); let args = fields.iter() .filter(|f| f.needs_arg()).map(|f| f.as_arg()); let inits = fields.iter() .map(|f| f.as_init()); let inits = if unit { - quote!() + my_quote!() } else if named { - quote![{ #(#inits),* }] + my_quote![{ #(#inits),* }] } else { - quote![( #(#inits),* )] + my_quote![( #(#inits),* )] }; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - let (new, qual, doc) = match variant { + let (mut new, qual, doc) = match variant { None => ( - syn::Ident::new("new"), - quote!(), + syn::Ident::from("new"), + my_quote!(), format!("Constructs a new `{}`.", name), ), Some(ref variant) => ( - syn::Ident::new(format!("new_{}", to_snake_case(variant.as_ref()))), - quote!(::#variant), + syn::Ident::from(format!("new_{}", to_snake_case(variant.as_ref()))), + my_quote!(::#variant), format!("Constructs a new `{}::{}`.", name, variant), ), }; + new.span = proc_macro2::Span::call_site(); let lint_attrs = collect_parent_lint_attrs(&ast.attrs); - let lint_attrs = quote![#(#lint_attrs),*]; - quote! { + let lint_attrs = my_quote![#(#lint_attrs),*]; + my_quote! { impl #impl_generics #name #ty_generics #where_clause { #[doc = #doc] #lint_attrs @@ -202,9 +212,9 @@ fn new_impl(ast: &syn::MacroInput, fields: Option<&[syn::Field]>, } fn collect_parent_lint_attrs(attrs: &[syn::Attribute]) -> Vec { - fn is_lint(item: &syn::MetaItem) -> bool { - if let syn::MetaItem::List(ref ident, _) = *item { - match ident.as_ref() { + fn is_lint(item: &syn::Meta) -> bool { + if let syn::Meta::List(ref l) = *item { + match l.ident.as_ref() { "allow" | "deny" | "forbid" | "warn" => return true, _ => (), } @@ -212,10 +222,10 @@ fn collect_parent_lint_attrs(attrs: &[syn::Attribute]) -> Vec { false } - fn is_cfg_attr_lint(item: &syn::MetaItem) -> bool { - if let syn::MetaItem::List(ref ident, ref items) = *item { - if ident.as_ref() == "cfg_attr" && items.len() == 2 { - if let syn::NestedMetaItem::MetaItem(ref item) = items[1] { + fn is_cfg_attr_lint(item: &syn::Meta) -> bool { + if let syn::Meta::List(ref l) = *item { + if l.ident.as_ref() == "cfg_attr" && l.nested.len() == 2 { + if let syn::NestedMeta::Meta(ref item) = l.nested[1] { return is_lint(item); } } @@ -223,68 +233,78 @@ fn collect_parent_lint_attrs(attrs: &[syn::Attribute]) -> Vec { false } - attrs.iter().filter(|attr| { - is_lint(&attr.value) || is_cfg_attr_lint(&attr.value) - }).cloned().collect() + attrs.iter() + .filter_map(|a| { + a.interpret_meta().map(|m| (m, a)) + }) + .filter(|&(ref m, _)| is_lint(m) || is_cfg_attr_lint(m)) + .map(|p| p.1) + .cloned() + .collect() } enum FieldAttr { Default, - Value(syn::Expr), + Value(proc_macro2::TokenStream), } impl FieldAttr { pub fn as_tokens(&self) -> quote::Tokens { match *self { - FieldAttr::Default => quote!(::std::default::Default::default()), - FieldAttr::Value(ref s) => quote!(#s), + FieldAttr::Default => my_quote!(::std::default::Default::default()), + FieldAttr::Value(ref s) => my_quote!(#s), } } pub fn parse(attrs: &[syn::Attribute]) -> Option { - use syn::{MetaItem, NestedMetaItem, AttrStyle}; + use syn::{Meta, NestedMeta, AttrStyle}; let mut result = None; for attr in attrs.iter() { - if attr.style == AttrStyle::Outer && attr.value.name() == "new" { - if let MetaItem::List(_, ref items) = attr.value { - for item in items { - if result.is_some() { - panic!("Expected at most one #[new] attribute"); + match attr.style { + AttrStyle::Outer => {} + _ => continue, + } + let meta = match attr.interpret_meta() { + Some(meta) => meta, + None => continue, + }; + let list = match meta { + Meta::List(l) => l, + _ => panic!("Invalid #[new] attribute, expected #[new(..)]"), + }; + if result.is_some() { + panic!("Expected at most one #[new] attribute"); + } + for item in list.nested.iter() { + match *item { + NestedMeta::Meta(Meta::Word(ref ident)) => { + if ident.as_ref() == "default" { + result = Some(FieldAttr::Default); + } else { + panic!("Invalid #[new] attribute: #[new({})]", ident); } - match *item { - NestedMetaItem::MetaItem(MetaItem::Word(ref ident)) => { - if ident.as_ref() == "default" { - result = Some(FieldAttr::Default); - } else { - panic!("Invalid #[new] attribute: #[new({})]", ident); - } - }, - NestedMetaItem::MetaItem(MetaItem::NameValue(ref ident, ref lit)) => { - if let syn::Lit::Str(ref s, _) = *lit { - if ident.as_ref() == "value" { - let expr = syn::parse_expr(s.as_ref()).ok() - .expect(&format!( - "Invalid expression in #[new]: `{}`", s)); - result = Some(FieldAttr::Value(expr)); - } else { - panic!("Invalid #[new] attribute: #[new({} = ..)]", ident); - } - } else { - panic!("Non-string literal value in #[new] attribute"); - } - }, - NestedMetaItem::MetaItem(MetaItem::List(ref ident, _)) => { - panic!("Invalid #[new] attribute: #[new({}(..))]", ident); - }, - NestedMetaItem::Literal(_) => { - panic!("Invalid #[new] attribute: literal value in #[new(..)]"); + }, + NestedMeta::Meta(Meta::NameValue(ref kv)) => { + if let syn::Lit::Str(ref s) = kv.lit { + if kv.ident.as_ref() == "value" { + let tokens = s.value().parse().ok() + .expect(&format!( + "Invalid expression in #[new]: `{}`", s.value())); + result = Some(FieldAttr::Value(tokens)); + } else { + panic!("Invalid #[new] attribute: #[new({} = ..)]", kv.ident); } + } else { + panic!("Non-string literal value in #[new] attribute"); } + }, + NestedMeta::Meta(Meta::List(ref l)) => { + panic!("Invalid #[new] attribute: #[new({}(..))]", l.ident); + }, + NestedMeta::Literal(_) => { + panic!("Invalid #[new] attribute: literal value in #[new(..)]"); } - - } else { - panic!("Invalid #[new] attribute, expected #[new(..)]"); } } } @@ -294,7 +314,7 @@ impl FieldAttr { } struct FieldExt<'a> { - ty: &'a syn::Ty, + ty: &'a syn::Type, attr: Option, ident: syn::Ident, named: bool, @@ -308,7 +328,7 @@ impl<'a> FieldExt<'a> { ident: if named { field.ident.clone().unwrap() } else { - syn::Ident::new(format!("f{}", idx)) + syn::Ident::from(format!("f{}", idx)) }, named: named, } @@ -320,9 +340,10 @@ impl<'a> FieldExt<'a> { pub fn is_phantom_data(&self) -> bool { match *self.ty { - syn::Ty::Path(None, ref path) => { - path.segments.as_slice().last() - .map(|x| x.ident.as_ref() == "PhantomData").unwrap_or(false) + syn::Type::Path(syn::TypePath { qself: None, ref path }) => { + path.segments.last() + .map(|x| x.value().ident.as_ref() == "PhantomData") + .unwrap_or(false) }, _ => false, } @@ -335,23 +356,23 @@ impl<'a> FieldExt<'a> { pub fn as_arg(&self) -> quote::Tokens { let f_name = &self.ident; let ty = &self.ty; - quote!(#f_name: #ty) + my_quote!(#f_name: #ty) } pub fn as_init(&self) -> quote::Tokens { let f_name = &self.ident; let init = if self.is_phantom_data() { - quote!(::std::marker::PhantomData) + my_quote!(::std::marker::PhantomData) } else { match self.attr { - None => quote!(#f_name), + None => my_quote!(#f_name), Some(ref attr) => attr.as_tokens(), } }; if self.named { - quote!(#f_name: #init) + my_quote!(#f_name: #init) } else { - quote!(#init) + my_quote!(#init) } } } diff --git a/testcrate/Cargo.toml b/testcrate/Cargo.toml new file mode 100644 index 0000000..647bf37 --- /dev/null +++ b/testcrate/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "testcrate" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] +derive-new = { path = ".." } + +[dev-dependencies] +compiletest_rs = "0.3.7" + +[[test]] +name = "compile-fail" +path = "tests/compile-fail.rs" +harness = false diff --git a/testcrate/src/lib.rs b/testcrate/src/lib.rs new file mode 100644 index 0000000..31e1bb2 --- /dev/null +++ b/testcrate/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/testcrate/tests/compile-fail.rs b/testcrate/tests/compile-fail.rs new file mode 100644 index 0000000..44dc547 --- /dev/null +++ b/testcrate/tests/compile-fail.rs @@ -0,0 +1,25 @@ +extern crate compiletest_rs as compiletest; + +use std::env; +use std::path::PathBuf; + +fn run_mode(mode: &'static str) { + let mut config = compiletest::Config::default(); + config.mode = mode.parse().expect("invalid mode"); + let mut me = env::current_exe().unwrap(); + me.pop(); + config.target_rustcflags = Some(format!("-L {}", me.display())); + let src = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + config.src_base = src.join("tests").join(mode); + + me.pop(); + me.pop(); + config.build_base = me.join("tests").join(mode); + config.filter = env::args().nth(1); + + compiletest::run_tests(&config); +} + +fn main() { + run_mode("compile-fail"); +} diff --git a/tests/compile-fail/enum-with-discriminants.rs b/testcrate/tests/compile-fail/enum-with-discriminants.rs similarity index 100% rename from tests/compile-fail/enum-with-discriminants.rs rename to testcrate/tests/compile-fail/enum-with-discriminants.rs diff --git a/tests/compile-fail/enum-zero-variants.rs b/testcrate/tests/compile-fail/enum-zero-variants.rs similarity index 100% rename from tests/compile-fail/enum-zero-variants.rs rename to testcrate/tests/compile-fail/enum-zero-variants.rs diff --git a/tests/compile-fail/multiple-new-attrs.rs b/testcrate/tests/compile-fail/multiple-new-attrs.rs similarity index 100% rename from tests/compile-fail/multiple-new-attrs.rs rename to testcrate/tests/compile-fail/multiple-new-attrs.rs diff --git a/tests/compile-fail/new-invalid-attr-type.rs b/testcrate/tests/compile-fail/new-invalid-attr-type.rs similarity index 100% rename from tests/compile-fail/new-invalid-attr-type.rs rename to testcrate/tests/compile-fail/new-invalid-attr-type.rs diff --git a/tests/compile-fail/new-invalid-value.rs b/testcrate/tests/compile-fail/new-invalid-value.rs similarity index 57% rename from tests/compile-fail/new-invalid-value.rs rename to testcrate/tests/compile-fail/new-invalid-value.rs index b18bd1e..a49ed4e 100644 --- a/tests/compile-fail/new-invalid-value.rs +++ b/testcrate/tests/compile-fail/new-invalid-value.rs @@ -2,8 +2,8 @@ extern crate derive_new; #[derive(new)] -//~^ ERROR proc-macro derive -//~^^ HELP Invalid expression in #[new]: `hello@world` +//~^ ERROR produced unparseable tokens +//~^^ ERROR expected one of struct Foo { #[new(value = "hello@world")] x: i32, diff --git a/tests/compile-fail/new-list-invalid.rs b/testcrate/tests/compile-fail/new-list-invalid.rs similarity index 100% rename from tests/compile-fail/new-list-invalid.rs rename to testcrate/tests/compile-fail/new-list-invalid.rs diff --git a/tests/compile-fail/new-name-value-invalid.rs b/testcrate/tests/compile-fail/new-name-value-invalid.rs similarity index 100% rename from tests/compile-fail/new-name-value-invalid.rs rename to testcrate/tests/compile-fail/new-name-value-invalid.rs diff --git a/tests/compile-fail/new-nested-list.rs b/testcrate/tests/compile-fail/new-nested-list.rs similarity index 100% rename from tests/compile-fail/new-nested-list.rs rename to testcrate/tests/compile-fail/new-nested-list.rs diff --git a/tests/compile-fail/new-nested-literal.rs b/testcrate/tests/compile-fail/new-nested-literal.rs similarity index 100% rename from tests/compile-fail/new-nested-literal.rs rename to testcrate/tests/compile-fail/new-nested-literal.rs diff --git a/tests/compile-fail/new-non-literal-value.rs b/testcrate/tests/compile-fail/new-non-literal-value.rs similarity index 100% rename from tests/compile-fail/new-non-literal-value.rs rename to testcrate/tests/compile-fail/new-non-literal-value.rs diff --git a/tests/compile-test.rs b/tests/compile-test.rs deleted file mode 100644 index a22f20e..0000000 --- a/tests/compile-test.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![cfg(feature = "compiletest")] - -extern crate compiletest_rs as compiletest; - -use std::path::PathBuf; - -fn run_mode(mode: &'static str) { - let mut config = compiletest::default_config(); - let cfg_mode = mode.parse().ok().expect("Invalid mode"); - - config.target_rustcflags = Some("-Ltarget/debug/ -Ltarget/debug/deps/".to_owned()); - config.mode = cfg_mode; - config.src_base = PathBuf::from(format!("tests/{}", mode)); - - compiletest::run_tests(&config); -} - -#[test] -fn compile_test() { - run_mode("compile-fail"); -}