From df915fefefba42493290c4f7c4ac627807e9ebd4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 25 Mar 2024 14:42:22 -0500 Subject: [PATCH] fix(derive): Re-allow expressions for id's Fixes #5407 --- clap_derive/src/derives/args.rs | 18 +++++++++++++++--- tests/derive/non_literal_attributes.rs | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/clap_derive/src/derives/args.rs b/clap_derive/src/derives/args.rs index 279f6ca0..b1b16de5 100644 --- a/clap_derive/src/derives/args.rs +++ b/clap_derive/src/derives/args.rs @@ -717,9 +717,21 @@ fn gen_parsers( }, Ty::Other => { - quote_spanned! { ty.span()=> - #arg_matches.#get_one(#id) - .ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, concat!("The following required argument was not provided: ", #id)))? + // Prefer `concat` where possible for reduced code size but fallback to `format!` to + // allow non-literal `id`s + match id { + Name::Assigned(_) => { + quote_spanned! { ty.span()=> + #arg_matches.#get_one(#id) + .ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #id)))? + } + } + Name::Derived(_) => { + quote_spanned! { ty.span()=> + #arg_matches.#get_one(#id) + .ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, concat!("The following required argument was not provided: ", #id)))? + } + } } } }; diff --git a/tests/derive/non_literal_attributes.rs b/tests/derive/non_literal_attributes.rs index 25ae36e0..eba4124f 100644 --- a/tests/derive/non_literal_attributes.rs +++ b/tests/derive/non_literal_attributes.rs @@ -156,3 +156,20 @@ fn test_parse_hex_function_path() { err ); } + +#[test] +#[cfg(feature = "error-context")] +fn test_const_name() { + #[derive(Parser, PartialEq, Debug)] + struct Opt { + #[arg(id = NAME, short, long)] + number: u64, + } + + const NAME: &str = "fun"; + + assert_eq!( + Opt { number: 5 }, + Opt::try_parse_from(["test", "-f", "5"]).unwrap() + ); +}