Skip to content

Commit

Permalink
Merge pull request #400 from TeXitoi/fix/matches-span
Browse files Browse the repository at this point in the history
  • Loading branch information
CreepySkeleton committed Jun 12, 2020
2 parents f84e751 + 83894e2 commit caa1455
Showing 1 changed file with 23 additions and 13 deletions.
36 changes: 23 additions & 13 deletions structopt-derive/src/lib.rs
Expand Up @@ -28,7 +28,7 @@ use crate::{

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.
Expand Down Expand Up @@ -239,6 +239,16 @@ fn gen_augmentation(
}

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,
Expand All @@ -265,13 +275,13 @@ fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
};
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 {
Expand Down Expand Up @@ -318,45 +328,45 @@ fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
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
}
},

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()
},
Expand Down

0 comments on commit caa1455

Please sign in to comment.