fix(derive): Builder-specialized attributes

This commit is contained in:
Ed Page 2022-09-02 13:31:24 -05:00
parent 20ba828f21
commit e0f2f6fbae
6 changed files with 63 additions and 22 deletions

View file

@ -32,6 +32,12 @@ impl ClapAttr {
Some(Sp::new(AttrKind::Clap, attr.path.span()))
} else if attr.path.is_ident("structopt") {
Some(Sp::new(AttrKind::StructOpt, attr.path.span()))
} else if attr.path.is_ident("command") {
Some(Sp::new(AttrKind::Command, attr.path.span()))
} else if attr.path.is_ident("arg") {
Some(Sp::new(AttrKind::Arg, attr.path.span()))
} else if attr.path.is_ident("value") {
Some(Sp::new(AttrKind::Value, attr.path.span()))
} else {
None
};
@ -194,6 +200,9 @@ impl ToTokens for AttrValue {
pub enum AttrKind {
Clap,
StructOpt,
Command,
Arg,
Value,
}
impl AttrKind {
@ -201,6 +210,9 @@ impl AttrKind {
match self {
Self::Clap => "clap",
Self::StructOpt => "structopt",
Self::Command => "command",
Self::Arg => "arg",
Self::Value => "value",
}
}
}

View file

@ -204,7 +204,7 @@ pub fn gen_augment(
Kind::Command(_)
| Kind::Value(_)
| Kind::Subcommand(_)
| Kind::Skip(_)
| Kind::Skip(_, _)
| Kind::FromGlobal(_)
| Kind::ExternalSubcommand => None,
Kind::Flatten => {
@ -384,7 +384,7 @@ pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream {
#field_name: clap::FromArgMatches::from_arg_matches_mut(#arg_matches)?
},
Kind::Skip(val) => match val {
Kind::Skip(val, _) => match val {
None => quote_spanned!(kind.span()=> #field_name: Default::default()),
Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
},
@ -463,7 +463,7 @@ pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream {
}
},
Kind::Skip(_) => quote!(),
Kind::Skip(_, _) => quote!(),
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(item, ty, field_name, field, Some(&access)),
}

View file

@ -137,7 +137,7 @@ fn gen_augment(
let kind = item.kind();
match &*kind {
Kind::Skip(_) => None,
Kind::Skip(_, _) => None,
Kind::ExternalSubcommand => {
let ty = match variant.fields {

View file

@ -78,7 +78,7 @@ fn lits(variants: &[(&Variant, Item)]) -> Vec<(TokenStream, Ident)> {
variants
.iter()
.filter_map(|(variant, item)| {
if let Kind::Skip(_) = &*item.kind() {
if let Kind::Skip(_, _) = &*item.kind() {
None
} else {
if !matches!(variant.fields, Fields::Unit) {

View file

@ -197,7 +197,7 @@ impl Item {
Kind::ExternalSubcommand
| Kind::FromGlobal(_)
| Kind::Skip(_)
| Kind::Skip(_, _)
| Kind::Command(_)
| Kind::Value(_)
| Kind::Arg(_) => (),
@ -321,7 +321,7 @@ impl Item {
res.kind = Sp::new(Kind::Subcommand(ty), res.kind.span());
}
Kind::Skip(_) => {
Kind::Skip(_, _) => {
if res.has_explicit_methods() {
abort!(
res.kind.span(),
@ -463,7 +463,10 @@ impl Item {
}
Some(MagicAttrName::Skip) => {
let expr = attr.value.clone();
let kind = Sp::new(Kind::Skip(expr), attr.name.clone().span());
let kind = Sp::new(
Kind::Skip(expr, self.kind.attr_kind()),
attr.name.clone().span(),
);
Some(kind)
}
_ => None,
@ -475,16 +478,29 @@ impl Item {
}
for attr in &parsed {
match attr.kind.get() {
AttrKind::Clap => {}
AttrKind::StructOpt => {
let actual_attr_kind = *attr.kind.get();
let expected_attr_kind = self.kind.attr_kind();
match (actual_attr_kind, expected_attr_kind) {
(AttrKind::Clap, _) => {}
(AttrKind::StructOpt, _) => {
self.deprecations.push(Deprecation::attribute(
"4.0.0",
*attr.kind.get(),
AttrKind::Clap,
actual_attr_kind,
expected_attr_kind,
attr.kind.span(),
));
}
_ if attr.kind != expected_attr_kind => {
abort!(
attr.kind.span(),
"Expected `{}` attribute instead of `{}`",
expected_attr_kind.as_str(),
actual_attr_kind.as_str()
);
}
_ => {}
}
if let Some(AttrValue::Call(tokens)) = &attr.value {
@ -868,12 +884,12 @@ impl Item {
(Kind::Arg(_), Kind::FromGlobal(_))
| (Kind::Arg(_), Kind::Subcommand(_))
| (Kind::Arg(_), Kind::Flatten)
| (Kind::Arg(_), Kind::Skip(_))
| (Kind::Arg(_), Kind::Skip(_, _))
| (Kind::Command(_), Kind::Subcommand(_))
| (Kind::Command(_), Kind::Flatten)
| (Kind::Command(_), Kind::Skip(_))
| (Kind::Command(_), Kind::Skip(_, _))
| (Kind::Command(_), Kind::ExternalSubcommand)
| (Kind::Value(_), Kind::Skip(_)) => {
| (Kind::Value(_), Kind::Skip(_, _)) => {
self.kind = kind;
}
@ -1117,7 +1133,7 @@ pub enum Kind {
FromGlobal(Sp<Ty>),
Subcommand(Sp<Ty>),
Flatten,
Skip(Option<AttrValue>),
Skip(Option<AttrValue>, AttrKind),
ExternalSubcommand,
}
@ -1130,10 +1146,23 @@ impl Kind {
Self::FromGlobal(_) => "from_global",
Self::Subcommand(_) => "subcommand",
Self::Flatten => "flatten",
Self::Skip(_) => "skip",
Self::Skip(_, _) => "skip",
Self::ExternalSubcommand => "external_subcommand",
}
}
pub fn attr_kind(&self) -> AttrKind {
match self {
Self::Arg(_) => AttrKind::Arg,
Self::Command(_) => AttrKind::Command,
Self::Value(_) => AttrKind::Value,
Self::FromGlobal(_) => AttrKind::Arg,
Self::Subcommand(_) => AttrKind::Command,
Self::Flatten => AttrKind::Command,
Self::Skip(_, kind) => *kind,
Self::ExternalSubcommand => AttrKind::Command,
}
}
}
#[derive(Clone)]

View file

@ -29,7 +29,7 @@ mod item;
mod utils;
/// Generates the `ValueEnum` impl.
#[proc_macro_derive(ValueEnum, attributes(clap))]
#[proc_macro_derive(ValueEnum, attributes(clap, value))]
#[proc_macro_error]
pub fn value_enum(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
@ -42,7 +42,7 @@ pub fn value_enum(input: TokenStream) -> TokenStream {
/// receiving an instance of `clap::ArgMatches` from conducting parsing, and then
/// implementing a conversion code to instantiate an instance of the user
/// context struct.
#[proc_macro_derive(Parser, attributes(clap, structopt))]
#[proc_macro_derive(Parser, attributes(clap, structopt, command, arg))]
#[proc_macro_error]
pub fn parser(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
@ -50,7 +50,7 @@ pub fn parser(input: TokenStream) -> TokenStream {
}
/// Generates the `Subcommand` impl.
#[proc_macro_derive(Subcommand, attributes(clap))]
#[proc_macro_derive(Subcommand, attributes(clap, command, arg))]
#[proc_macro_error]
pub fn subcommand(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);
@ -58,7 +58,7 @@ pub fn subcommand(input: TokenStream) -> TokenStream {
}
/// Generates the `Args` impl.
#[proc_macro_derive(Args, attributes(clap))]
#[proc_macro_derive(Args, attributes(clap, command, arg))]
#[proc_macro_error]
pub fn args(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input);