Repository: TeXitoi/structopt (language: rust)

Issue:
`SubCommand` enum variant with fields duplicates parent attributes
This example:
```
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opts {
    #[structopt(subcommand)]
    /// The command to run
    command: Command,
}

#[derive(Debug, StructOpt)]
enum Command {
    /// Reticulate the splines
    #[structopt(visible_alias = "ret")]
    Reticulate {
        /// How many splines
        num_splines: u8,
    },
    /// Frobnicate the rest
    #[structopt(visible_alias = "frob")]
    Frobnicate,
}

fn main() {
    let opts = Opts::from_args();
    println!("{:?}", opts);
}
```

Produces this output:
```
$ cargo run -- -h
so_test 0.1.0

USAGE:
    so_test <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    frobnicate    Frobnicate the rest [aliases: frob]
    help          Prints this message or the help of the given subcommand(s)
    reticulate    Reticulate the splines [aliases: ret, ret]
```

Where we see the `reticulate` command has the `ret` alias appear twice. Looking at the expanded code:

```
$ cargo expand
...
        let app = app.subcommand({
           let subcommand = ::structopt::clap::SubCommand::with_name("reticulate");
            let subcommand = {
                let subcommand = subcommand
                    .about("Reticulate the splines")
                    .visible_alias("ret");
                let subcommand = subcommand.arg(
                    ::structopt::clap::Arg::with_name("num-splines")
                        .takes_value(true)
                        .multiple(false)
                        .required(true)
                        .validator(|s| {
                            ::std::str::FromStr::from_str(s.as_str())
                                .map(|_: u8| ())
                                .map_err(|e| e.to_string())
                        })
                        .help("How many splines"),
                );
                subcommand.version("0.1.0")
            };
            subcommand
                .about("Reticulate the splines")
                .visible_alias("ret")
                .version("0.1.0")
        });
...
```

The `about`, `visible_alias`, and `version` functions on `subcommand` are called twice. In contrast, the `Frobnicate` case in the `Command` enum does not exhibit this behavior, as it does not contain any fields, so does not include a call `subcommand.arg`:

```
       let app = app.subcommand({
            let subcommand = ::structopt::clap::SubCommand::with_name("frobnicate");
            let subcommand = subcommand;
            subcommand
                .about("Frobnicate the rest")
                .visible_alias("frob")
                .version("0.1.0")
        });
        app.version("0.1.0")
````

I believe this duplication arises from [this](https://github.com/TeXitoi/structopt/blob/9fe3f04c78843a367fe602e4bb54ca7f79f553a8/structopt-derive/src/lib.rs#L545-L555) or [this](https://github.com/TeXitoi/structopt/blob/9fe3f04c78843a367fe602e4bb54ca7f79f553a8/structopt-derive/src/lib.rs#L231-L238) code, but I am not sure if simply removing would break other cases or not.


Discussion / hints:
I'm able to confirm the duplicate `visible_alias` in the help output. I'm upgrading from `v0.2.15`, and some quick tests show that the alias duplication starts appearing from `v0.3.0` so I would consider this a regression.

Fix patch:
diff --git a/structopt-derive/src/lib.rs b/structopt-derive/src/lib.rs
index b2835b4..0838f50 100644
--- a/structopt-derive/src/lib.rs
+++ b/structopt-derive/src/lib.rs
@@ -520,9 +520,14 @@ fn gen_augment_clap_enum(
 
             _ => {
                 let app_var = Ident::new("subcommand", Span::call_site());
+                let from_attrs = attrs.top_level_methods();
+                let version = attrs.version();
+
                 let arg_block = match variant.fields {
+                    // If the variant is named, then gen_augmentation already generates the
+                    // top level methods (#from_attrs) and version.
                     Named(ref fields) => gen_augmentation(&fields.named, &app_var, &attrs),
-                    Unit => quote!( #app_var ),
+                    Unit => quote!( #app_var#from_attrs#version ),
                     Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
                         let ty = &unnamed[0];
                         quote_spanned! { ty.span()=>
@@ -536,7 +541,7 @@ fn gen_augment_clap_enum(
                                     )
                                 } else {
                                     #app_var
-                                }
+                                }#from_attrs#version
                             }
                         }
                     }
@@ -544,13 +549,10 @@ fn gen_augment_clap_enum(
                 };
 
                 let name = attrs.cased_name();
-                let from_attrs = attrs.top_level_methods();
-                let version = attrs.version();
                 Some(quote! {
                     let app = app.subcommand({
                         let #app_var = ::structopt::clap::SubCommand::with_name(#name);
-                        let #app_var = #arg_block;
-                        #app_var#from_attrs#version
+                        #arg_block
                     });
                 })
             },


Test patch:
diff --git a/tests/issues.rs b/tests/issues.rs
index 5860c49..3f9e1af 100644
--- a/tests/issues.rs
+++ b/tests/issues.rs
@@ -116,6 +116,34 @@ fn issue_359() {
     );
 }
 
+#[test]
+fn issue_418() {
+    use structopt::StructOpt;
+
+    #[derive(Debug, StructOpt)]
+    struct Opts {
+        #[structopt(subcommand)]
+        /// The command to run
+        command: Command,
+    }
+
+    #[derive(Debug, StructOpt)]
+    enum Command {
+        /// Reticulate the splines
+        #[structopt(visible_alias = "ret")]
+        Reticulate {
+            /// How many splines
+            num_splines: u8,
+        },
+        /// Frobnicate the rest
+        #[structopt(visible_alias = "frob")]
+        Frobnicate,
+    }
+
+    let help = get_long_help::<Opts>();
+    assert!(help.contains("Reticulate the splines [aliases: ret]"));
+}
+
 #[test]
 fn issue_490() {
     use std::iter::FromIterator;