Mark ab/6881855 as merged

Bug: 172690556
Change-Id: I1bcff03831f2f1e3691a33c570490228592c4345
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 2df1587..ae54c03 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "203c6bc19e561da1734873794bbd420e0bfc79b9"
+    "sha1": "6fa8d68298eab6b4eb94b4b40ce64992b20c7263"
   }
 }
diff --git a/Android.bp b/Android.bp
index 0c11915..627688f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -36,7 +36,7 @@
 //   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.42 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote"
+//   syn-1.0.48 "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..4f0f326 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 [package]
 edition = "2018"
 name = "structopt-derive"
-version = "0.4.7"
+version = "0.4.13"
 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
old mode 100644
new mode 100755
index 4e97528..176b34a
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "structopt-derive"
-version = "0.4.7"
+version = "0.4.13"
 edition = "2018"
 authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
 description = "Parse command line argument by defining a struct, derive crate."
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
old mode 100644
new mode 100755
diff --git a/LICENSE-MIT b/LICENSE-MIT
old mode 100644
new mode 100755
diff --git a/METADATA b/METADATA
index bbf085b..18397ed 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/structopt-derive/structopt-derive-0.4.7.crate"
+    value: "https://static.crates.io/crates/structopt-derive/structopt-derive-0.4.13.crate"
   }
-  version: "0.4.7"
+  version: "0.4.13"
   license_type: NOTICE
   last_upgrade_date {
     year: 2020
-    month: 5
-    day: 6
+    month: 10
+    day: 28
   }
 }
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 1c512e3..1e756de 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,8 +2,8 @@
 {
   "presubmit": [
     {
-      "name": "structopt-derive_host_test_src_lib",
-      "host": true
+      "host": true,
+      "name": "structopt-derive_host_test_src_lib"
     }
   ]
 }
diff --git a/src/attrs.rs b/src/attrs.rs
old mode 100644
new mode 100755
index d75b50c..11655b8
--- 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/doc_comments.rs b/src/doc_comments.rs
old mode 100644
new mode 100755
diff --git a/src/lib.rs b/src/lib.rs
old mode 100644
new mode 100755
index 5e49468..b99bd35
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,6 +11,9 @@
 //! for the usage of `#[derive(StructOpt)]`.
 
 #![allow(clippy::large_enum_variant)]
+// FIXME: remove when and if our MSRV hits 1.42
+#![allow(clippy::match_like_matches_macro)]
+#![forbid(unsafe_code)]
 
 extern crate proc_macro;
 
@@ -28,7 +31,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 +242,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 +278,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 +331,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 +356,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 +484,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 +563,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 +663,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 +735,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/parse.rs b/src/parse.rs
old mode 100644
new mode 100755
diff --git a/src/spanned.rs b/src/spanned.rs
old mode 100644
new mode 100755
index 19dbe47..1c02a82
--- 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
         });
 
diff --git a/src/ty.rs b/src/ty.rs
old mode 100644
new mode 100755
index 89d8b00..ad3acd9
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -63,6 +63,8 @@
 where
     F: FnOnce(&PathSegment) -> bool,
 {
+    let ty = strip_group(ty);
+
     only_last_segment(ty)
         .filter(|segment| f(segment))
         .and_then(|segment| {
@@ -85,6 +87,8 @@
 }
 
 pub fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
+    let ty = strip_group(ty);
+
     only_last_segment(ty)
         .map(|segment| {
             if let PathArguments::None = segment.arguments {
@@ -96,6 +100,23 @@
         .unwrap_or(false)
 }
 
+// If the struct is placed inside of a macro_rules! declaration,
+// in some circumstances, the tokens inside will be enclosed
+// in `proc_macro::Group` delimited by invisible `proc_macro::Delimiter::None`.
+//
+// In syn speak, this is encoded via `*::Group` variants. We don't really care about
+// that, so let's just strip it.
+//
+// Details: https://doc.rust-lang.org/proc_macro/enum.Delimiter.html#variant.None
+// See also: https://github.com/TeXitoi/structopt/issues/439
+fn strip_group(mut ty: &syn::Type) -> &syn::Type {
+    while let Type::Group(group) = ty {
+        ty = &*group.elem;
+    }
+
+    ty
+}
+
 fn is_generic_ty(ty: &syn::Type, name: &str) -> bool {
     subty_if_name(ty, name).is_some()
 }