Skip ab/6749736 in stage.

Merged-In: Ib48578a9cade614fe5e9d342be775a775a40d541
Change-Id: Ie3ce841177da3f16eba18f769763a287d1bac5b0
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 2df1587..bb978e8 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "203c6bc19e561da1734873794bbd420e0bfc79b9"
+    "sha1": "ff542c67023cbddbb2198df4087abc6aa6c8d5b7"
   }
 }
diff --git a/Android.bp b/Android.bp
index 9074bac..0c11915 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --device --tests --dependencies.
+// This file is generated by cargo2android.py --run --tests --dependencies.
 
 rust_proc_macro {
     name: "libstructopt_derive",
@@ -32,12 +32,11 @@
 
 // dependent_library ["feature_list"]
 //   heck-0.3.1
-//   proc-macro-error-1.0.3
-//   proc-macro-error-attr-1.0.3
-//   proc-macro2-1.0.19 "default,proc-macro"
+//   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.36 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
-//   syn-mid-0.5.0
+//   syn-1.0.42 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
 //   unicode-segmentation-1.6.0
 //   unicode-xid-0.2.1 "default"
 //   version_check-0.9.2
diff --git a/Cargo.toml b/Cargo.toml
index 301f046..5afdc79 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 [package]
 edition = "2018"
 name = "structopt-derive"
-version = "0.4.7"
+version = "0.4.11"
 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 4e97528..ff14f47 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "structopt-derive"
-version = "0.4.7"
+version = "0.4.11"
 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 bb03db3..b40e4df 100644
--- a/METADATA
+++ b/METADATA
@@ -1,4 +1,4 @@
-name: structopt-derive
+name: "structopt-derive"
 description: "Parse command line argument by defining a struct, derive crate."
 third_party {
   url {
@@ -6,14 +6,14 @@
     value: "https://crates.io/crates/structopt-derive"
   }
   url {
-    type: GIT
-    value: "https://github.com/TeXitoi/structopt"
+    type: ARCHIVE
+    value: "https://static.crates.io/crates/structopt-derive/structopt-derive-0.4.11.crate"
   }
-  version: "0.4.7"
+  version: "0.4.11"
   license_type: NOTICE
   last_upgrade_date {
     year: 2020
-    month: 5
+    month: 10
     day: 6
   }
-}
\ No newline at end of file
+}
diff --git a/src/attrs.rs b/src/attrs.rs
index d75b50c..11655b8 100644
--- a/src/attrs.rs
+++ b/src/attrs.rs
@@ -65,6 +65,10 @@
     Snake,
     /// Use the original attribute name defined in the code.
     Verbatim,
+    /// Keep all letters lowercase and remove word boundaries.
+    Lower,
+    /// Keep all letters uppercase and remove word boundaries.
+    Upper,
 }
 
 #[derive(Clone)]
@@ -188,6 +192,8 @@
             "screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake),
             "snake" | "snakecase" => cs(Snake),
             "verbatim" | "verbatimcase" => cs(Verbatim),
+            "lower" | "lowercase" => cs(Lower),
+            "upper" | "uppercase" => cs(Upper),
             s => abort!(name, "unsupported casing: `{}`", s),
         }
     }
@@ -208,6 +214,8 @@
                     ScreamingSnake => s.to_shouty_snake_case(),
                     Snake => s.to_snake_case(),
                     Verbatim => s,
+                    Lower => s.to_snake_case().replace("_", ""),
+                    Upper => s.to_shouty_snake_case().replace("_", ""),
                 };
                 quote_spanned!(ident.span()=> #s)
             }
@@ -437,12 +445,16 @@
                         "parse attribute is not allowed for flattened entry"
                     );
                 }
-                if res.has_explicit_methods() || res.has_doc_methods() {
+                if res.has_explicit_methods() {
                     abort!(
                         res.kind.span(),
-                        "methods and doc comments are not allowed for flattened entry"
+                        "methods are not allowed for flattened entry"
                     );
                 }
+
+                if res.has_doc_methods() {
+                    res.doc_comment = vec![];
+                }
             }
 
             Kind::ExternalSubcommand => {}
diff --git a/src/lib.rs b/src/lib.rs
index 5e49468..6cc415b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,6 +11,7 @@
 //! for the usage of `#[derive(StructOpt)]`.
 
 #![allow(clippy::large_enum_variant)]
+#![forbid(unsafe_code)]
 
 extern crate proc_macro;
 
@@ -28,7 +29,7 @@
 
 use proc_macro2::{Span, TokenStream};
 use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy};
-use quote::{quote, quote_spanned};
+use quote::{format_ident, quote, quote_spanned};
 use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *};
 
 /// Default casing style for generated arguments.
@@ -239,6 +240,16 @@
 }
 
 fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
+    // This ident is used in several match branches below,
+    // and the `quote[_spanned]` invocations have different spans.
+    //
+    // Given that this ident is used in several places and
+    // that the branches are located inside of a loop, it is possible that
+    // this ident will be given _different_ spans in different places, and
+    // thus will not be the _same_ ident anymore. To make sure the `matches`
+    // is always the same, we factor it out.
+    let matches = format_ident!("matches");
+
     let fields = fields.iter().map(|field| {
         let attrs = Attrs::from_field(
             field,
@@ -265,13 +276,13 @@
                 };
                 quote_spanned! { kind.span()=>
                     #field_name: <#subcmd_type as ::structopt::StructOptInternal>::from_subcommand(
-                        matches.subcommand())
+                        #matches.subcommand())
                         #unwrapper
                 }
             }
 
             Kind::Flatten => quote_spanned! { kind.span()=>
-                #field_name: ::structopt::StructOpt::from_clap(matches)
+                #field_name: ::structopt::StructOpt::from_clap(#matches)
             },
 
             Kind::Skip(val) => match val {
@@ -318,24 +329,24 @@
                 let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
                 let name = attrs.cased_name();
                 let field_value = match **ty {
-                    Ty::Bool => quote_spanned!(ty.span()=> matches.is_present(#name)),
+                    Ty::Bool => quote_spanned!(ty.span()=> #matches.is_present(#name)),
 
                     Ty::Option => quote_spanned! { ty.span()=>
-                        matches.#value_of(#name)
+                        #matches.#value_of(#name)
                             .map(#parse)
                     },
 
                     Ty::OptionOption => quote_spanned! { ty.span()=>
-                        if matches.is_present(#name) {
-                            Some(matches.#value_of(#name).map(#parse))
+                        if #matches.is_present(#name) {
+                            Some(#matches.#value_of(#name).map(#parse))
                         } else {
                             None
                         }
                     },
 
                     Ty::OptionVec => quote_spanned! { ty.span()=>
-                        if matches.is_present(#name) {
-                            Some(matches.#values_of(#name)
+                        if #matches.is_present(#name) {
+                            Some(#matches.#values_of(#name)
                                  .map_or_else(Vec::new, |v| v.map(#parse).collect()))
                         } else {
                             None
@@ -343,20 +354,20 @@
                     },
 
                     Ty::Vec => quote_spanned! { ty.span()=>
-                        matches.#values_of(#name)
+                        #matches.#values_of(#name)
                             .map_or_else(Vec::new, |v| v.map(#parse).collect())
                     },
 
                     Ty::Other if occurrences => quote_spanned! { ty.span()=>
-                        #parse(matches.#value_of(#name))
+                        #parse(#matches.#value_of(#name))
                     },
 
                     Ty::Other if flag => quote_spanned! { ty.span()=>
-                        #parse(matches.is_present(#name))
+                        #parse(#matches.is_present(#name))
                     },
 
                     Ty::Other => quote_spanned! { ty.span()=>
-                        matches.#value_of(#name)
+                        #matches.#value_of(#name)
                             .map(#parse)
                             .unwrap()
                     },
@@ -471,8 +482,9 @@
         let kind = attrs.kind();
         match &*kind {
             Kind::ExternalSubcommand => {
+                let app_var = Ident::new("app", Span::call_site());
                 quote_spanned! { attrs.kind().span()=>
-                    let app = app.setting(
+                    let #app_var = #app_var.setting(
                         ::structopt::clap::AppSettings::AllowExternalSubcommands
                     );
                 }
@@ -549,7 +561,8 @@
     quote! {
         fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
             <#name as ::structopt::StructOptInternal>::from_subcommand(matches.subcommand())
-                .unwrap()
+                .expect("structopt misuse: You likely tried to #[flatten] a struct \
+                         that contains #[subcommand]. This is forbidden.")
         }
     }
 }
@@ -648,10 +661,10 @@
                 }
 
                 (external, None) => {
-                    ::std::option::Option::Some(#name::#var_name({
+                    ::std::option::Option::Some(#name::#var_name(
                         ::std::iter::once(#str_ty::from(external))
                             .collect::<::std::vec::Vec<_>>()
-                    }))
+                    ))
                 }
             }
         },
@@ -720,7 +733,7 @@
 #[cfg(feature = "paw")]
 fn gen_paw_impl(name: &Ident) -> TokenStream {
     quote! {
-        impl paw::ParseArgs for #name {
+        impl ::structopt::paw::ParseArgs for #name {
             type Error = std::io::Error;
 
             fn parse_args() -> std::result::Result<Self, Self::Error> {
diff --git a/src/spanned.rs b/src/spanned.rs
index 19dbe47..1c02a82 100644
--- a/src/spanned.rs
+++ b/src/spanned.rs
@@ -88,7 +88,7 @@
         // this is the simplest way out of correct ones to change span on
         // arbitrary token tree I can come up with
         let tt = self.val.to_token_stream().into_iter().map(|mut tt| {
-            tt.set_span(self.span.clone());
+            tt.set_span(self.span);
             tt
         });