diff options
author | Matthew Maurer <mmaurer@google.com> | 2023-04-04 12:12:01 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-04-04 12:12:01 +0000 |
commit | cb3f07245160fece9ab00552829234000b5fe661 (patch) | |
tree | 71072e4f3b2bd823a6e356c31736bc837a2e6622 | |
parent | fa8e13476a446bc339a57cd590440d572f995746 (diff) | |
parent | 735c0d0505a9097967f38eb3e235a2713429a95d (diff) | |
download | derive_arbitrary-cb3f07245160fece9ab00552829234000b5fe661.tar.gz |
Upgrade derive_arbitrary to 1.3.0 am: bd22a34ae7 am: 81a681e628 am: 735c0d0505android14-dev
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/derive_arbitrary/+/2520840
Change-Id: Ib3a2987f6a7bc78f37e761859fdbb5161674c390
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | Cargo.toml | 9 | ||||
-rw-r--r-- | Cargo.toml.orig | 4 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | src/container_attributes.rs | 72 | ||||
-rw-r--r-- | src/field_attributes.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 59 |
8 files changed, 144 insertions, 16 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 1f38b6d..5db9271 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "98044ba8b0f7d730b500fa3b4f2e96a5edcd926d" + "sha1": "c20a95029145c0eab249416f3d301c4bd21f33f6" }, "path_in_vcs": "derive" }
\ No newline at end of file @@ -43,7 +43,7 @@ rust_proc_macro { name: "libderive_arbitrary", crate_name: "derive_arbitrary", cargo_env_compat: true, - cargo_pkg_version: "1.2.3", + cargo_pkg_version: "1.3.0", srcs: ["src/lib.rs"], edition: "2021", rustlibs: [ @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.63.0" name = "derive_arbitrary" -version = "1.2.3" +version = "1.3.0" authors = [ "The Rust-Fuzz Project Developers", "Nick Fitzgerald <fitzgen@gmail.com>", @@ -45,5 +45,8 @@ version = "1.0" version = "1.0" [dependencies.syn] -version = "1.0" -features = ["derive"] +version = "1.0.56" +features = [ + "derive", + "parsing", +] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 99f5538..570519f 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "derive_arbitrary" -version = "1.2.3" # Make sure it matches the version of the arbitrary crate itself (not including the patch version) +version = "1.3.0" # Make sure it matches the version of the arbitrary crate itself (not including the patch version) authors = [ "The Rust-Fuzz Project Developers", "Nick Fitzgerald <fitzgen@gmail.com>", @@ -21,7 +21,7 @@ rust-version = "1.63.0" [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "1.0", features = ['derive'] } +syn = { version = "1.0.56", features = ['derive', 'parsing'] } [lib] proc_macro = true @@ -11,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/derive_arbitrary/derive_arbitrary-1.2.3.crate" + value: "https://static.crates.io/crates/derive_arbitrary/derive_arbitrary-1.3.0.crate" } - version: "1.2.3" + version: "1.3.0" license_type: NOTICE last_upgrade_date { year: 2023 - month: 2 - day: 1 + month: 4 + day: 3 } } diff --git a/src/container_attributes.rs b/src/container_attributes.rs new file mode 100644 index 0000000..9a91ac8 --- /dev/null +++ b/src/container_attributes.rs @@ -0,0 +1,72 @@ +use crate::ARBITRARY_ATTRIBUTE_NAME; +use syn::{ + parse::Error, punctuated::Punctuated, DeriveInput, Lit, Meta, MetaNameValue, NestedMeta, Token, + TypeParam, +}; + +pub struct ContainerAttributes { + /// Specify type bounds to be applied to the derived `Arbitrary` implementation instead of the + /// default inferred bounds. + /// + /// ```ignore + /// #[arbitrary(bound = "T: Default, U: Debug")] + /// ``` + /// + /// Multiple attributes will be combined as long as they don't conflict, e.g. + /// + /// ```ignore + /// #[arbitrary(bound = "T: Default")] + /// #[arbitrary(bound = "U: Default")] + /// ``` + pub bounds: Option<Vec<Punctuated<TypeParam, Token![,]>>>, +} + +impl ContainerAttributes { + pub fn from_derive_input(derive_input: &DeriveInput) -> Result<Self, Error> { + let mut bounds = None; + + for attr in &derive_input.attrs { + if !attr.path.is_ident(ARBITRARY_ATTRIBUTE_NAME) { + continue; + } + + let meta_list = match attr.parse_meta()? { + Meta::List(l) => l, + _ => { + return Err(Error::new_spanned( + attr, + format!( + "invalid `{}` attribute. expected list", + ARBITRARY_ATTRIBUTE_NAME + ), + )) + } + }; + + for nested_meta in meta_list.nested.iter() { + match nested_meta { + NestedMeta::Meta(Meta::NameValue(MetaNameValue { + path, + lit: Lit::Str(bound_str_lit), + .. + })) if path.is_ident("bound") => { + bounds + .get_or_insert_with(Vec::new) + .push(bound_str_lit.parse_with(Punctuated::parse_terminated)?); + } + _ => { + return Err(Error::new_spanned( + attr, + format!( + "invalid `{}` attribute. expected `bound = \"..\"`", + ARBITRARY_ATTRIBUTE_NAME, + ), + )) + } + } + } + } + + Ok(Self { bounds }) + } +} diff --git a/src/field_attributes.rs b/src/field_attributes.rs index ccaba74..2ca0f1c 100644 --- a/src/field_attributes.rs +++ b/src/field_attributes.rs @@ -1,10 +1,8 @@ +use crate::ARBITRARY_ATTRIBUTE_NAME; use proc_macro2::{Group, Span, TokenStream, TokenTree}; use quote::quote; use syn::{spanned::Spanned, *}; -/// Used to filter out necessary field attribute and within error messages. -static ARBITRARY_ATTRIBUTE_NAME: &str = "arbitrary"; - /// Determines how a value for a field should be constructed. #[cfg_attr(test, derive(Debug))] pub enum FieldConstructor { @@ -4,9 +4,12 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::*; +mod container_attributes; mod field_attributes; +use container_attributes::ContainerAttributes; use field_attributes::{determine_field_constructor, FieldConstructor}; +static ARBITRARY_ATTRIBUTE_NAME: &str = "arbitrary"; static ARBITRARY_LIFETIME_NAME: &str = "'arbitrary"; #[proc_macro_derive(Arbitrary, attributes(arbitrary))] @@ -18,6 +21,8 @@ pub fn derive_arbitrary(tokens: proc_macro::TokenStream) -> proc_macro::TokenStr } fn expand_derive_arbitrary(input: syn::DeriveInput) -> Result<TokenStream> { + let container_attrs = ContainerAttributes::from_derive_input(&input)?; + let (lifetime_without_bounds, lifetime_with_bounds) = build_arbitrary_lifetime(input.generics.clone()); @@ -30,8 +35,13 @@ fn expand_derive_arbitrary(input: syn::DeriveInput) -> Result<TokenStream> { gen_arbitrary_method(&input, lifetime_without_bounds.clone(), &recursive_count)?; let size_hint_method = gen_size_hint_method(&input)?; let name = input.ident; - // Add a bound `T: Arbitrary` to every type parameter T. - let generics = add_trait_bounds(input.generics, lifetime_without_bounds.clone()); + + // Apply user-supplied bounds or automatic `T: ArbitraryBounds`. + let generics = apply_trait_bounds( + input.generics, + lifetime_without_bounds.clone(), + &container_attrs, + )?; // Build ImplGeneric with a lifetime (https://github.com/dtolnay/syn/issues/90) let mut generics_with_lifetime = generics.clone(); @@ -77,6 +87,51 @@ fn build_arbitrary_lifetime(generics: Generics) -> (LifetimeDef, LifetimeDef) { (lifetime_without_bounds, lifetime_with_bounds) } +fn apply_trait_bounds( + mut generics: Generics, + lifetime: LifetimeDef, + container_attrs: &ContainerAttributes, +) -> Result<Generics> { + // If user-supplied bounds exist, apply them to their matching type parameters. + if let Some(config_bounds) = &container_attrs.bounds { + let mut config_bounds_applied = 0; + for param in generics.params.iter_mut() { + if let GenericParam::Type(type_param) = param { + if let Some(replacement) = config_bounds + .iter() + .flatten() + .find(|p| p.ident == type_param.ident) + { + *type_param = replacement.clone(); + config_bounds_applied += 1; + } else { + // If no user-supplied bounds exist for this type, delete the original bounds. + // This mimics serde. + type_param.bounds = Default::default(); + type_param.default = None; + } + } + } + let config_bounds_supplied = config_bounds + .iter() + .map(|bounds| bounds.len()) + .sum::<usize>(); + if config_bounds_applied != config_bounds_supplied { + return Err(Error::new( + Span::call_site(), + format!( + "invalid `{}` attribute. too many bounds, only {} out of {} are applicable", + ARBITRARY_ATTRIBUTE_NAME, config_bounds_applied, config_bounds_supplied, + ), + )); + } + Ok(generics) + } else { + // Otherwise, inject a `T: Arbitrary` bound for every parameter. + Ok(add_trait_bounds(generics, lifetime)) + } +} + // Add a bound `T: Arbitrary` to every type parameter T. fn add_trait_bounds(mut generics: Generics, lifetime: LifetimeDef) -> Generics { for param in generics.params.iter_mut() { |