refactor(derive): Clarify we are dealing with API item

This commit is contained in:
Ed Page 2022-08-31 21:19:26 -05:00
parent 7242e22810
commit d9844002e5
7 changed files with 121 additions and 124 deletions

View file

@ -13,8 +13,8 @@
// MIT/Apache 2.0 license.
use crate::{
attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
dummies,
item::{Item, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
utils::{inner_type, sub_type, Sp, Ty},
};
@ -55,7 +55,7 @@ pub fn gen_for_struct(
fields: &Punctuated<Field, Comma>,
attrs: &[Attribute],
) -> TokenStream {
let attrs = Attrs::from_args_struct(
let item = Item::from_args_struct(
Span::call_site(),
attrs,
Name::Derived(struct_name.clone()),
@ -65,13 +65,13 @@ pub fn gen_for_struct(
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let constructor = gen_constructor(fields, &attrs);
let updater = gen_updater(fields, &attrs, true);
let constructor = gen_constructor(fields, &item);
let updater = gen_updater(fields, &item, true);
let raw_deprecated = raw_deprecated();
let app_var = Ident::new("__clap_app", Span::call_site());
let augmentation = gen_augment(fields, &app_var, &attrs, false);
let augmentation_update = gen_augment(fields, &app_var, &attrs, true);
let augmentation = gen_augment(fields, &app_var, &item, false);
let augmentation_update = gen_augment(fields, &app_var, &item, true);
quote! {
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
@ -138,16 +138,16 @@ pub fn gen_for_struct(
pub fn gen_augment(
fields: &Punctuated<Field, Comma>,
app_var: &Ident,
parent_attribute: &Attrs,
parent_item: &Item,
override_required: bool,
) -> TokenStream {
let mut subcmds = fields.iter().filter_map(|field| {
let attrs = Attrs::from_args_field(
let item = Item::from_args_field(
field,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
let kind = attrs.kind();
let kind = item.kind();
if let Kind::Subcommand(ty) = &*kind {
let subcmd_type = match (**ty, sub_type(&field.ty)) {
(Ty::Option, Some(sub_type)) => sub_type,
@ -188,12 +188,12 @@ pub fn gen_augment(
}
let args = fields.iter().filter_map(|field| {
let attrs = Attrs::from_args_field(
let item = Item::from_args_field(
field,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
let kind = attrs.kind();
let kind = item.kind();
match &*kind {
Kind::Subcommand(_)
| Kind::Skip(_)
@ -202,8 +202,8 @@ pub fn gen_augment(
Kind::Flatten => {
let ty = &field.ty;
let old_heading_var = format_ident!("__clap_old_heading");
let next_help_heading = attrs.next_help_heading();
let next_display_order = attrs.next_display_order();
let next_help_heading = item.next_help_heading();
let next_display_order = item.next_display_order();
if override_required {
Some(quote_spanned! { kind.span()=>
let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned()));
@ -221,9 +221,9 @@ pub fn gen_augment(
}
}
Kind::Arg(ty) => {
let value_parser = attrs.value_parser(&field.ty);
let action = attrs.action(&field.ty);
let value_name = attrs.value_name();
let value_parser = item.value_parser(&field.ty);
let action = item.action(&field.ty);
let value_name = item.value_name();
let implicit_methods = match **ty {
Ty::Option => {
@ -242,7 +242,7 @@ pub fn gen_augment(
},
Ty::OptionVec => {
if attrs.is_positional() {
if item.is_positional() {
quote_spanned! { ty.span()=>
.value_name(#value_name)
.num_args(1..) // action won't be sufficient for getting multiple
@ -259,7 +259,7 @@ pub fn gen_augment(
}
Ty::Vec => {
if attrs.is_positional() {
if item.is_positional() {
quote_spanned! { ty.span()=>
.value_name(#value_name)
.num_args(1..) // action won't be sufficient for getting multiple
@ -276,7 +276,7 @@ pub fn gen_augment(
}
Ty::Other => {
let required = attrs.find_default_method().is_none() && !override_required;
let required = item.find_default_method().is_none() && !override_required;
// `ArgAction::takes_values` is assuming `ArgAction::default_value` will be
// set though that won't always be true but this should be good enough,
// otherwise we'll report an "arg required" error when unwrapping.
@ -290,8 +290,8 @@ pub fn gen_augment(
}
};
let id = attrs.id();
let explicit_methods = attrs.field_methods(true);
let id = item.id();
let explicit_methods = item.field_methods(true);
Some(quote_spanned! { field.span()=>
let #app_var = #app_var.arg({
@ -308,8 +308,8 @@ pub fn gen_augment(
}
});
let initial_app_methods = parent_attribute.initial_top_level_methods();
let final_app_methods = parent_attribute.final_top_level_methods();
let initial_app_methods = parent_item.initial_top_level_methods();
let final_app_methods = parent_item.final_top_level_methods();
quote! {{
let #app_var = #app_var #initial_app_methods;
#( #args )*
@ -318,15 +318,15 @@ pub fn gen_augment(
}}
}
pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_item: &Item) -> TokenStream {
let fields = fields.iter().map(|field| {
let attrs = Attrs::from_args_field(
let item = Item::from_args_field(
field,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
let field_name = field.ident.as_ref().unwrap();
let kind = attrs.kind();
let kind = item.kind();
let arg_matches = format_ident!("__clap_arg_matches");
match &*kind {
Kind::ExternalSubcommand => {
@ -371,7 +371,7 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Att
},
Kind::Arg(ty) | Kind::FromGlobal(ty) => {
gen_parsers(&attrs, ty, field_name, field, None)
gen_parsers(&item, ty, field_name, field, None)
}
}
});
@ -383,17 +383,17 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Att
pub fn gen_updater(
fields: &Punctuated<Field, Comma>,
parent_attribute: &Attrs,
parent_item: &Item,
use_self: bool,
) -> TokenStream {
let fields = fields.iter().map(|field| {
let attrs = Attrs::from_args_field(
let item = Item::from_args_field(
field,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
let field_name = field.ident.as_ref().unwrap();
let kind = attrs.kind();
let kind = item.kind();
let access = if use_self {
quote! {
@ -452,7 +452,7 @@ pub fn gen_updater(
Kind::Skip(_) => quote!(),
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&attrs, ty, field_name, field, Some(&access)),
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&item, ty, field_name, field, Some(&access)),
}
});
@ -462,7 +462,7 @@ pub fn gen_updater(
}
fn gen_parsers(
attrs: &Attrs,
item: &Item,
ty: &Sp<Ty>,
field_name: &Ident,
field: &Field,
@ -470,7 +470,7 @@ fn gen_parsers(
) -> TokenStream {
let span = ty.span();
let convert_type = inner_type(&field.ty);
let id = attrs.id();
let id = item.id();
let get_one = quote_spanned!(span=> remove_one::<#convert_type>);
let get_many = quote_spanned!(span=> remove_many::<#convert_type>);
let deref = quote!(|s| s);

View file

@ -19,7 +19,7 @@ use quote::quote;
use syn::{Attribute, Generics, Ident};
use crate::{
attrs::{Attrs, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
item::{Item, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
utils::Sp,
};
@ -30,14 +30,14 @@ pub fn gen_for_struct(
) -> TokenStream {
let app_name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
let attrs = Attrs::from_args_struct(
let item = Item::from_args_struct(
Span::call_site(),
attrs,
Name::Assigned(quote!(#app_name)),
Sp::call_site(DEFAULT_CASING),
Sp::call_site(DEFAULT_ENV_CASING),
);
let name = attrs.cased_name();
let name = item.cased_name();
let app_var = Ident::new("__clap_app", Span::call_site());
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
@ -75,14 +75,14 @@ pub fn gen_for_struct(
pub fn gen_for_enum(enum_name: &Ident, generics: &Generics, attrs: &[Attribute]) -> TokenStream {
let app_name = env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
let attrs = Attrs::from_subcommand_enum(
let item = Item::from_subcommand_enum(
Span::call_site(),
attrs,
Name::Assigned(quote!(#app_name)),
Sp::call_site(DEFAULT_CASING),
Sp::call_site(DEFAULT_ENV_CASING),
);
let name = attrs.cased_name();
let name = item.cased_name();
let app_var = Ident::new("__clap_app", Span::call_site());
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

View file

@ -12,9 +12,9 @@
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.
use crate::{
attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
derives::args,
dummies,
item::{Item, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
utils::{is_simple_ty, subty_if_name, Sp},
};
@ -43,7 +43,7 @@ pub fn gen_for_enum(
attrs: &[Attribute],
e: &DataEnum,
) -> TokenStream {
let attrs = Attrs::from_subcommand_enum(
let item = Item::from_subcommand_enum(
Span::call_site(),
attrs,
Name::Derived(enum_name.clone()),
@ -51,12 +51,12 @@ pub fn gen_for_enum(
Sp::call_site(DEFAULT_ENV_CASING),
);
let from_arg_matches = gen_from_arg_matches(enum_name, &e.variants, &attrs);
let update_from_arg_matches = gen_update_from_arg_matches(enum_name, &e.variants, &attrs);
let from_arg_matches = gen_from_arg_matches(enum_name, &e.variants, &item);
let update_from_arg_matches = gen_update_from_arg_matches(enum_name, &e.variants, &item);
let augmentation = gen_augment(&e.variants, &attrs, false);
let augmentation_update = gen_augment(&e.variants, &attrs, true);
let has_subcommand = gen_has_subcommand(&e.variants, &attrs);
let augmentation = gen_augment(&e.variants, &item, false);
let augmentation_update = gen_augment(&e.variants, &item, true);
let has_subcommand = gen_has_subcommand(&e.variants, &item);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
@ -116,7 +116,7 @@ pub fn gen_for_enum(
fn gen_augment(
variants: &Punctuated<Variant, Token![,]>,
parent_attribute: &Attrs,
parent_item: &Item,
override_required: bool,
) -> TokenStream {
use syn::Fields::*;
@ -126,12 +126,12 @@ fn gen_augment(
let subcommands: Vec<_> = variants
.iter()
.filter_map(|variant| {
let attrs = Attrs::from_subcommand_variant(
let item = Item::from_subcommand_variant(
variant,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
let kind = attrs.kind();
let kind = item.kind();
match &*kind {
Kind::Skip(_) => None,
@ -167,8 +167,8 @@ fn gen_augment(
Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
let ty = &unnamed[0];
let old_heading_var = format_ident!("__clap_old_heading");
let next_help_heading = attrs.next_help_heading();
let next_display_order = attrs.next_display_order();
let next_help_heading = item.next_help_heading();
let next_display_order = item.next_display_order();
let subcommand = if override_required {
quote! {
let #old_heading_var = #app_var.get_next_help_heading().map(|s| clap::builder::Str::from(s.to_owned()));
@ -220,9 +220,9 @@ fn gen_augment(
}
};
let name = attrs.cased_name();
let initial_app_methods = attrs.initial_top_level_methods();
let final_from_attrs = attrs.final_top_level_methods();
let name = item.cased_name();
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
let subcommand = quote! {
let #app_var = #app_var.subcommand({
let #subcommand_var = clap::Command::new(#name);
@ -242,12 +242,12 @@ 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, &attrs, override_required)
args::gen_augment(&fields.named, &subcommand_var, &item, override_required)
}
Unit => {
let arg_block = quote!( #subcommand_var );
let initial_app_methods = attrs.initial_top_level_methods();
let final_from_attrs = attrs.final_top_level_methods();
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
quote! {
let #subcommand_var = #subcommand_var #initial_app_methods;
let #subcommand_var = #arg_block;
@ -269,8 +269,8 @@ fn gen_augment(
}
}
};
let initial_app_methods = attrs.initial_top_level_methods();
let final_from_attrs = attrs.final_top_level_methods();
let initial_app_methods = item.initial_top_level_methods();
let final_from_attrs = item.final_top_level_methods();
quote! {
let #subcommand_var = #subcommand_var #initial_app_methods;
let #subcommand_var = #arg_block;
@ -282,7 +282,7 @@ fn gen_augment(
}
};
let name = attrs.cased_name();
let name = item.cased_name();
let subcommand = quote! {
let #app_var = #app_var.subcommand({
let #subcommand_var = clap::Command::new(#name);
@ -295,8 +295,8 @@ fn gen_augment(
})
.collect();
let initial_app_methods = parent_attribute.initial_top_level_methods();
let final_app_methods = parent_attribute.final_top_level_methods();
let initial_app_methods = parent_item.initial_top_level_methods();
let final_app_methods = parent_item.final_top_level_methods();
quote! {
let #app_var = #app_var #initial_app_methods;
#( #subcommands )*;
@ -306,7 +306,7 @@ fn gen_augment(
fn gen_has_subcommand(
variants: &Punctuated<Variant, Token![,]>,
parent_attribute: &Attrs,
parent_item: &Item,
) -> TokenStream {
use syn::Fields::*;
@ -315,26 +315,26 @@ fn gen_has_subcommand(
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
.iter()
.filter_map(|variant| {
let attrs = Attrs::from_subcommand_variant(
let item = Item::from_subcommand_variant(
variant,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
if let Kind::ExternalSubcommand = &*attrs.kind() {
if let Kind::ExternalSubcommand = &*item.kind() {
ext_subcmd = true;
None
} else {
Some((variant, attrs))
Some((variant, item))
}
})
.partition(|(_, attrs)| {
let kind = attrs.kind();
.partition(|(_, item)| {
let kind = item.kind();
matches!(&*kind, Kind::Flatten)
});
let subcommands = variants.iter().map(|(_variant, attrs)| {
let sub_name = attrs.cased_name();
let subcommands = variants.iter().map(|(_variant, item)| {
let sub_name = item.cased_name();
quote! {
if #sub_name == __clap_name {
return true
@ -374,7 +374,7 @@ fn gen_has_subcommand(
fn gen_from_arg_matches(
name: &Ident,
variants: &Punctuated<Variant, Token![,]>,
parent_attribute: &Attrs,
parent_item: &Item,
) -> TokenStream {
use syn::Fields::*;
@ -385,16 +385,16 @@ fn gen_from_arg_matches(
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
.iter()
.filter_map(|variant| {
let attrs = Attrs::from_subcommand_variant(
let item = Item::from_subcommand_variant(
variant,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
if let Kind::ExternalSubcommand = &*attrs.kind() {
if let Kind::ExternalSubcommand = &*item.kind() {
if ext_subcmd.is_some() {
abort!(
attrs.kind().span(),
item.kind().span(),
"Only one variant can be marked with `external_subcommand`, \
this is the second"
);
@ -436,19 +436,19 @@ fn gen_from_arg_matches(
ext_subcmd = Some((span, &variant.ident, str_ty));
None
} else {
Some((variant, attrs))
Some((variant, item))
}
})
.partition(|(_, attrs)| {
let kind = attrs.kind();
.partition(|(_, item)| {
let kind = item.kind();
matches!(&*kind, Kind::Flatten)
});
let subcommands = variants.iter().map(|(variant, attrs)| {
let sub_name = attrs.cased_name();
let subcommands = variants.iter().map(|(variant, item)| {
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, attrs),
Named(ref fields) => args::gen_constructor(&fields.named, item),
Unit => quote!(),
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
let ty = &fields.unnamed[0];
@ -527,32 +527,32 @@ fn gen_from_arg_matches(
fn gen_update_from_arg_matches(
name: &Ident,
variants: &Punctuated<Variant, Token![,]>,
parent_attribute: &Attrs,
parent_item: &Item,
) -> TokenStream {
use syn::Fields::*;
let (flatten, variants): (Vec<_>, Vec<_>) = variants
.iter()
.filter_map(|variant| {
let attrs = Attrs::from_subcommand_variant(
let item = Item::from_subcommand_variant(
variant,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
match &*attrs.kind() {
match &*item.kind() {
// Fallback to `from_arg_matches_mut`
Kind::ExternalSubcommand => None,
_ => Some((variant, attrs)),
_ => Some((variant, item)),
}
})
.partition(|(_, attrs)| {
let kind = attrs.kind();
.partition(|(_, item)| {
let kind = item.kind();
matches!(&*kind, Kind::Flatten)
});
let subcommands = variants.iter().map(|(variant, attrs)| {
let sub_name = attrs.cased_name();
let subcommands = variants.iter().map(|(variant, item)| {
let sub_name = item.cased_name();
let variant_name = &variant.ident;
let (pattern, updater) = match variant.fields {
Named(ref fields) => {
@ -560,15 +560,15 @@ fn gen_update_from_arg_matches(
.named
.iter()
.map(|field| {
let attrs = Attrs::from_args_field(
let item = Item::from_args_field(
field,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
let field_name = field.ident.as_ref().unwrap();
(
quote!( ref mut #field_name ),
args::gen_updater(&fields.named, &attrs, false),
args::gen_updater(&fields.named, &item, false),
)
})
.unzip();

View file

@ -9,8 +9,8 @@
// except according to those terms.
use crate::{
attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
dummies,
item::{Item, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
utils::Sp,
};
@ -35,7 +35,7 @@ pub fn derive_value_enum(input: &DeriveInput) -> TokenStream {
}
pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
let attrs = Attrs::from_value_enum(
let item = Item::from_value_enum(
Span::call_site(),
attrs,
Name::Derived(name.clone()),
@ -43,7 +43,7 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr
Sp::call_site(DEFAULT_ENV_CASING),
);
let lits = lits(&e.variants, &attrs);
let lits = lits(&e.variants, &item);
let value_variants = gen_value_variants(&lits);
let to_possible_value = gen_to_possible_value(&lits);
@ -68,26 +68,23 @@ pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStr
}
}
fn lits(
variants: &Punctuated<Variant, Comma>,
parent_attribute: &Attrs,
) -> Vec<(TokenStream, Ident)> {
fn lits(variants: &Punctuated<Variant, Comma>, parent_item: &Item) -> Vec<(TokenStream, Ident)> {
variants
.iter()
.filter_map(|variant| {
let attrs = Attrs::from_value_enum_variant(
let item = Item::from_value_enum_variant(
variant,
parent_attribute.casing(),
parent_attribute.env_casing(),
parent_item.casing(),
parent_item.env_casing(),
);
if let Kind::Skip(_) = &*attrs.kind() {
if let Kind::Skip(_) = &*item.kind() {
None
} else {
if !matches!(variant.fields, Fields::Unit) {
abort!(variant.span(), "`#[derive(ValueEnum)]` only supports unit variants. Non-unit variants must be skipped");
}
let fields = attrs.field_methods(false);
let name = attrs.cased_name();
let fields = item.field_methods(false);
let name = item.cased_name();
Some((
quote_spanned! { variant.span()=>
clap::builder::PossibleValue::new(#name)

View file

@ -35,7 +35,7 @@ pub const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
pub const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
#[derive(Clone)]
pub struct Attrs {
pub struct Item {
name: Name,
casing: Sp<CasingStyle>,
env_casing: Sp<CasingStyle>,
@ -53,7 +53,7 @@ pub struct Attrs {
kind: Sp<Kind>,
}
impl Attrs {
impl Item {
pub fn from_args_struct(
span: Span,
attrs: &[Attribute],

View file

@ -22,9 +22,9 @@ use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use syn::{parse_macro_input, DeriveInput};
mod attrs;
mod derives;
mod dummies;
mod item;
mod parse;
mod utils;

View file

@ -3,7 +3,7 @@
//! #[derive(Parser)] works in terms of "paragraphs". Paragraph is a sequence of
//! non-empty adjacent lines, delimited by sequences of blank (whitespace only) lines.
use crate::attrs::Method;
use crate::item::Method;
use quote::{format_ident, quote};
use std::iter;