diff --git a/derive_builder/src/lib.rs b/derive_builder/src/lib.rs index 5af714a..52ac260 100644 --- a/derive_builder/src/lib.rs +++ b/derive_builder/src/lib.rs @@ -645,13 +645,13 @@ //! #[derive(Debug, PartialEq, Default, Builder, Clone)] //! #[builder(derive(Debug, PartialEq))] //! struct Lorem { -//! #[builder(setter(into), field(type = "u32"))] +//! #[builder(setter(into), field(ty = "u32"))] //! ipsum: u32, //! -//! #[builder(field(type = "String", build = "()"))] +//! #[builder(field(ty = "String", build = "()"))] //! dolor: (), //! -//! #[builder(field(type = "&'static str", build = "self.amet.parse()?"))] +//! #[builder(field(ty = "&'static str", build = "self.amet.parse()?"))] //! amet: u32, //! } //! @@ -670,7 +670,7 @@ //! # } //! ``` //! -//! The builder field type (`type =`) must implement `Default`. +//! The builder field type (`ty =`) must implement `Default`. //! //! The argument to `build` must be a literal string containing Rust code for the contents of a block, which must evaluate to the type of the target field. //! It may refer to the builder struct as `self`, use `?`, etc. diff --git a/derive_builder/tests/builder_field_custom.rs b/derive_builder/tests/builder_field_custom.rs index 35e5e8e..a1a5ee8 100644 --- a/derive_builder/tests/builder_field_custom.rs +++ b/derive_builder/tests/builder_field_custom.rs @@ -7,10 +7,10 @@ use std::num::ParseIntError; #[derive(Debug, PartialEq, Default, Builder, Clone)] pub struct Lorem { - #[builder(field(type = "Option", build = "self.ipsum.unwrap_or(42) + 1"))] + #[builder(field(ty = "Option", build = "self.ipsum.unwrap_or(42) + 1"))] ipsum: usize, - #[builder(setter(into), field(type = "String", build = "self.dolor.parse()?"))] + #[builder(setter(into), field(ty = "String", build = "self.dolor.parse()?"))] dolor: u32, } diff --git a/derive_builder/tests/compile-fail/builder_field_custom.rs b/derive_builder/tests/compile-fail/builder_field_custom.rs index 74c37ef..38a54c0 100644 --- a/derive_builder/tests/compile-fail/builder_field_custom.rs +++ b/derive_builder/tests/compile-fail/builder_field_custom.rs @@ -11,11 +11,11 @@ pub struct Lorem { ipsum: usize, // `default` is incompatible with `field.type`, even without `field.build` - #[builder(default = "2", field(type = "usize"))] + #[builder(default = "2", field(ty = "usize"))] sit: usize, // Both errors can occur on the same field - #[builder(default = "3", field(type = "usize", build = "self.ipsum + 42"))] + #[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))] amet: usize, } diff --git a/derive_builder/tests/compile-fail/builder_field_custom.stderr b/derive_builder/tests/compile-fail/builder_field_custom.stderr index 6cfc733..b9737a9 100644 --- a/derive_builder/tests/compile-fail/builder_field_custom.stderr +++ b/derive_builder/tests/compile-fail/builder_field_custom.stderr @@ -4,20 +4,20 @@ error: #[builder(default)] and #[builder(field(build="..."))] cannot be used tog 8 | default = "1", | ^^^ -error: #[builder(default)] and #[builder(field(type="..."))] cannot be used together +error: #[builder(default)] and #[builder(field(ty="..."))] cannot be used together --> tests/compile-fail/builder_field_custom.rs:14:25 | -14 | #[builder(default = "2", field(type = "usize"))] +14 | #[builder(default = "2", field(ty = "usize"))] | ^^^ error: #[builder(default)] and #[builder(field(build="..."))] cannot be used together --> tests/compile-fail/builder_field_custom.rs:18:25 | -18 | #[builder(default = "3", field(type = "usize", build = "self.ipsum + 42"))] +18 | #[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))] | ^^^ -error: #[builder(default)] and #[builder(field(type="..."))] cannot be used together +error: #[builder(default)] and #[builder(field(ty="..."))] cannot be used together --> tests/compile-fail/builder_field_custom.rs:18:25 | -18 | #[builder(default = "3", field(type = "usize", build = "self.ipsum + 42"))] +18 | #[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))] | ^^^ diff --git a/derive_builder_core/Cargo.toml b/derive_builder_core/Cargo.toml index 602fc87..2f99b1f 100644 --- a/derive_builder_core/Cargo.toml +++ b/derive_builder_core/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "derive_builder_core" version = "0.13.0" -authors = ["Colin Kiegel ", - "Pascal Hertleif ", - "Jan-Erik Rediger ", - "Ted Driggs "] +authors = [ + "Colin Kiegel ", + "Pascal Hertleif ", + "Jan-Erik Rediger ", + "Ted Driggs ", +] description = "Internal helper library for the derive_builder crate." repository = "https://github.com/colin-kiegel/rust-derive-builder" @@ -19,10 +21,10 @@ clippy = [] lib_has_std = [] [dependencies] -darling = "0.14.0" +darling = "0.20.4" proc-macro2 = "1.0.37" -quote = "1.0.18" -syn = { version = "1.0.91", features = ["full", "extra-traits"] } +quote = "1.0.35" +syn = { version = "2.0.15", features = ["full", "extra-traits"] } [dev-dependencies] pretty_assertions = "1.2.1" diff --git a/derive_builder_core/src/block.rs b/derive_builder_core/src/block.rs index d412f90..a772abe 100644 --- a/derive_builder_core/src/block.rs +++ b/derive_builder_core/src/block.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use syn::{self, spanned::Spanned, Block, LitStr}; @@ -16,6 +16,10 @@ impl BlockContents { pub fn is_empty(&self) -> bool { self.0.stmts.is_empty() } + + pub fn span(&self) -> Span { + self.0.span() + } } impl ToTokens for BlockContents { @@ -39,7 +43,7 @@ impl From for BlockContents { fn from(v: syn::Expr) -> Self { Self(Block { brace_token: syn::token::Brace(v.span()), - stmts: vec![syn::Stmt::Expr(v)], + stmts: vec![syn::Stmt::Expr(v, None)], }) } } @@ -71,7 +75,7 @@ mod test { } #[test] - #[should_panic(expected = r#"lex error"#)] + #[should_panic(expected = r#"cannot parse"#)] fn block_invalid_token_trees() { parse("let x = 2; { x+1").unwrap(); } diff --git a/derive_builder_core/src/builder.rs b/derive_builder_core/src/builder.rs index a00581b..a6d2e7d 100644 --- a/derive_builder_core/src/builder.rs +++ b/derive_builder_core/src/builder.rs @@ -858,7 +858,7 @@ mod tests { add_simple_foo_builder(&mut result); - result.append_all(quote!(compile_error! { #ALLOC_NOT_ENABLED_ERROR })); + result.append_all(quote!(::core::compile_error! { #ALLOC_NOT_ENABLED_ERROR })); result } diff --git a/derive_builder_core/src/default_expression.rs b/derive_builder_core/src/default_expression.rs index 27e62fa..b4a7208 100644 --- a/derive_builder_core/src/default_expression.rs +++ b/derive_builder_core/src/default_expression.rs @@ -23,6 +23,13 @@ impl DefaultExpression { } } + pub fn span(&self) -> Span { + match self { + DefaultExpression::Explicit(block) => block.span(), + DefaultExpression::Trait => Span::call_site(), + } + } + #[cfg(test)] pub fn explicit>(content: I) -> Self { DefaultExpression::Explicit(content.into()) @@ -39,15 +46,6 @@ impl darling::FromMeta for DefaultExpression { } } -impl syn::spanned::Spanned for DefaultExpression { - fn span(&self) -> Span { - match self { - DefaultExpression::Explicit(block) => block.span(), - DefaultExpression::Trait => Span::call_site(), - } - } -} - /// Wrapper for `DefaultExpression` struct DefaultExpressionWithCrateRoot<'a> { crate_root: &'a syn::Path, diff --git a/derive_builder_core/src/macro_options/darling_opts.rs b/derive_builder_core/src/macro_options/darling_opts.rs index 963d368..7d7e04e 100644 --- a/derive_builder_core/src/macro_options/darling_opts.rs +++ b/derive_builder_core/src/macro_options/darling_opts.rs @@ -4,8 +4,7 @@ use crate::BuildMethod; use darling::util::{Flag, PathList, SpannedValue}; use darling::{self, Error, FromMeta}; -use proc_macro2::{Span, TokenStream}; -use syn::parse::{ParseStream, Parser}; +use proc_macro2::Span; use syn::Meta; use syn::{self, spanned::Spanned, Attribute, Generics, Ident, Path}; @@ -61,8 +60,10 @@ fn no_visibility_conflict(v: &T) -> darling::Result<()> { } } else if declares_public && declares_private { Err( - Error::custom(r#"`public` and `private` cannot be used together"#) - .with_span(v.public()), + Error::custom(r#"`public` and `private` cannot be used together"#).with_span( + // TODO fix this + &Span::call_site(), + ), ) } else { Ok(()) @@ -103,7 +104,7 @@ impl FromMeta for BuildFnError { match item { Meta::Path(_) => Err(Error::unsupported_format("word").with_span(item)), Meta::List(_) => BuildFnErrorGenerated::from_meta(item).map(Self::Generated), - Meta::NameValue(i) => Path::from_value(&i.lit).map(Self::Existing), + Meta::NameValue(i) => Path::from_expr(&i.value).map(Self::Existing), } } } @@ -112,7 +113,7 @@ impl FromMeta for BuildFnError { /// There is no inheritance for these settings from struct-level to field-level, /// so we don't bother using `Option` for values in this struct. #[derive(Debug, Clone, FromMeta)] -#[darling(default, and_then = "Self::validation_needs_error")] +#[darling(default, and_then = Self::validation_needs_error)] pub struct BuildFn { skip: bool, name: Ident, @@ -155,7 +156,7 @@ impl BuildFn { Error::custom( "Cannot set `error(validation_error = false)` when using `validate`", ) - .with_span(&e.validation_error), + .with_span(&e.validation_error.span()), ) } } @@ -226,7 +227,7 @@ pub struct FieldLevelFieldMeta { private: Flag, vis: Option, /// Custom builder field type - #[darling(rename = "type")] + #[darling(rename = "ty")] builder_type: Option, /// Custom builder field method, for making target struct field value build: Option, @@ -270,14 +271,10 @@ impl StructLevelSetter { /// * `each(name = "...")`, which allows setting additional options on the `each` setter fn parse_each(meta: &Meta) -> darling::Result> { if let Meta::NameValue(mnv) = meta { - if let syn::Lit::Str(v) = &mnv.lit { - v.parse::() - .map(Each::from) - .map(Some) - .map_err(|_| darling::Error::unknown_value(&v.value()).with_span(v)) - } else { - Err(darling::Error::unexpected_lit_type(&mnv.lit)) - } + Ident::from_meta(meta) + .map(Each::from) + .map(Some) + .map_err(|e| e.with_span(&mnv.value)) } else { Each::from_meta(meta).map(Some) } @@ -294,7 +291,7 @@ pub struct FieldLevelSetter { strip_option: Option, skip: Option, custom: Option, - #[darling(with = "parse_each")] + #[darling(with = parse_each)] each: Option, } @@ -425,19 +422,19 @@ impl Field { darling::Error::custom( r#"#[builder(default)] and #[builder(field(build="..."))] cannot be used together"#, ) - .with_span(field_default), + .with_span(&field_default.span()), ); } - // `field.type` being set means `default` will not be used, since we don't know how + // `field.ty` being set means `default` will not be used, since we don't know how // to check a custom field type for the absence of a value and therefore we'll never // know that we should use the `default` value. if self.field.builder_type.is_some() { errors.push( darling::Error::custom( - r#"#[builder(default)] and #[builder(field(type="..."))] cannot be used together"#, + r#"#[builder(default)] and #[builder(field(ty="..."))] cannot be used together"#, ) - .with_span(field_default) + .with_span(&field_default.span()) ) } }; @@ -482,7 +479,7 @@ fn distribute_and_unnest_attrs( for attr in input.drain(..) { let destination = outputs .iter_mut() - .find(|(ptattr, _)| attr.path.is_ident(ptattr)); + .find(|(ptattr, _)| attr.path().is_ident(ptattr)); if let Some((_, destination)) = destination { match unnest_from_one_attribute(attr) { @@ -509,7 +506,7 @@ fn unnest_from_one_attribute(attr: syn::Attribute) -> darling::Result syn::AttrStyle::Inner(bang) => { return Err(darling::Error::unsupported_format(&format!( "{} must be an outer attribute", - attr.path + attr.path() .get_ident() .map(Ident::to_string) .unwrap_or_else(|| "Attribute".to_string()) @@ -518,34 +515,19 @@ fn unnest_from_one_attribute(attr: syn::Attribute) -> darling::Result } }; - #[derive(Debug)] - struct ContainedAttribute(syn::Attribute); - impl syn::parse::Parse for ContainedAttribute { - fn parse(input: ParseStream) -> syn::Result { - // Strip parentheses, and save the span of the parenthesis token - let content; - let paren_token = parenthesized!(content in input); - let wrap_span = paren_token.span; - - // Wrap up in #[ ] instead. - let pound = Token![#](wrap_span); // We can't write a literal # inside quote - let content: TokenStream = content.parse()?; - let content = quote_spanned!(wrap_span=> #pound [ #content ]); - - let parser = syn::Attribute::parse_outer; - let mut attrs = parser.parse2(content)?.into_iter(); - // TryFrom for Array not available in Rust 1.40 - // We think this error can never actually happen, since `#[...]` ought to make just one Attribute - let attr = match (attrs.next(), attrs.next()) { - (Some(attr), None) => attr, - _ => return Err(input.error("expected exactly one attribute")), - }; - Ok(Self(attr)) + let original_span = attr.span(); + + let pound = attr.pound_token; + let meta = attr.meta; + + match meta { + Meta::Path(_) => Err(Error::unsupported_format("word").with_span(&meta)), + Meta::NameValue(_) => Err(Error::unsupported_format("name-value").with_span(&meta)), + Meta::List(list) => { + let inner = list.tokens; + Ok(parse_quote_spanned!(original_span=> #pound [ #inner ])) } } - - let ContainedAttribute(attr) = syn::parse2(attr.tokens)?; - Ok(attr) } impl Visibility for Field { diff --git a/derive_builder_core/src/setter.rs b/derive_builder_core/src/setter.rs index 95d988a..2cd43de 100644 --- a/derive_builder_core/src/setter.rs +++ b/derive_builder_core/src/setter.rs @@ -243,7 +243,7 @@ fn wrap_expression_in_some(crate_root: &syn::Path, bare_value: impl ToTokens) -> // We cannot handle those arbitrary names. fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> { use syn::punctuated::Pair; - use syn::token::Colon2; + use syn::token::PathSep; use syn::{GenericArgument, Path, PathArguments, PathSegment}; fn extract_type_path(ty: &syn::Type) -> Option<&Path> { @@ -255,7 +255,7 @@ fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> { // TODO store (with lazy static) precomputed parsing of Option when support of rust 1.18 will be removed (incompatible with lazy_static) // TODO maybe optimization, reverse the order of segments - fn extract_option_segment(path: &Path) -> Option> { + fn extract_option_segment(path: &Path) -> Option> { let idents_of_path = path.segments.iter().fold(String::new(), |mut acc, v| { acc.push_str(&v.ident.to_string()); acc.push('|'); diff --git a/derive_builder_macro/Cargo.toml b/derive_builder_macro/Cargo.toml index c520964..53b13bf 100644 --- a/derive_builder_macro/Cargo.toml +++ b/derive_builder_macro/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "derive_builder_macro" version = "0.13.0" -authors = ["Colin Kiegel ", - "Pascal Hertleif ", - "Jan-Erik Rediger ", - "Ted Driggs "] +authors = [ + "Colin Kiegel ", + "Pascal Hertleif ", + "Jan-Erik Rediger ", + "Ted Driggs ", +] description = "Rust macro to automatically implement the builder pattern for arbitrary structs." repository = "https://github.com/colin-kiegel/rust-derive-builder" @@ -24,5 +26,5 @@ clippy = ["derive_builder_core/clippy"] lib_has_std = ["derive_builder_core/lib_has_std"] [dependencies] -syn = { version = "1.0.91", features = ["full", "extra-traits"] } +syn = { version = "2.0.15", features = ["full", "extra-traits"] } derive_builder_core = { version = "=0.13.0", path = "../derive_builder_core" }