Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(derive): Provide derive-friendly deprecation messages #3832

Merged
merged 5 commits into from Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Expand Up @@ -73,7 +73,8 @@ color = ["atty", "termcolor"]
suggestions = ["strsim"]

# Optional
deprecated = [] # Guided experience to prepare for next breaking release (at different stages of development, this may become default)
# note: this will always enable clap_derive, change this to `clap_derive?/unstable-v4` when MSRV is bigger than 1.60
deprecated = ["clap_derive/deprecated"] # Guided experience to prepare for next breaking release (at different stages of development, this may become default)
derive = ["clap_derive", "once_cell"]
cargo = ["once_cell"] # Disable if you're not using Cargo, enables Cargo-env-var-dependent macros
wrap_help = ["terminal_size", "textwrap/terminal_size"]
Expand Down
4 changes: 3 additions & 1 deletion clap_derive/Cargo.toml
Expand Up @@ -51,4 +51,6 @@ proc-macro-error = "1"
[features]
default = []
debug = []
unstable-v4 = []
unstable-v4 = ["deprecated"]
deprecated = []
raw-deprecated = ["deprecated"]
4 changes: 4 additions & 0 deletions clap_derive/src/attrs.rs
Expand Up @@ -825,6 +825,10 @@ impl Attrs {
self.value_parser.is_some() || self.action.is_some()
}

pub fn explicit_parser(&self) -> bool {
self.parser.is_some()
}

pub fn parser(&self, field_type: &Type) -> Sp<Parser> {
self.parser
.clone()
Expand Down
75 changes: 68 additions & 7 deletions clap_derive/src/derives/args.rs
Expand Up @@ -113,6 +113,7 @@ pub fn gen_from_arg_matches_for_struct(

let constructor = gen_constructor(fields, &attrs);
let updater = gen_updater(fields, &attrs, true);
let raw_deprecated = raw_deprecated();

let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

Expand All @@ -136,6 +137,7 @@ pub fn gen_from_arg_matches_for_struct(
}

fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
#raw_deprecated
let v = #struct_name #constructor;
::std::result::Result::Ok(v)
}
Expand All @@ -145,6 +147,7 @@ pub fn gen_from_arg_matches_for_struct(
}

fn update_from_arg_matches_mut(&mut self, __clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<(), clap::Error> {
#raw_deprecated
#updater
::std::result::Result::Ok(())
}
Expand Down Expand Up @@ -272,6 +275,45 @@ pub fn gen_augment(
quote!()
}
};
let parse_deprecation = match *parser.kind {
_ if !attrs.explicit_parser() || cfg!(not(feature = "deprecated")) => quote!(),
ParserKind::FromStr => quote_spanned! { func.span()=>
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]`")]
fn parse_from_str() {
}
parse_from_str();
},
ParserKind::TryFromStr => quote_spanned! { func.span()=>
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]`")]
fn parse_try_from_str() {
}
parse_try_from_str();
},
ParserKind::FromOsStr => quote_spanned! { func.span()=>
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser)]` for `PathBuf` or `#[clap(value_parser = ...)]` with a custom `TypedValueParser`")]
fn parse_from_os_str() {
}
parse_from_os_str();
},
ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(value_parser = ...)]` with a custom `TypedValueParser`")]
fn parse_try_from_os_str() {
}
parse_try_from_os_str();
},
ParserKind::FromFlag => quote_spanned! { func.span()=>
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::SetTrue)]`")]
fn parse_from_flag() {
}
parse_from_flag();
},
ParserKind::FromOccurrences => quote_spanned! { func.span()=>
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::Count)]` with a field type of `u8`")]
fn parse_from_occurrences() {
}
parse_from_occurrences();
},
};

let value_name = attrs.value_name();
let possible_values = if attrs.is_enum() && !attrs.ignore_parser() {
Expand All @@ -280,7 +322,7 @@ pub fn gen_augment(
quote!()
};

let modifier = match **ty {
let implicit_methods = match **ty {
Ty::Option => {
quote_spanned! { ty.span()=>
.takes_value(true)
Expand Down Expand Up @@ -401,14 +443,20 @@ pub fn gen_augment(
};

let id = attrs.id();
let methods = attrs.field_methods(true);
let explicit_methods = attrs.field_methods(true);

Some(quote_spanned! { field.span()=>
let #app_var = #app_var.arg(
clap::Arg::new(#id)
#modifier
#methods
);
let #app_var = #app_var.arg({
#parse_deprecation

#[allow(deprecated)]
let arg = clap::Arg::new(#id)
#implicit_methods;

let arg = arg
#explicit_methods;
arg
});
})
}
}
Expand Down Expand Up @@ -733,3 +781,16 @@ fn gen_parsers(
quote_spanned!(field.span()=> #field_name: #field_value )
}
}

#[cfg(feature = "raw-deprecated")]
pub fn raw_deprecated() -> TokenStream {
quote! {}
}

#[cfg(not(feature = "raw-deprecated"))]
pub fn raw_deprecated() -> TokenStream {
quote! {
#![allow(deprecated)] // Assuming any deprecation in here will be related to a deprecation in `Args`

}
}
6 changes: 6 additions & 0 deletions clap_derive/src/derives/subcommand.rs
Expand Up @@ -540,8 +540,11 @@ fn gen_from_arg_matches(
},
};

let raw_deprecated = args::raw_deprecated();
quote! {
fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
#raw_deprecated

#( #child_subcommands )else*

if let Some((#subcommand_name_var, mut __clap_arg_sub_matches)) = __clap_arg_matches.remove_subcommand() {
Expand Down Expand Up @@ -652,11 +655,14 @@ fn gen_update_from_arg_matches(
}
});

let raw_deprecated = args::raw_deprecated();
quote! {
fn update_from_arg_matches_mut<'b>(
&mut self,
__clap_arg_matches: &mut clap::ArgMatches,
) -> ::std::result::Result<(), clap::Error> {
#raw_deprecated

if let Some(__clap_name) = __clap_arg_matches.subcommand_name() {
match self {
#( #subcommands ),*
Expand Down