Snap for 7629113 from 59075dac546bb35c83d4164a637c8f3fe9613057 to tm-release

Change-Id: I60d001cc1a9b4815e76ab4faf37e814ef70c1221
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 7d10f0d..887fa2d 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "8bda3b64daf53f0ed6bb6bee2c767a63c7c477fc"
+    "sha1": "004cfc218e7fbfdbecc4088f9e3fa5061f36cb4d"
   }
 }
diff --git a/Android.bp b/Android.bp
index edcebb2..eec57d9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,5 @@
 // This file is generated by cargo2android.py --run --tests --dependencies.
+// Do not modify this file as changes will be overridden on upgrade.
 
 package {
     default_applicable_licenses: [
@@ -58,6 +59,9 @@
     srcs: ["src/lib.rs"],
     test_suites: ["general-tests"],
     auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
     edition: "2018",
     rustlibs: [
         "libheck",
@@ -69,12 +73,12 @@
 }
 
 // dependent_library ["feature_list"]
-//   heck-0.3.1
+//   heck-0.3.3
 //   proc-macro-error-1.0.4 "default,syn,syn-error"
 //   proc-macro-error-attr-1.0.4
-//   proc-macro2-1.0.24 "default,proc-macro"
-//   quote-1.0.7 "default,proc-macro"
-//   syn-1.0.53 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
-//   unicode-segmentation-1.7.1
-//   unicode-xid-0.2.1 "default"
-//   version_check-0.9.2
+//   proc-macro2-1.0.28 "default,proc-macro"
+//   quote-1.0.9 "default,proc-macro"
+//   syn-1.0.74 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
+//   unicode-segmentation-1.8.0
+//   unicode-xid-0.2.2 "default"
+//   version_check-0.9.3
diff --git a/Cargo.toml b/Cargo.toml
index adfbce9..6a9c2b1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 [package]
 edition = "2018"
 name = "structopt-derive"
-version = "0.4.14"
+version = "0.4.15"
 authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
 description = "Parse command line argument by defining a struct, derive crate."
 documentation = "https://docs.rs/structopt-derive"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index c346198..db7e295 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "structopt-derive"
-version = "0.4.14"
+version = "0.4.15"
 edition = "2018"
 authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
 description = "Parse command line argument by defining a struct, derive crate."
diff --git a/METADATA b/METADATA
index 03f0e52..e5e5980 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/structopt-derive/structopt-derive-0.4.14.crate"
+    value: "https://static.crates.io/crates/structopt-derive/structopt-derive-0.4.15.crate"
   }
-  version: "0.4.14"
+  version: "0.4.15"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2020
-    month: 11
-    day: 30
+    year: 2021
+    month: 8
+    day: 9
   }
 }
diff --git a/src/attrs.rs b/src/attrs.rs
index 11655b8..aa16145 100644
--- a/src/attrs.rs
+++ b/src/attrs.rs
@@ -100,7 +100,7 @@
         Method { name, args }
     }
 
-    fn from_lit_or_env(ident: Ident, lit: Option<LitStr>, env_var: &str) -> Option<Self> {
+    fn from_lit_or_env(ident: Ident, lit: Option<LitStr>, env_var: &str) -> Self {
         let mut lit = match lit {
             Some(lit) => lit,
 
@@ -121,7 +121,7 @@
             lit = LitStr::new(&edited, lit.span());
         }
 
-        Some(Method::new(ident, quote!(#lit)))
+        Method::new(ident, quote!(#lit))
     }
 }
 
@@ -335,11 +335,15 @@
                 }
 
                 About(ident, about) => {
-                    self.about = Method::from_lit_or_env(ident, about, "CARGO_PKG_DESCRIPTION");
+                    self.about = Some(Method::from_lit_or_env(
+                        ident,
+                        about,
+                        "CARGO_PKG_DESCRIPTION",
+                    ));
                 }
 
                 Author(ident, author) => {
-                    self.author = Method::from_lit_or_env(ident, author, "CARGO_PKG_AUTHORS");
+                    self.author = Some(Method::from_lit_or_env(ident, author, "CARGO_PKG_AUTHORS"));
                 }
 
                 Version(ident, version) => {
diff --git a/src/lib.rs b/src/lib.rs
index b818386..cf4dbba 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -559,10 +559,10 @@
     }
 }
 
-fn gen_from_clap_enum(name: &Ident) -> TokenStream {
+fn gen_from_clap_enum() -> TokenStream {
     quote! {
         fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
-            <#name as ::structopt::StructOptInternal>::from_subcommand(matches.subcommand())
+            <Self as ::structopt::StructOptInternal>::from_subcommand(matches.subcommand())
                 .expect("structopt misuse: You likely tried to #[flatten] a struct \
                          that contains #[subcommand]. This is forbidden.")
         }
@@ -736,9 +736,9 @@
 }
 
 #[cfg(feature = "paw")]
-fn gen_paw_impl(name: &Ident) -> TokenStream {
+fn gen_paw_impl(impl_generics: &ImplGenerics, name: &Ident, ty_generics: &TypeGenerics, where_clause: &TokenStream) -> TokenStream {
     quote! {
-        impl ::structopt::paw::ParseArgs for #name {
+        impl #impl_generics ::structopt::paw::ParseArgs for #name #ty_generics #where_clause {
             type Error = std::io::Error;
 
             fn parse_args() -> std::result::Result<Self, Self::Error> {
@@ -748,19 +748,109 @@
     }
 }
 #[cfg(not(feature = "paw"))]
-fn gen_paw_impl(_: &Ident) -> TokenStream {
+fn gen_paw_impl(_: &ImplGenerics, _: &Ident, _: &TypeGenerics, _: &TokenStream) -> TokenStream {
     TokenStream::new()
 }
 
+fn split_structopt_generics_for_impl(generics: &Generics) -> (ImplGenerics, TypeGenerics, TokenStream) {
+    use syn::{ token::Add, TypeParamBound::Trait };
+
+    fn path_ends_with(path: &Path, ident: &str) -> bool {
+        path.segments.last().unwrap().ident == ident
+    }
+
+    fn type_param_bounds_contains(bounds: &Punctuated<TypeParamBound, Add>, ident: &str) -> bool {
+        for bound in bounds {
+            if let Trait(bound) = bound {
+                if path_ends_with(&bound.path, ident) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    struct TraitBoundAmendments{
+        tokens: TokenStream,
+        need_where: bool,
+        need_comma: bool,
+    }
+
+    impl TraitBoundAmendments {
+        fn new(where_clause: Option<&WhereClause>) -> Self {
+            let tokens = TokenStream::new();
+            let (need_where,need_comma) = if let Some(where_clause) = where_clause {
+                if where_clause.predicates.trailing_punct() {
+                    (false, false)
+                } else {
+                    (false, true)
+                }
+            } else {
+                (true, false)
+            };
+            Self{tokens, need_where, need_comma}
+        }
+
+        fn add(&mut self, amendment: TokenStream) {
+            if self.need_where {
+                self.tokens.extend(quote!{ where });
+                self.need_where = false;
+            }
+            if self.need_comma {
+                self.tokens.extend(quote!{ , });
+            }
+            self.tokens.extend(amendment);
+            self.need_comma = true;
+        }
+
+        fn into_tokens(self) -> TokenStream {
+            self.tokens
+        }
+    }
+
+    let mut trait_bound_amendments = TraitBoundAmendments::new(generics.where_clause.as_ref());
+
+    for param in &generics.params {
+        if let GenericParam::Type(param) = param {
+            let param_ident = &param.ident;
+            if type_param_bounds_contains(&param.bounds, "StructOpt") {
+                trait_bound_amendments.add(quote!{ #param_ident : ::structopt::StructOptInternal });
+            }
+        }
+    }
+
+    if let Some(where_clause) = &generics.where_clause {
+        for predicate in &where_clause.predicates {
+            if let WherePredicate::Type(predicate) = predicate {
+                let predicate_bounded_ty = &predicate.bounded_ty;
+                if type_param_bounds_contains(&predicate.bounds, "StructOpt") {
+                    trait_bound_amendments.add(quote!{ #predicate_bounded_ty : ::structopt::StructOptInternal });
+                }
+            }
+        }
+    }
+
+    let trait_bound_amendments = trait_bound_amendments.into_tokens();
+
+    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+
+    let where_clause = quote!{ #where_clause #trait_bound_amendments };
+
+    (impl_generics, ty_generics, where_clause)
+}
+
 fn impl_structopt_for_struct(
     name: &Ident,
     fields: &Punctuated<Field, Comma>,
     attrs: &[Attribute],
+    generics: &Generics,
 ) -> TokenStream {
+    let (impl_generics, ty_generics, where_clause) = split_structopt_generics_for_impl(&generics);
+
     let basic_clap_app_gen = gen_clap_struct(attrs);
     let augment_clap = gen_augment_clap(fields, &basic_clap_app_gen.attrs);
     let from_clap = gen_from_clap(name, fields, &basic_clap_app_gen.attrs);
-    let paw_impl = gen_paw_impl(name);
+    let paw_impl = gen_paw_impl(&impl_generics, name, &ty_generics, &where_clause);
 
     let clap_tokens = basic_clap_app_gen.tokens;
     quote! {
@@ -778,7 +868,7 @@
         )]
         #[deny(clippy::correctness)]
         #[allow(dead_code, unreachable_code)]
-        impl ::structopt::StructOpt for #name {
+        impl #impl_generics ::structopt::StructOpt for #name #ty_generics #where_clause {
             #clap_tokens
             #from_clap
         }
@@ -797,7 +887,7 @@
         )]
         #[deny(clippy::correctness)]
         #[allow(dead_code, unreachable_code)]
-        impl ::structopt::StructOptInternal for #name {
+        impl #impl_generics ::structopt::StructOptInternal for #name #ty_generics #where_clause {
             #augment_clap
             fn is_subcommand() -> bool { false }
         }
@@ -810,15 +900,19 @@
     name: &Ident,
     variants: &Punctuated<Variant, Comma>,
     attrs: &[Attribute],
+    generics: &Generics,
 ) -> TokenStream {
+
+    let (impl_generics, ty_generics, where_clause) = split_structopt_generics_for_impl(&generics);
+
     let basic_clap_app_gen = gen_clap_enum(attrs);
     let clap_tokens = basic_clap_app_gen.tokens;
     let attrs = basic_clap_app_gen.attrs;
 
     let augment_clap = gen_augment_clap_enum(variants, &attrs);
-    let from_clap = gen_from_clap_enum(name);
+    let from_clap = gen_from_clap_enum();
     let from_subcommand = gen_from_subcommand(name, variants, &attrs);
-    let paw_impl = gen_paw_impl(name);
+    let paw_impl = gen_paw_impl(&impl_generics, name, &ty_generics, &where_clause);
 
     quote! {
         #[allow(unknown_lints)]
@@ -834,7 +928,7 @@
             clippy::cargo
         )]
         #[deny(clippy::correctness)]
-        impl ::structopt::StructOpt for #name {
+        impl #impl_generics ::structopt::StructOpt for #name #ty_generics #where_clause {
             #clap_tokens
             #from_clap
         }
@@ -853,7 +947,7 @@
         )]
         #[deny(clippy::correctness)]
         #[allow(dead_code, unreachable_code)]
-        impl ::structopt::StructOptInternal for #name {
+        impl #impl_generics ::structopt::StructOptInternal for #name #ty_generics #where_clause {
             #augment_clap
             #from_subcommand
             fn is_subcommand() -> bool { true }
@@ -885,8 +979,8 @@
         Struct(DataStruct {
             fields: syn::Fields::Named(ref fields),
             ..
-        }) => impl_structopt_for_struct(struct_name, &fields.named, &input.attrs),
-        Enum(ref e) => impl_structopt_for_enum(struct_name, &e.variants, &input.attrs),
+        }) => impl_structopt_for_struct(struct_name, &fields.named, &input.attrs, &input.generics),
+        Enum(ref e) => impl_structopt_for_enum(struct_name, &e.variants, &input.attrs, &input.generics),
         _ => abort_call_site!("structopt only supports non-tuple structs and enums"),
     }
 }