Skip to content

Commit 132b5dd

Browse files
authored
Merge pull request #5425 from epage/lit
fix(derive): Re-allow expressions for id's
2 parents 024089b + df915fe commit 132b5dd

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

clap_derive/src/derives/args.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -717,9 +717,21 @@ fn gen_parsers(
717717
},
718718

719719
Ty::Other => {
720-
quote_spanned! { ty.span()=>
721-
#arg_matches.#get_one(#id)
722-
.ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, concat!("The following required argument was not provided: ", #id)))?
720+
// Prefer `concat` where possible for reduced code size but fallback to `format!` to
721+
// allow non-literal `id`s
722+
match id {
723+
Name::Assigned(_) => {
724+
quote_spanned! { ty.span()=>
725+
#arg_matches.#get_one(#id)
726+
.ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, format!("The following required argument was not provided: {}", #id)))?
727+
}
728+
}
729+
Name::Derived(_) => {
730+
quote_spanned! { ty.span()=>
731+
#arg_matches.#get_one(#id)
732+
.ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, concat!("The following required argument was not provided: ", #id)))?
733+
}
734+
}
723735
}
724736
}
725737
};

clap_derive/src/item.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -974,8 +974,8 @@ impl Item {
974974
quote!( #(#doc_comment)* #(#methods)* )
975975
}
976976

977-
pub fn group_id(&self) -> TokenStream {
978-
self.group_id.clone().raw()
977+
pub fn group_id(&self) -> &Name {
978+
&self.group_id
979979
}
980980

981981
pub fn group_methods(&self) -> TokenStream {
@@ -998,8 +998,8 @@ impl Item {
998998
quote!( #(#next_help_heading)* )
999999
}
10001000

1001-
pub fn id(&self) -> TokenStream {
1002-
self.name.clone().raw()
1001+
pub fn id(&self) -> &Name {
1002+
&self.name
10031003
}
10041004

10051005
pub fn cased_name(&self) -> TokenStream {
@@ -1410,16 +1410,6 @@ pub enum Name {
14101410
}
14111411

14121412
impl Name {
1413-
pub fn raw(self) -> TokenStream {
1414-
match self {
1415-
Name::Assigned(tokens) => tokens,
1416-
Name::Derived(ident) => {
1417-
let s = ident.unraw().to_string();
1418-
quote_spanned!(ident.span()=> #s)
1419-
}
1420-
}
1421-
}
1422-
14231413
pub fn translate(self, style: CasingStyle) -> TokenStream {
14241414
use CasingStyle::*;
14251415

@@ -1466,3 +1456,15 @@ impl Name {
14661456
}
14671457
}
14681458
}
1459+
1460+
impl ToTokens for Name {
1461+
fn to_tokens(&self, tokens: &mut TokenStream) {
1462+
match self {
1463+
Name::Assigned(t) => t.to_tokens(tokens),
1464+
Name::Derived(ident) => {
1465+
let s = ident.unraw().to_string();
1466+
quote_spanned!(ident.span()=> #s).to_tokens(tokens)
1467+
}
1468+
}
1469+
}
1470+
}

tests/derive/non_literal_attributes.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,19 +125,19 @@ fn test_bool() {
125125
assert_eq!(result.unwrap_err().kind(), ErrorKind::NoEquals);
126126
}
127127

128-
fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
129-
u64::from_str_radix(input, 16)
130-
}
131-
132-
#[derive(Parser, PartialEq, Debug)]
133-
struct HexOpt {
134-
#[arg(short, value_parser = parse_hex)]
135-
number: u64,
136-
}
137-
138128
#[test]
139129
#[cfg(feature = "error-context")]
140130
fn test_parse_hex_function_path() {
131+
#[derive(Parser, PartialEq, Debug)]
132+
struct HexOpt {
133+
#[arg(short, value_parser = parse_hex)]
134+
number: u64,
135+
}
136+
137+
fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
138+
u64::from_str_radix(input, 16)
139+
}
140+
141141
assert_eq!(
142142
HexOpt { number: 5 },
143143
HexOpt::try_parse_from(["test", "-n", "5"]).unwrap()
@@ -156,3 +156,20 @@ fn test_parse_hex_function_path() {
156156
err
157157
);
158158
}
159+
160+
#[test]
161+
#[cfg(feature = "error-context")]
162+
fn test_const_name() {
163+
#[derive(Parser, PartialEq, Debug)]
164+
struct Opt {
165+
#[arg(id = NAME, short, long)]
166+
number: u64,
167+
}
168+
169+
const NAME: &str = "fun";
170+
171+
assert_eq!(
172+
Opt { number: 5 },
173+
Opt::try_parse_from(["test", "-f", "5"]).unwrap()
174+
);
175+
}

0 commit comments

Comments
 (0)