diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index bb6ecca4..9cf24df4 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -36,8 +36,15 @@ pub fn derive_args(input: &DeriveInput) -> TokenStream { }) => { let name = Name::Derived(ident.clone()); let item = Item::from_args_struct(input, name); - let fields = &fields.named; - gen_for_struct(&item, ident, &input.generics, fields) + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::>(); + gen_for_struct(&item, ident, &input.generics, &fields) } Data::Struct(DataStruct { fields: Fields::Unit, @@ -45,8 +52,15 @@ pub fn derive_args(input: &DeriveInput) -> TokenStream { }) => { let name = Name::Derived(ident.clone()); let item = Item::from_args_struct(input, name); - let fields = &Punctuated::::new(); - gen_for_struct(&item, ident, &input.generics, fields) + let fields = Punctuated::::new(); + let fields = fields + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::>(); + gen_for_struct(&item, ident, &input.generics, &fields) } _ => abort_call_site!("`#[derive(Args)]` only supports non-tuple structs"), } @@ -56,12 +70,12 @@ pub fn gen_for_struct( item: &Item, item_name: &Ident, generics: &Generics, - fields: &Punctuated, + fields: &[(&Field, Item)], ) -> TokenStream { let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let constructor = gen_constructor(fields, item); - let updater = gen_updater(fields, item, true); + let constructor = gen_constructor(fields); + let updater = gen_updater(fields, true); let raw_deprecated = raw_deprecated(); let app_var = Ident::new("__clap_app", Span::call_site()); @@ -131,17 +145,12 @@ pub fn gen_for_struct( /// Generate a block of code to add arguments/subcommands corresponding to /// the `fields` to an cmd. pub fn gen_augment( - fields: &Punctuated, + fields: &[(&Field, Item)], app_var: &Ident, parent_item: &Item, override_required: bool, ) -> TokenStream { - let mut subcmds = fields.iter().filter_map(|field| { - let item = Item::from_args_field( - field, - parent_item.casing(), - parent_item.env_casing(), - ); + let mut subcmds = fields.iter().filter_map(|(field, item)| { let kind = item.kind(); if let Kind::Subcommand(ty) = &*kind { let subcmd_type = match (**ty, sub_type(&field.ty)) { @@ -182,12 +191,7 @@ pub fn gen_augment( ); } - let args = fields.iter().filter_map(|field| { - let item = Item::from_args_field( - field, - parent_item.casing(), - parent_item.env_casing(), - ); + let args = fields.iter().filter_map(|(field, item)| { let kind = item.kind(); match &*kind { Kind::Subcommand(_) @@ -313,13 +317,8 @@ pub fn gen_augment( }} } -pub fn gen_constructor(fields: &Punctuated, parent_item: &Item) -> TokenStream { - let fields = fields.iter().map(|field| { - let item = Item::from_args_field( - field, - parent_item.casing(), - parent_item.env_casing(), - ); +pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream { + let fields = fields.iter().map(|(field, item)| { let field_name = field.ident.as_ref().unwrap(); let kind = item.kind(); let arg_matches = format_ident!("__clap_arg_matches"); @@ -366,7 +365,7 @@ pub fn gen_constructor(fields: &Punctuated, parent_item: &Item) -> }, Kind::Arg(ty) | Kind::FromGlobal(ty) => { - gen_parsers(&item, ty, field_name, field, None) + gen_parsers(item, ty, field_name, field, None) } } }); @@ -376,17 +375,8 @@ pub fn gen_constructor(fields: &Punctuated, parent_item: &Item) -> }} } -pub fn gen_updater( - fields: &Punctuated, - parent_item: &Item, - use_self: bool, -) -> TokenStream { - let fields = fields.iter().map(|field| { - let item = Item::from_args_field( - field, - parent_item.casing(), - parent_item.env_casing(), - ); +pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream { + let fields = fields.iter().map(|(field, item)| { let field_name = field.ident.as_ref().unwrap(); let kind = item.kind(); @@ -447,7 +437,7 @@ pub fn gen_updater( Kind::Skip(_) => quote!(), - Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&item, ty, field_name, field, Some(&access)), + Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(item, ty, field_name, field, Some(&access)), } }); diff --git a/clap_derive/src/derives/parser.rs b/clap_derive/src/derives/parser.rs index ec729502..5518fde7 100644 --- a/clap_derive/src/derives/parser.rs +++ b/clap_derive/src/derives/parser.rs @@ -16,7 +16,6 @@ use proc_macro2::TokenStream; use proc_macro_error::abort_call_site; use quote::quote; use syn::Ident; -use syn::Token; use syn::Variant; use syn::{ self, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields, @@ -42,8 +41,15 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream { .ok() .unwrap_or_default())); let item = Item::from_args_struct(input, name); - let fields = &fields.named; - gen_for_struct(&item, ident, &input.generics, fields) + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::>(); + gen_for_struct(&item, ident, &input.generics, &fields) } Data::Struct(DataStruct { fields: Fields::Unit, @@ -55,8 +61,15 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream { .ok() .unwrap_or_default())); let item = Item::from_args_struct(input, name); - let fields = &Punctuated::::new(); - gen_for_struct(&item, ident, &input.generics, fields) + let fields = Punctuated::::new(); + let fields = fields + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::>(); + gen_for_struct(&item, ident, &input.generics, &fields) } Data::Enum(ref e) => { dummies::parser_enum(ident); @@ -65,8 +78,16 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream { .ok() .unwrap_or_default())); let item = Item::from_subcommand_enum(input, name); - let variants = &e.variants; - gen_for_enum(&item, ident, &input.generics, variants) + let variants = e + .variants + .iter() + .map(|variant| { + let item = + Item::from_subcommand_variant(variant, item.casing(), item.env_casing()); + (variant, item) + }) + .collect::>(); + gen_for_enum(&item, ident, &input.generics, &variants) } _ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"), } @@ -76,7 +97,7 @@ fn gen_for_struct( item: &Item, item_name: &Ident, generics: &Generics, - fields: &Punctuated, + fields: &[(&Field, Item)], ) -> TokenStream { let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); @@ -95,7 +116,7 @@ fn gen_for_enum( item: &Item, item_name: &Ident, generics: &Generics, - variants: &Punctuated, + variants: &[(&Variant, Item)], ) -> TokenStream { let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); diff --git a/clap_derive/src/derives/subcommand.rs b/clap_derive/src/derives/subcommand.rs index 508c2bbb..408f20de 100644 --- a/clap_derive/src/derives/subcommand.rs +++ b/clap_derive/src/derives/subcommand.rs @@ -15,10 +15,7 @@ use proc_macro2::{Ident, Span, TokenStream}; use proc_macro_error::{abort, abort_call_site}; use quote::{format_ident, quote, quote_spanned}; -use syn::{ - punctuated::Punctuated, spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Token, - Variant, -}; +use syn::{spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Variant}; use crate::derives::args; use crate::dummies; @@ -34,8 +31,16 @@ pub fn derive_subcommand(input: &DeriveInput) -> TokenStream { Data::Enum(ref e) => { let name = Name::Derived(ident.clone()); let item = Item::from_subcommand_enum(input, name); - let variants = &e.variants; - gen_for_enum(&item, ident, &input.generics, variants) + let variants = e + .variants + .iter() + .map(|variant| { + let item = + Item::from_subcommand_variant(variant, item.casing(), item.env_casing()); + (variant, item) + }) + .collect::>(); + gen_for_enum(&item, ident, &input.generics, &variants) } _ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"), } @@ -45,16 +50,16 @@ pub fn gen_for_enum( item: &Item, item_name: &Ident, generics: &Generics, - variants: &Punctuated, + variants: &[(&Variant, Item)], ) -> TokenStream { let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let from_arg_matches = gen_from_arg_matches(variants, item); - let update_from_arg_matches = gen_update_from_arg_matches(variants, item); + let from_arg_matches = gen_from_arg_matches(variants); + let update_from_arg_matches = gen_update_from_arg_matches(variants); let augmentation = gen_augment(variants, item, false); let augmentation_update = gen_augment(variants, item, true); - let has_subcommand = gen_has_subcommand(variants, item); + let has_subcommand = gen_has_subcommand(variants); quote! { #[allow(dead_code, unreachable_code, unused_variables, unused_braces)] @@ -111,7 +116,7 @@ pub fn gen_for_enum( } fn gen_augment( - variants: &Punctuated, + variants: &[(&Variant, Item)], parent_item: &Item, override_required: bool, ) -> TokenStream { @@ -121,12 +126,7 @@ fn gen_augment( let subcommands: Vec<_> = variants .iter() - .filter_map(|variant| { - let item = Item::from_subcommand_variant( - variant, - parent_item.casing(), - parent_item.env_casing(), - ); + .filter_map(|(variant, item)| { let kind = item.kind(); match &*kind { @@ -238,7 +238,15 @@ fn gen_augment( let sub_augment = match variant.fields { Named(ref fields) => { // Defer to `gen_augment` for adding cmd methods - args::gen_augment(&fields.named, &subcommand_var, &item, override_required) + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::>(); + args::gen_augment(&fields, &subcommand_var, item, override_required) } Unit => { let arg_block = quote!( #subcommand_var ); @@ -300,23 +308,14 @@ fn gen_augment( } } -fn gen_has_subcommand( - variants: &Punctuated, - parent_item: &Item, -) -> TokenStream { +fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> TokenStream { use syn::Fields::*; let mut ext_subcmd = false; let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants .iter() - .filter_map(|variant| { - let item = Item::from_subcommand_variant( - variant, - parent_item.casing(), - parent_item.env_casing(), - ); - + .filter_map(|(variant, item)| { if let Kind::ExternalSubcommand = &*item.kind() { ext_subcmd = true; None @@ -367,10 +366,7 @@ fn gen_has_subcommand( } } -fn gen_from_arg_matches( - variants: &Punctuated, - parent_item: &Item, -) -> TokenStream { +fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream { use syn::Fields::*; let mut ext_subcmd = None; @@ -379,13 +375,7 @@ fn gen_from_arg_matches( let sub_arg_matches_var = format_ident!("__clap_arg_matches"); let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants .iter() - .filter_map(|variant| { - let item = Item::from_subcommand_variant( - variant, - parent_item.casing(), - parent_item.env_casing(), - ); - + .filter_map(|(variant, item)| { if let Kind::ExternalSubcommand = &*item.kind() { if ext_subcmd.is_some() { abort!( @@ -443,7 +433,17 @@ fn gen_from_arg_matches( let sub_name = item.cased_name(); let variant_name = &variant.ident; let constructor_block = match variant.fields { - Named(ref fields) => args::gen_constructor(&fields.named, item), + Named(ref fields) => { + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::>(); + args::gen_constructor(&fields) + }, Unit => quote!(), Unnamed(ref fields) if fields.unnamed.len() == 1 => { let ty = &fields.unnamed[0]; @@ -519,21 +519,12 @@ fn gen_from_arg_matches( } } -fn gen_update_from_arg_matches( - variants: &Punctuated, - parent_item: &Item, -) -> TokenStream { +fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream { use syn::Fields::*; let (flatten, variants): (Vec<_>, Vec<_>) = variants .iter() - .filter_map(|variant| { - let item = Item::from_subcommand_variant( - variant, - parent_item.casing(), - parent_item.env_casing(), - ); - + .filter_map(|(variant, item)| { match &*item.kind() { // Fallback to `from_arg_matches_mut` Kind::ExternalSubcommand => None, @@ -553,7 +544,15 @@ fn gen_update_from_arg_matches( let field_names = fields.named.iter().map(|field| { field.ident.as_ref().unwrap() }).collect::>(); - let update = args::gen_updater(&fields.named, item, false); + let fields = fields + .named + .iter() + .map(|field| { + let item = Item::from_args_field(field, item.casing(), item.env_casing()); + (field, item) + }) + .collect::>(); + let update = args::gen_updater(&fields, false); (quote!( { #( #field_names, )* }), quote!( { #update } )) } Unit => (quote!(), quote!({})), diff --git a/clap_derive/src/derives/value_enum.rs b/clap_derive/src/derives/value_enum.rs index e78cadb0..8ef32903 100644 --- a/clap_derive/src/derives/value_enum.rs +++ b/clap_derive/src/derives/value_enum.rs @@ -12,10 +12,7 @@ use proc_macro2::TokenStream; use proc_macro_error::{abort, abort_call_site}; use quote::quote; use quote::quote_spanned; -use syn::{ - punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DeriveInput, Fields, Ident, - Variant, -}; +use syn::{spanned::Spanned, Data, DeriveInput, Fields, Ident, Variant}; use crate::dummies; use crate::item::{Item, Kind, Name}; @@ -29,19 +26,23 @@ pub fn derive_value_enum(input: &DeriveInput) -> TokenStream { Data::Enum(ref e) => { let name = Name::Derived(ident.clone()); let item = Item::from_value_enum(input, name); - let variants = &e.variants; - gen_for_enum(&item, ident, variants) + let variants = e + .variants + .iter() + .map(|variant| { + let item = + Item::from_value_enum_variant(variant, item.casing(), item.env_casing()); + (variant, item) + }) + .collect::>(); + gen_for_enum(&item, ident, &variants) } _ => abort_call_site!("`#[derive(ValueEnum)]` only supports enums"), } } -pub fn gen_for_enum( - item: &Item, - item_name: &Ident, - variants: &Punctuated, -) -> TokenStream { - let lits = lits(variants, item); +pub fn gen_for_enum(_item: &Item, item_name: &Ident, variants: &[(&Variant, Item)]) -> TokenStream { + let lits = lits(variants); let value_variants = gen_value_variants(&lits); let to_possible_value = gen_to_possible_value(&lits); @@ -66,15 +67,10 @@ pub fn gen_for_enum( } } -fn lits(variants: &Punctuated, parent_item: &Item) -> Vec<(TokenStream, Ident)> { +fn lits(variants: &[(&Variant, Item)]) -> Vec<(TokenStream, Ident)> { variants .iter() - .filter_map(|variant| { - let item = Item::from_value_enum_variant( - variant, - parent_item.casing(), - parent_item.env_casing(), - ); + .filter_map(|(variant, item)| { if let Kind::Skip(_) = &*item.kind() { None } else {