1// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
2// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
3// Ana Hobden (@hoverbear) <operator@hoverbear.org>
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10//
11// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
12// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
13// MIT/Apache 2.0 license.
14
15use std::env;
16
17use heck::{ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
18use proc_macro2::{self, Span, TokenStream};
19use quote::{format_ident, quote, quote_spanned, ToTokens};
20use syn::DeriveInput;
21use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Field, Ident, LitStr, Type, Variant};
22
23use crate::attr::*;
24use crate::utils::{extract_doc_comment, format_doc_comment, inner_type, is_simple_ty, Sp, Ty};
25
26/// Default casing style for generated arguments.
27pub const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
28
29/// Default casing style for environment variables
30pub const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
31
32#[derive(Clone)]
33pub struct Item {
34    name: Name,
35    ident: Ident,
36    casing: Sp<CasingStyle>,
37    env_casing: Sp<CasingStyle>,
38    ty: Option<Type>,
39    doc_comment: Vec<Method>,
40    methods: Vec<Method>,
41    deprecations: Vec<Deprecation>,
42    value_parser: Option<ValueParser>,
43    action: Option<Action>,
44    verbatim_doc_comment: bool,
45    force_long_help: bool,
46    next_display_order: Option<Method>,
47    next_help_heading: Option<Method>,
48    is_enum: bool,
49    is_positional: bool,
50    skip_group: bool,
51    kind: Sp<Kind>,
52}
53
54impl Item {
55    pub fn from_args_struct(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
56        let ident = input.ident.clone();
57        let span = input.ident.span();
58        let attrs = &input.attrs;
59        let argument_casing = Sp::new(DEFAULT_CASING, span);
60        let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
61        let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
62
63        let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
64        let parsed_attrs = ClapAttr::parse_all(attrs)?;
65        res.infer_kind(&parsed_attrs)?;
66        res.push_attrs(&parsed_attrs)?;
67        res.push_doc_comment(attrs, "about", Some("long_about"));
68
69        Ok(res)
70    }
71
72    pub fn from_subcommand_enum(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
73        let ident = input.ident.clone();
74        let span = input.ident.span();
75        let attrs = &input.attrs;
76        let argument_casing = Sp::new(DEFAULT_CASING, span);
77        let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
78        let kind = Sp::new(Kind::Command(Sp::new(Ty::Other, span)), span);
79
80        let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
81        let parsed_attrs = ClapAttr::parse_all(attrs)?;
82        res.infer_kind(&parsed_attrs)?;
83        res.push_attrs(&parsed_attrs)?;
84        res.push_doc_comment(attrs, "about", Some("long_about"));
85
86        Ok(res)
87    }
88
89    pub fn from_value_enum(input: &DeriveInput, name: Name) -> Result<Self, syn::Error> {
90        let ident = input.ident.clone();
91        let span = input.ident.span();
92        let attrs = &input.attrs;
93        let argument_casing = Sp::new(DEFAULT_CASING, span);
94        let env_casing = Sp::new(DEFAULT_ENV_CASING, span);
95        let kind = Sp::new(Kind::Value, span);
96
97        let mut res = Self::new(name, ident, None, argument_casing, env_casing, kind);
98        let parsed_attrs = ClapAttr::parse_all(attrs)?;
99        res.infer_kind(&parsed_attrs)?;
100        res.push_attrs(&parsed_attrs)?;
101        // Ignoring `push_doc_comment` as there is no top-level clap builder to add documentation
102        // to
103
104        if res.has_explicit_methods() {
105            abort!(
106                res.methods[0].name.span(),
107                "{} doesn't exist for `ValueEnum` enums",
108                res.methods[0].name
109            );
110        }
111
112        Ok(res)
113    }
114
115    pub fn from_subcommand_variant(
116        variant: &Variant,
117        struct_casing: Sp<CasingStyle>,
118        env_casing: Sp<CasingStyle>,
119    ) -> Result<Self, syn::Error> {
120        let name = variant.ident.clone();
121        let ident = variant.ident.clone();
122        let span = variant.span();
123        let ty = match variant.fields {
124            syn::Fields::Unnamed(syn::FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
125                Ty::from_syn_ty(&unnamed[0].ty)
126            }
127            syn::Fields::Named(_) | syn::Fields::Unnamed(..) | syn::Fields::Unit => {
128                Sp::new(Ty::Other, span)
129            }
130        };
131        let kind = Sp::new(Kind::Command(ty), span);
132        let mut res = Self::new(
133            Name::Derived(name),
134            ident,
135            None,
136            struct_casing,
137            env_casing,
138            kind,
139        );
140        let parsed_attrs = ClapAttr::parse_all(&variant.attrs)?;
141        res.infer_kind(&parsed_attrs)?;
142        res.push_attrs(&parsed_attrs)?;
143        if matches!(&*res.kind, Kind::Command(_) | Kind::Subcommand(_)) {
144            res.push_doc_comment(&variant.attrs, "about", Some("long_about"));
145        }
146
147        match &*res.kind {
148            Kind::Flatten(_) => {
149                if res.has_explicit_methods() {
150                    abort!(
151                        res.kind.span(),
152                        "methods are not allowed for flattened entry"
153                    );
154                }
155            }
156
157            Kind::Subcommand(_)
158            | Kind::ExternalSubcommand
159            | Kind::FromGlobal(_)
160            | Kind::Skip(_, _)
161            | Kind::Command(_)
162            | Kind::Value
163            | Kind::Arg(_) => (),
164        }
165
166        Ok(res)
167    }
168
169    pub fn from_value_enum_variant(
170        variant: &Variant,
171        argument_casing: Sp<CasingStyle>,
172        env_casing: Sp<CasingStyle>,
173    ) -> Result<Self, syn::Error> {
174        let ident = variant.ident.clone();
175        let span = variant.span();
176        let kind = Sp::new(Kind::Value, span);
177        let mut res = Self::new(
178            Name::Derived(variant.ident.clone()),
179            ident,
180            None,
181            argument_casing,
182            env_casing,
183            kind,
184        );
185        let parsed_attrs = ClapAttr::parse_all(&variant.attrs)?;
186        res.infer_kind(&parsed_attrs)?;
187        res.push_attrs(&parsed_attrs)?;
188        if matches!(&*res.kind, Kind::Value) {
189            res.push_doc_comment(&variant.attrs, "help", None);
190        }
191
192        Ok(res)
193    }
194
195    pub fn from_args_field(
196        field: &Field,
197        struct_casing: Sp<CasingStyle>,
198        env_casing: Sp<CasingStyle>,
199    ) -> Result<Self, syn::Error> {
200        let name = field.ident.clone().unwrap();
201        let ident = field.ident.clone().unwrap();
202        let span = field.span();
203        let ty = Ty::from_syn_ty(&field.ty);
204        let kind = Sp::new(Kind::Arg(ty), span);
205        let mut res = Self::new(
206            Name::Derived(name),
207            ident,
208            Some(field.ty.clone()),
209            struct_casing,
210            env_casing,
211            kind,
212        );
213        let parsed_attrs = ClapAttr::parse_all(&field.attrs)?;
214        res.infer_kind(&parsed_attrs)?;
215        res.push_attrs(&parsed_attrs)?;
216        if matches!(&*res.kind, Kind::Arg(_)) {
217            res.push_doc_comment(&field.attrs, "help", Some("long_help"));
218        }
219
220        match &*res.kind {
221            Kind::Flatten(_) => {
222                if res.has_explicit_methods() {
223                    abort!(
224                        res.kind.span(),
225                        "methods are not allowed for flattened entry"
226                    );
227                }
228            }
229
230            Kind::Subcommand(_) => {
231                if res.has_explicit_methods() {
232                    abort!(
233                        res.kind.span(),
234                        "methods in attributes are not allowed for subcommand"
235                    );
236                }
237            }
238            Kind::Skip(_, _)
239            | Kind::FromGlobal(_)
240            | Kind::Arg(_)
241            | Kind::Command(_)
242            | Kind::Value
243            | Kind::ExternalSubcommand => {}
244        }
245
246        Ok(res)
247    }
248
249    fn new(
250        name: Name,
251        ident: Ident,
252        ty: Option<Type>,
253        casing: Sp<CasingStyle>,
254        env_casing: Sp<CasingStyle>,
255        kind: Sp<Kind>,
256    ) -> Self {
257        Self {
258            name,
259            ident,
260            ty,
261            casing,
262            env_casing,
263            doc_comment: vec![],
264            methods: vec![],
265            deprecations: vec![],
266            value_parser: None,
267            action: None,
268            verbatim_doc_comment: false,
269            force_long_help: false,
270            next_display_order: None,
271            next_help_heading: None,
272            is_enum: false,
273            is_positional: true,
274            skip_group: false,
275            kind,
276        }
277    }
278
279    fn push_method(&mut self, kind: AttrKind, name: Ident, arg: impl ToTokens) {
280        if name == "id" {
281            match kind {
282                AttrKind::Command | AttrKind::Value => {
283                    self.deprecations.push(Deprecation {
284                        span: name.span(),
285                        id: "id_is_only_for_arg",
286                        version: "4.0.0",
287                        description: format!(
288                            "`#[{}(id)] was allowed by mistake, instead use `#[{}(name)]`",
289                            kind.as_str(),
290                            kind.as_str()
291                        ),
292                    });
293                }
294                AttrKind::Group | AttrKind::Arg | AttrKind::Clap | AttrKind::StructOpt => {}
295            }
296            self.name = Name::Assigned(quote!(#arg));
297        } else if name == "name" {
298            match kind {
299                AttrKind::Arg => {
300                    self.deprecations.push(Deprecation {
301                        span: name.span(),
302                        id: "id_is_only_for_arg",
303                        version: "4.0.0",
304                        description: format!(
305                            "`#[{}(name)] was allowed by mistake, instead use `#[{}(id)]` or `#[{}(value_name)]`",
306                            kind.as_str(),
307                            kind.as_str(),
308                            kind.as_str()
309                        ),
310                    });
311                }
312                AttrKind::Group
313                | AttrKind::Command
314                | AttrKind::Value
315                | AttrKind::Clap
316                | AttrKind::StructOpt => {}
317            }
318            self.name = Name::Assigned(quote!(#arg));
319        } else if name == "value_parser" {
320            self.value_parser = Some(ValueParser::Explicit(Method::new(name, quote!(#arg))));
321        } else if name == "action" {
322            self.action = Some(Action::Explicit(Method::new(name, quote!(#arg))));
323        } else {
324            if name == "short" || name == "long" {
325                self.is_positional = false;
326            }
327            self.methods.push(Method::new(name, quote!(#arg)));
328        }
329    }
330
331    fn infer_kind(&mut self, attrs: &[ClapAttr]) -> Result<(), syn::Error> {
332        for attr in attrs {
333            if let Some(AttrValue::Call(_)) = &attr.value {
334                continue;
335            }
336
337            let actual_attr_kind = *attr.kind.get();
338            let kind = match &attr.magic {
339                Some(MagicAttrName::FromGlobal) => {
340                    if attr.value.is_some() {
341                        let expr = attr.value_or_abort()?;
342                        abort!(expr, "attribute `{}` does not accept a value", attr.name);
343                    }
344                    let ty = self
345                        .kind()
346                        .ty()
347                        .cloned()
348                        .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
349                    let kind = Sp::new(Kind::FromGlobal(ty), attr.name.clone().span());
350                    Some(kind)
351                }
352                Some(MagicAttrName::Subcommand) if attr.value.is_none() => {
353                    if attr.value.is_some() {
354                        let expr = attr.value_or_abort()?;
355                        abort!(expr, "attribute `{}` does not accept a value", attr.name);
356                    }
357                    let ty = self
358                        .kind()
359                        .ty()
360                        .cloned()
361                        .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
362                    let kind = Sp::new(Kind::Subcommand(ty), attr.name.clone().span());
363                    Some(kind)
364                }
365                Some(MagicAttrName::ExternalSubcommand) if attr.value.is_none() => {
366                    if attr.value.is_some() {
367                        let expr = attr.value_or_abort()?;
368                        abort!(expr, "attribute `{}` does not accept a value", attr.name);
369                    }
370                    let kind = Sp::new(Kind::ExternalSubcommand, attr.name.clone().span());
371                    Some(kind)
372                }
373                Some(MagicAttrName::Flatten) if attr.value.is_none() => {
374                    if attr.value.is_some() {
375                        let expr = attr.value_or_abort()?;
376                        abort!(expr, "attribute `{}` does not accept a value", attr.name);
377                    }
378                    let ty = self
379                        .kind()
380                        .ty()
381                        .cloned()
382                        .unwrap_or_else(|| Sp::new(Ty::Other, self.kind.span()));
383                    let kind = Sp::new(Kind::Flatten(ty), attr.name.clone().span());
384                    Some(kind)
385                }
386                Some(MagicAttrName::Skip) if actual_attr_kind != AttrKind::Group => {
387                    let expr = attr.value.clone();
388                    let kind = Sp::new(
389                        Kind::Skip(expr, self.kind.attr_kind()),
390                        attr.name.clone().span(),
391                    );
392                    Some(kind)
393                }
394                _ => None,
395            };
396
397            if let Some(kind) = kind {
398                self.set_kind(kind)?;
399            }
400        }
401
402        Ok(())
403    }
404
405    fn push_attrs(&mut self, attrs: &[ClapAttr]) -> Result<(), syn::Error> {
406        for attr in attrs {
407            let actual_attr_kind = *attr.kind.get();
408            let expected_attr_kind = self.kind.attr_kind();
409            match (actual_attr_kind, expected_attr_kind) {
410                (AttrKind::Clap, _) | (AttrKind::StructOpt, _) => {
411                    self.deprecations.push(Deprecation::attribute(
412                        "4.0.0",
413                        actual_attr_kind,
414                        expected_attr_kind,
415                        attr.kind.span(),
416                    ));
417                }
418
419                (AttrKind::Group, AttrKind::Command) => {}
420
421                _ if attr.kind != expected_attr_kind => {
422                    abort!(
423                        attr.kind.span(),
424                        "Expected `{}` attribute instead of `{}`",
425                        expected_attr_kind.as_str(),
426                        actual_attr_kind.as_str()
427                    );
428                }
429
430                _ => {}
431            }
432
433            if let Some(AttrValue::Call(tokens)) = &attr.value {
434                // Force raw mode with method call syntax
435                self.push_method(*attr.kind.get(), attr.name.clone(), quote!(#(#tokens),*));
436                continue;
437            }
438
439            match &attr.magic {
440                Some(MagicAttrName::Short) if attr.value.is_none() => {
441                    assert_attr_kind(attr, &[AttrKind::Arg])?;
442
443                    self.push_method(
444                        *attr.kind.get(),
445                        attr.name.clone(),
446                        self.name.clone().translate_char(*self.casing),
447                    );
448                }
449
450                Some(MagicAttrName::Long) if attr.value.is_none() => {
451                    assert_attr_kind(attr, &[AttrKind::Arg])?;
452
453                    self.push_method(*attr.kind.get(), attr.name.clone(), self.name.clone().translate(*self.casing));
454                }
455
456                Some(MagicAttrName::ValueParser) if attr.value.is_none() => {
457                    assert_attr_kind(attr, &[AttrKind::Arg])?;
458
459                    self.deprecations.push(Deprecation {
460                        span: attr.name.span(),
461                        id: "bare_value_parser",
462                        version: "4.0.0",
463                        description: "`#[arg(value_parser)]` is now the default and is no longer needed`".to_owned(),
464                    });
465                    self.value_parser = Some(ValueParser::Implicit(attr.name.clone()));
466                }
467
468                Some(MagicAttrName::Action) if attr.value.is_none() => {
469                    assert_attr_kind(attr, &[AttrKind::Arg])?;
470
471                    self.deprecations.push(Deprecation {
472                        span: attr.name.span(),
473                        id: "bare_action",
474                        version: "4.0.0",
475                        description: "`#[arg(action)]` is now the default and is no longer needed`".to_owned(),
476                    });
477                    self.action = Some(Action::Implicit(attr.name.clone()));
478                }
479
480                Some(MagicAttrName::Env) if attr.value.is_none() => {
481                    assert_attr_kind(attr, &[AttrKind::Arg])?;
482
483                    self.push_method(
484                        *attr.kind.get(),
485                        attr.name.clone(),
486                        self.name.clone().translate(*self.env_casing),
487                    );
488                }
489
490                Some(MagicAttrName::ValueEnum) if attr.value.is_none() => {
491                    assert_attr_kind(attr, &[AttrKind::Arg])?;
492
493                    self.is_enum = true
494                }
495
496                Some(MagicAttrName::VerbatimDocComment) if attr.value.is_none() => {
497                    self.verbatim_doc_comment = true
498                }
499
500                Some(MagicAttrName::About) if attr.value.is_none() => {
501                    assert_attr_kind(attr, &[AttrKind::Command])?;
502
503                    if let Some(method) =
504                        Method::from_env(attr.name.clone(), "CARGO_PKG_DESCRIPTION")?
505                    {
506                        self.methods.push(method);
507                    }
508                }
509
510                Some(MagicAttrName::LongAbout) if attr.value.is_none() => {
511                    assert_attr_kind(attr, &[AttrKind::Command])?;
512
513                    self.force_long_help = true;
514                }
515
516                Some(MagicAttrName::LongHelp) if attr.value.is_none() => {
517                    assert_attr_kind(attr, &[AttrKind::Arg])?;
518
519                    self.force_long_help = true;
520                }
521
522                Some(MagicAttrName::Author) if attr.value.is_none() => {
523                    assert_attr_kind(attr, &[AttrKind::Command])?;
524
525                    if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_AUTHORS")? {
526                        self.methods.push(method);
527                    }
528                }
529
530                Some(MagicAttrName::Version) if attr.value.is_none() => {
531                    assert_attr_kind(attr, &[AttrKind::Command])?;
532
533                    if let Some(method) = Method::from_env(attr.name.clone(), "CARGO_PKG_VERSION")? {
534                        self.methods.push(method);
535                    }
536                }
537
538                Some(MagicAttrName::DefaultValueT) => {
539                    assert_attr_kind(attr, &[AttrKind::Arg])?;
540
541                    let ty = if let Some(ty) = self.ty.as_ref() {
542                        ty
543                    } else {
544                        abort!(
545                            attr.name.clone(),
546                            "#[arg(default_value_t)] (without an argument) can be used \
547                            only on field level\n\n= note: {note}\n\n",
548
549                            note = "see \
550                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
551                    };
552
553                    let val = if let Some(expr) = &attr.value {
554                        quote!(#expr)
555                    } else {
556                        quote!(<#ty as ::std::default::Default>::default())
557                    };
558
559                    let val = if attrs
560                        .iter()
561                        .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
562                    {
563                        quote_spanned!(attr.name.clone().span()=> {
564                            static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<String> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
565                                let val: #ty = #val;
566                                clap::ValueEnum::to_possible_value(&val).unwrap().get_name().to_owned()
567                            });
568                            let s: &'static str = &*DEFAULT_VALUE;
569                            s
570                        })
571                    } else {
572                        quote_spanned!(attr.name.clone().span()=> {
573                            static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<String> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
574                                let val: #ty = #val;
575                                ::std::string::ToString::to_string(&val)
576                            });
577                            let s: &'static str = &*DEFAULT_VALUE;
578                            s
579                        })
580                    };
581
582                    let raw_ident = Ident::new("default_value", attr.name.clone().span());
583                    self.methods.push(Method::new(raw_ident, val));
584                }
585
586                Some(MagicAttrName::DefaultValuesT) => {
587                    assert_attr_kind(attr, &[AttrKind::Arg])?;
588
589                    let ty = if let Some(ty) = self.ty.as_ref() {
590                        ty
591                    } else {
592                        abort!(
593                            attr.name.clone(),
594                            "#[arg(default_values_t)] (without an argument) can be used \
595                            only on field level\n\n= note: {note}\n\n",
596
597                            note = "see \
598                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
599                    };
600                    let expr = attr.value_or_abort()?;
601
602                    let container_type = Ty::from_syn_ty(ty);
603                    if *container_type != Ty::Vec {
604                        abort!(
605                            attr.name.clone(),
606                            "#[arg(default_values_t)] can be used only on Vec types\n\n= note: {note}\n\n",
607
608                            note = "see \
609                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
610                    }
611                    let inner_type = inner_type(ty);
612
613                    // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and
614                    // `Vec<#inner_type>`.
615                    let val = if attrs
616                        .iter()
617                        .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
618                    {
619                        quote_spanned!(attr.name.clone().span()=> {
620                            {
621                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=String>
622                                where
623                                    T: ::std::borrow::Borrow<#inner_type>
624                                {
625                                    iterable
626                                        .into_iter()
627                                        .map(|val| {
628                                            clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name().to_owned()
629                                        })
630                                }
631
632                                static DEFAULT_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::string::String>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
633                                    iter_to_vals(#expr).collect()
634                                });
635
636                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&str>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
637                                    DEFAULT_STRINGS.iter().map(::std::string::String::as_str).collect()
638                                });
639                                DEFAULT_VALUES.iter().copied()
640                            }
641                        })
642                    } else {
643                        quote_spanned!(attr.name.clone().span()=> {
644                            {
645                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=String>
646                                where
647                                    T: ::std::borrow::Borrow<#inner_type>
648                                {
649                                    iterable.into_iter().map(|val| val.borrow().to_string())
650                                }
651
652                                static DEFAULT_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::string::String>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
653                                    iter_to_vals(#expr).collect()
654                                });
655
656                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&str>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
657                                    DEFAULT_STRINGS.iter().map(::std::string::String::as_str).collect()
658                                });
659                                DEFAULT_VALUES.iter().copied()
660                            }
661                        })
662                    };
663
664                    self.methods.push(Method::new(
665                        Ident::new("default_values", attr.name.clone().span()),
666                        val,
667                    ));
668                }
669
670                Some(MagicAttrName::DefaultValueOsT) => {
671                    assert_attr_kind(attr, &[AttrKind::Arg])?;
672
673                    let ty = if let Some(ty) = self.ty.as_ref() {
674                        ty
675                    } else {
676                        abort!(
677                            attr.name.clone(),
678                            "#[arg(default_value_os_t)] (without an argument) can be used \
679                            only on field level\n\n= note: {note}\n\n",
680
681                            note = "see \
682                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
683                    };
684
685                    let val = if let Some(expr) = &attr.value {
686                        quote!(#expr)
687                    } else {
688                        quote!(<#ty as ::std::default::Default>::default())
689                    };
690
691                    let val = if attrs
692                        .iter()
693                        .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
694                    {
695                        quote_spanned!(attr.name.clone().span()=> {
696                            static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<::std::ffi::OsString> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
697                                let val: #ty = #val;
698                                clap::ValueEnum::to_possible_value(&val).unwrap().get_name().to_owned()
699                            });
700                            let s: &'static ::std::ffi::OsStr = &*DEFAULT_VALUE;
701                            s
702                        })
703                    } else {
704                        quote_spanned!(attr.name.clone().span()=> {
705                            static DEFAULT_VALUE: clap::__macro_refs::once_cell::sync::Lazy<::std::ffi::OsString> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
706                                let val: #ty = #val;
707                                ::std::ffi::OsString::from(val)
708                            });
709                            let s: &'static ::std::ffi::OsStr = &*DEFAULT_VALUE;
710                            s
711                        })
712                    };
713
714                    let raw_ident = Ident::new("default_value", attr.name.clone().span());
715                    self.methods.push(Method::new(raw_ident, val));
716                }
717
718                Some(MagicAttrName::DefaultValuesOsT) => {
719                    assert_attr_kind(attr, &[AttrKind::Arg])?;
720
721                    let ty = if let Some(ty) = self.ty.as_ref() {
722                        ty
723                    } else {
724                        abort!(
725                            attr.name.clone(),
726                            "#[arg(default_values_os_t)] (without an argument) can be used \
727                            only on field level\n\n= note: {note}\n\n",
728
729                            note = "see \
730                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
731                    };
732                    let expr = attr.value_or_abort()?;
733
734                    let container_type = Ty::from_syn_ty(ty);
735                    if *container_type != Ty::Vec {
736                        abort!(
737                            attr.name.clone(),
738                            "#[arg(default_values_os_t)] can be used only on Vec types\n\n= note: {note}\n\n",
739
740                            note = "see \
741                                https://github.com/clap-rs/clap/blob/master/examples/derive_ref/README.md#magic-attributes")
742                    }
743                    let inner_type = inner_type(ty);
744
745                    // Use `Borrow<#inner_type>` so we accept `&Vec<#inner_type>` and
746                    // `Vec<#inner_type>`.
747                    let val = if attrs
748                        .iter()
749                        .any(|a| a.magic == Some(MagicAttrName::ValueEnum))
750                    {
751                        quote_spanned!(attr.name.clone().span()=> {
752                            {
753                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=::std::ffi::OsString>
754                                where
755                                    T: ::std::borrow::Borrow<#inner_type>
756                                {
757                                    iterable
758                                        .into_iter()
759                                        .map(|val| {
760                                            clap::ValueEnum::to_possible_value(val.borrow()).unwrap().get_name().to_owned().into()
761                                        })
762                                }
763
764                                static DEFAULT_OS_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::ffi::OsString>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
765                                    iter_to_vals(#expr).collect()
766                                });
767
768                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&::std::ffi::OsStr>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
769                                    DEFAULT_OS_STRINGS.iter().map(::std::ffi::OsString::as_os_str).collect()
770                                });
771                                DEFAULT_VALUES.iter().copied()
772                            }
773                        })
774                    } else {
775                        quote_spanned!(attr.name.clone().span()=> {
776                            {
777                                fn iter_to_vals<T>(iterable: impl IntoIterator<Item = T>) -> impl Iterator<Item=::std::ffi::OsString>
778                                where
779                                    T: ::std::borrow::Borrow<#inner_type>
780                                {
781                                    iterable.into_iter().map(|val| val.borrow().into())
782                                }
783
784                                static DEFAULT_OS_STRINGS: clap::__macro_refs::once_cell::sync::Lazy<Vec<::std::ffi::OsString>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
785                                    iter_to_vals(#expr).collect()
786                                });
787
788                                static DEFAULT_VALUES: clap::__macro_refs::once_cell::sync::Lazy<Vec<&::std::ffi::OsStr>> = clap::__macro_refs::once_cell::sync::Lazy::new(|| {
789                                    DEFAULT_OS_STRINGS.iter().map(::std::ffi::OsString::as_os_str).collect()
790                                });
791                                DEFAULT_VALUES.iter().copied()
792                            }
793                        })
794                    };
795
796                    self.methods.push(Method::new(
797                        Ident::new("default_values", attr.name.clone().span()),
798                        val,
799                    ));
800                }
801
802                Some(MagicAttrName::NextDisplayOrder) => {
803                    assert_attr_kind(attr, &[AttrKind::Command])?;
804
805                    let expr = attr.value_or_abort()?;
806                    self.next_display_order = Some(Method::new(attr.name.clone(), quote!(#expr)));
807                }
808
809                Some(MagicAttrName::NextHelpHeading) => {
810                    assert_attr_kind(attr, &[AttrKind::Command])?;
811
812                    let expr = attr.value_or_abort()?;
813                    self.next_help_heading = Some(Method::new(attr.name.clone(), quote!(#expr)));
814                }
815
816                Some(MagicAttrName::RenameAll) => {
817                    let lit = attr.lit_str_or_abort()?;
818                    self.casing = CasingStyle::from_lit(lit)?;
819                }
820
821                Some(MagicAttrName::RenameAllEnv) => {
822                    assert_attr_kind(attr, &[AttrKind::Command, AttrKind::Arg])?;
823
824                    let lit = attr.lit_str_or_abort()?;
825                    self.env_casing = CasingStyle::from_lit(lit)?;
826                }
827
828                Some(MagicAttrName::Skip) if actual_attr_kind == AttrKind::Group => {
829                    self.skip_group = true;
830                }
831
832                None
833                // Magic only for the default, otherwise just forward to the builder
834                | Some(MagicAttrName::Short)
835                | Some(MagicAttrName::Long)
836                | Some(MagicAttrName::Env)
837                | Some(MagicAttrName::About)
838                | Some(MagicAttrName::LongAbout)
839                | Some(MagicAttrName::LongHelp)
840                | Some(MagicAttrName::Author)
841                | Some(MagicAttrName::Version)
842                 => {
843                    let expr = attr.value_or_abort()?;
844                    self.push_method(*attr.kind.get(), attr.name.clone(), expr);
845                }
846
847                // Magic only for the default, otherwise just forward to the builder
848                Some(MagicAttrName::ValueParser) | Some(MagicAttrName::Action) => {
849                    let expr = attr.value_or_abort()?;
850                    self.push_method(*attr.kind.get(), attr.name.clone(), expr);
851                }
852
853                // Directives that never receive a value
854                Some(MagicAttrName::ValueEnum)
855                | Some(MagicAttrName::VerbatimDocComment) => {
856                    let expr = attr.value_or_abort()?;
857                    abort!(expr, "attribute `{}` does not accept a value", attr.name);
858                }
859
860                // Kinds
861                Some(MagicAttrName::FromGlobal)
862                | Some(MagicAttrName::Subcommand)
863                | Some(MagicAttrName::ExternalSubcommand)
864                | Some(MagicAttrName::Flatten)
865                | Some(MagicAttrName::Skip) => {
866                }
867            }
868        }
869
870        if self.has_explicit_methods() {
871            if let Kind::Skip(_, attr) = &*self.kind {
872                abort!(
873                    self.methods[0].name.span(),
874                    "`{}` cannot be used with `#[{}(skip)]",
875                    self.methods[0].name,
876                    attr.as_str(),
877                );
878            }
879            if let Kind::FromGlobal(_) = &*self.kind {
880                abort!(
881                    self.methods[0].name.span(),
882                    "`{}` cannot be used with `#[arg(from_global)]",
883                    self.methods[0].name,
884                );
885            }
886        }
887
888        Ok(())
889    }
890
891    fn push_doc_comment(&mut self, attrs: &[Attribute], short_name: &str, long_name: Option<&str>) {
892        let lines = extract_doc_comment(attrs);
893
894        if !lines.is_empty() {
895            let (short_help, long_help) =
896                format_doc_comment(&lines, !self.verbatim_doc_comment, self.force_long_help);
897            let short_name = format_ident!("{}", short_name);
898            let short = Method::new(
899                short_name,
900                short_help
901                    .map(|h| quote!(#h))
902                    .unwrap_or_else(|| quote!(None)),
903            );
904            self.doc_comment.push(short);
905            if let Some(long_name) = long_name {
906                let long_name = format_ident!("{}", long_name);
907                let long = Method::new(
908                    long_name,
909                    long_help
910                        .map(|h| quote!(#h))
911                        .unwrap_or_else(|| quote!(None)),
912                );
913                self.doc_comment.push(long);
914            }
915        }
916    }
917
918    fn set_kind(&mut self, kind: Sp<Kind>) -> Result<(), syn::Error> {
919        match (self.kind.get(), kind.get()) {
920            (Kind::Arg(_), Kind::FromGlobal(_))
921            | (Kind::Arg(_), Kind::Subcommand(_))
922            | (Kind::Arg(_), Kind::Flatten(_))
923            | (Kind::Arg(_), Kind::Skip(_, _))
924            | (Kind::Command(_), Kind::Subcommand(_))
925            | (Kind::Command(_), Kind::Flatten(_))
926            | (Kind::Command(_), Kind::Skip(_, _))
927            | (Kind::Command(_), Kind::ExternalSubcommand)
928            | (Kind::Value, Kind::Skip(_, _)) => {
929                self.kind = kind;
930            }
931
932            (_, _) => {
933                let old = self.kind.name();
934                let new = kind.name();
935                abort!(kind.span(), "`{}` cannot be used with `{}`", new, old);
936            }
937        }
938        Ok(())
939    }
940
941    pub fn find_default_method(&self) -> Option<&Method> {
942        self.methods
943            .iter()
944            .find(|m| m.name == "default_value" || m.name == "default_value_os")
945    }
946
947    /// generate methods from attributes on top of struct or enum
948    pub fn initial_top_level_methods(&self) -> TokenStream {
949        let next_display_order = self.next_display_order.as_ref().into_iter();
950        let next_help_heading = self.next_help_heading.as_ref().into_iter();
951        quote!(
952            #(#next_display_order)*
953            #(#next_help_heading)*
954        )
955    }
956
957    pub fn final_top_level_methods(&self) -> TokenStream {
958        let methods = &self.methods;
959        let doc_comment = &self.doc_comment;
960
961        quote!( #(#doc_comment)* #(#methods)*)
962    }
963
964    /// generate methods on top of a field
965    pub fn field_methods(&self) -> proc_macro2::TokenStream {
966        let methods = &self.methods;
967        let doc_comment = &self.doc_comment;
968        quote!( #(#doc_comment)* #(#methods)* )
969    }
970
971    pub fn deprecations(&self) -> proc_macro2::TokenStream {
972        let deprecations = &self.deprecations;
973        quote!( #(#deprecations)* )
974    }
975
976    pub fn next_display_order(&self) -> TokenStream {
977        let next_display_order = self.next_display_order.as_ref().into_iter();
978        quote!( #(#next_display_order)* )
979    }
980
981    pub fn next_help_heading(&self) -> TokenStream {
982        let next_help_heading = self.next_help_heading.as_ref().into_iter();
983        quote!( #(#next_help_heading)* )
984    }
985
986    pub fn ident(&self) -> &Ident {
987        &self.ident
988    }
989
990    pub fn id(&self) -> TokenStream {
991        self.name.clone().raw()
992    }
993
994    pub fn cased_name(&self) -> TokenStream {
995        self.name.clone().translate(*self.casing)
996    }
997
998    pub fn value_name(&self) -> TokenStream {
999        self.name.clone().translate(CasingStyle::ScreamingSnake)
1000    }
1001
1002    pub fn value_parser(&self, field_type: &Type) -> Method {
1003        self.value_parser
1004            .clone()
1005            .map(|p| {
1006                let inner_type = inner_type(field_type);
1007                p.resolve(inner_type)
1008            })
1009            .unwrap_or_else(|| {
1010                let inner_type = inner_type(field_type);
1011                if let Some(action) = self.action.as_ref() {
1012                    let span = action.span();
1013                    default_value_parser(inner_type, span)
1014                } else {
1015                    let span = self
1016                        .action
1017                        .as_ref()
1018                        .map(|a| a.span())
1019                        .unwrap_or_else(|| self.kind.span());
1020                    default_value_parser(inner_type, span)
1021                }
1022            })
1023    }
1024
1025    pub fn action(&self, field_type: &Type) -> Method {
1026        self.action
1027            .clone()
1028            .map(|p| p.resolve(field_type))
1029            .unwrap_or_else(|| {
1030                if let Some(value_parser) = self.value_parser.as_ref() {
1031                    let span = value_parser.span();
1032                    default_action(field_type, span)
1033                } else {
1034                    let span = self
1035                        .value_parser
1036                        .as_ref()
1037                        .map(|a| a.span())
1038                        .unwrap_or_else(|| self.kind.span());
1039                    default_action(field_type, span)
1040                }
1041            })
1042    }
1043
1044    pub fn kind(&self) -> Sp<Kind> {
1045        self.kind.clone()
1046    }
1047
1048    pub fn is_positional(&self) -> bool {
1049        self.is_positional
1050    }
1051
1052    pub fn casing(&self) -> Sp<CasingStyle> {
1053        self.casing
1054    }
1055
1056    pub fn env_casing(&self) -> Sp<CasingStyle> {
1057        self.env_casing
1058    }
1059
1060    pub fn has_explicit_methods(&self) -> bool {
1061        self.methods
1062            .iter()
1063            .any(|m| m.name != "help" && m.name != "long_help")
1064    }
1065
1066    pub fn skip_group(&self) -> bool {
1067        self.skip_group
1068    }
1069}
1070
1071#[derive(Clone)]
1072enum ValueParser {
1073    Explicit(Method),
1074    Implicit(Ident),
1075}
1076
1077impl ValueParser {
1078    fn resolve(self, _inner_type: &Type) -> Method {
1079        match self {
1080            Self::Explicit(method) => method,
1081            Self::Implicit(ident) => default_value_parser(_inner_type, ident.span()),
1082        }
1083    }
1084
1085    fn span(&self) -> Span {
1086        match self {
1087            Self::Explicit(method) => method.name.span(),
1088            Self::Implicit(ident) => ident.span(),
1089        }
1090    }
1091}
1092
1093fn default_value_parser(inner_type: &Type, span: Span) -> Method {
1094    let func = Ident::new("value_parser", span);
1095    Method::new(
1096        func,
1097        quote_spanned! { span=>
1098            clap::value_parser!(#inner_type)
1099        },
1100    )
1101}
1102
1103#[derive(Clone)]
1104pub enum Action {
1105    Explicit(Method),
1106    Implicit(Ident),
1107}
1108
1109impl Action {
1110    pub fn resolve(self, _field_type: &Type) -> Method {
1111        match self {
1112            Self::Explicit(method) => method,
1113            Self::Implicit(ident) => default_action(_field_type, ident.span()),
1114        }
1115    }
1116
1117    pub fn span(&self) -> Span {
1118        match self {
1119            Self::Explicit(method) => method.name.span(),
1120            Self::Implicit(ident) => ident.span(),
1121        }
1122    }
1123}
1124
1125fn default_action(field_type: &Type, span: Span) -> Method {
1126    let ty = Ty::from_syn_ty(field_type);
1127    let args = match *ty {
1128        Ty::Vec | Ty::OptionVec | Ty::VecVec | Ty::OptionVecVec => {
1129            quote_spanned! { span=>
1130                clap::ArgAction::Append
1131            }
1132        }
1133        Ty::Option | Ty::OptionOption => {
1134            quote_spanned! { span=>
1135                clap::ArgAction::Set
1136            }
1137        }
1138        _ => {
1139            if is_simple_ty(field_type, "bool") {
1140                quote_spanned! { span=>
1141                    clap::ArgAction::SetTrue
1142                }
1143            } else {
1144                quote_spanned! { span=>
1145                    clap::ArgAction::Set
1146                }
1147            }
1148        }
1149    };
1150
1151    let func = Ident::new("action", span);
1152    Method::new(func, args)
1153}
1154
1155#[allow(clippy::large_enum_variant)]
1156#[derive(Clone)]
1157pub enum Kind {
1158    Arg(Sp<Ty>),
1159    Command(Sp<Ty>),
1160    Value,
1161    FromGlobal(Sp<Ty>),
1162    Subcommand(Sp<Ty>),
1163    Flatten(Sp<Ty>),
1164    Skip(Option<AttrValue>, AttrKind),
1165    ExternalSubcommand,
1166}
1167
1168impl Kind {
1169    pub fn name(&self) -> &'static str {
1170        match self {
1171            Self::Arg(_) => "arg",
1172            Self::Command(_) => "command",
1173            Self::Value => "value",
1174            Self::FromGlobal(_) => "from_global",
1175            Self::Subcommand(_) => "subcommand",
1176            Self::Flatten(_) => "flatten",
1177            Self::Skip(_, _) => "skip",
1178            Self::ExternalSubcommand => "external_subcommand",
1179        }
1180    }
1181
1182    pub fn attr_kind(&self) -> AttrKind {
1183        match self {
1184            Self::Arg(_) => AttrKind::Arg,
1185            Self::Command(_) => AttrKind::Command,
1186            Self::Value => AttrKind::Value,
1187            Self::FromGlobal(_) => AttrKind::Arg,
1188            Self::Subcommand(_) => AttrKind::Command,
1189            Self::Flatten(_) => AttrKind::Command,
1190            Self::Skip(_, kind) => *kind,
1191            Self::ExternalSubcommand => AttrKind::Command,
1192        }
1193    }
1194
1195    pub fn ty(&self) -> Option<&Sp<Ty>> {
1196        match self {
1197            Self::Arg(ty)
1198            | Self::Command(ty)
1199            | Self::Flatten(ty)
1200            | Self::FromGlobal(ty)
1201            | Self::Subcommand(ty) => Some(ty),
1202            Self::Value | Self::Skip(_, _) | Self::ExternalSubcommand => None,
1203        }
1204    }
1205}
1206
1207#[derive(Clone)]
1208pub struct Method {
1209    name: Ident,
1210    args: TokenStream,
1211}
1212
1213impl Method {
1214    pub fn new(name: Ident, args: TokenStream) -> Self {
1215        Method { name, args }
1216    }
1217
1218    fn from_env(ident: Ident, env_var: &str) -> Result<Option<Self>, syn::Error> {
1219        let mut lit = match env::var(env_var) {
1220            Ok(val) => {
1221                if val.is_empty() {
1222                    return Ok(None);
1223                }
1224                LitStr::new(&val, ident.span())
1225            }
1226            Err(_) => {
1227                abort!(
1228                    ident,
1229                    "cannot derive `{}` from Cargo.toml\n\n= note: {note}\n\n= help: {help}\n\n",
1230                    ident,
1231                    note = format_args!("`{}` environment variable is not set", env_var),
1232                    help = format_args!("use `{} = \"...\"` to set {} manually", ident, ident)
1233                );
1234            }
1235        };
1236
1237        if ident == "author" {
1238            let edited = process_author_str(&lit.value());
1239            lit = LitStr::new(&edited, lit.span());
1240        }
1241
1242        Ok(Some(Method::new(ident, quote!(#lit))))
1243    }
1244
1245    pub(crate) fn args(&self) -> &TokenStream {
1246        &self.args
1247    }
1248}
1249
1250impl ToTokens for Method {
1251    fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1252        let Method { ref name, ref args } = self;
1253
1254        let tokens = quote!( .#name(#args) );
1255
1256        tokens.to_tokens(ts);
1257    }
1258}
1259
1260#[derive(Clone)]
1261pub struct Deprecation {
1262    pub span: Span,
1263    pub id: &'static str,
1264    pub version: &'static str,
1265    pub description: String,
1266}
1267
1268impl Deprecation {
1269    fn attribute(version: &'static str, old: AttrKind, new: AttrKind, span: Span) -> Self {
1270        Self {
1271            span,
1272            id: "old_attribute",
1273            version,
1274            description: format!(
1275                "Attribute `#[{}(...)]` has been deprecated in favor of `#[{}(...)]`",
1276                old.as_str(),
1277                new.as_str()
1278            ),
1279        }
1280    }
1281}
1282
1283impl ToTokens for Deprecation {
1284    fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1285        let tokens = if cfg!(feature = "deprecated") {
1286            let Deprecation {
1287                span,
1288                id,
1289                version,
1290                description,
1291            } = self;
1292            let span = *span;
1293            let id = Ident::new(id, span);
1294
1295            quote_spanned!(span=> {
1296                #[deprecated(since = #version, note = #description)]
1297                fn #id() {}
1298                #id();
1299            })
1300        } else {
1301            quote!()
1302        };
1303
1304        tokens.to_tokens(ts);
1305    }
1306}
1307
1308fn assert_attr_kind(attr: &ClapAttr, possible_kind: &[AttrKind]) -> Result<(), syn::Error> {
1309    if *attr.kind.get() == AttrKind::Clap || *attr.kind.get() == AttrKind::StructOpt {
1310        // deprecated
1311    } else if !possible_kind.contains(attr.kind.get()) {
1312        let options = possible_kind
1313            .iter()
1314            .map(|k| format!("`#[{}({})]`", k.as_str(), attr.name))
1315            .collect::<Vec<_>>();
1316        abort!(
1317            attr.name,
1318            "Unknown `#[{}({})]` attribute ({} exists)",
1319            attr.kind.as_str(),
1320            attr.name,
1321            options.join(", ")
1322        );
1323    }
1324    Ok(())
1325}
1326
1327/// replace all `:` with `, ` when not inside the `<>`
1328///
1329/// `"author1:author2:author3" => "author1, author2, author3"`
1330/// `"author1 <http://website1.com>:author2" => "author1 <http://website1.com>, author2"
1331fn process_author_str(author: &str) -> String {
1332    let mut res = String::with_capacity(author.len());
1333    let mut inside_angle_braces = 0usize;
1334
1335    for ch in author.chars() {
1336        if inside_angle_braces > 0 && ch == '>' {
1337            inside_angle_braces -= 1;
1338            res.push(ch);
1339        } else if ch == '<' {
1340            inside_angle_braces += 1;
1341            res.push(ch);
1342        } else if inside_angle_braces == 0 && ch == ':' {
1343            res.push_str(", ");
1344        } else {
1345            res.push(ch);
1346        }
1347    }
1348
1349    res
1350}
1351
1352/// Defines the casing for the attributes long representation.
1353#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1354pub enum CasingStyle {
1355    /// Indicate word boundaries with uppercase letter, excluding the first word.
1356    Camel,
1357    /// Keep all letters lowercase and indicate word boundaries with hyphens.
1358    Kebab,
1359    /// Indicate word boundaries with uppercase letter, including the first word.
1360    Pascal,
1361    /// Keep all letters uppercase and indicate word boundaries with underscores.
1362    ScreamingSnake,
1363    /// Keep all letters lowercase and indicate word boundaries with underscores.
1364    Snake,
1365    /// Keep all letters lowercase and remove word boundaries.
1366    Lower,
1367    /// Keep all letters uppercase and remove word boundaries.
1368    Upper,
1369    /// Use the original attribute name defined in the code.
1370    Verbatim,
1371}
1372
1373impl CasingStyle {
1374    fn from_lit(name: &LitStr) -> Result<Sp<Self>, syn::Error> {
1375        use self::CasingStyle::*;
1376
1377        let normalized = name.value().to_upper_camel_case().to_lowercase();
1378        let cs = |kind| Sp::new(kind, name.span());
1379
1380        let s = match normalized.as_ref() {
1381            "camel" | "camelcase" => cs(Camel),
1382            "kebab" | "kebabcase" => cs(Kebab),
1383            "pascal" | "pascalcase" => cs(Pascal),
1384            "screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake),
1385            "snake" | "snakecase" => cs(Snake),
1386            "lower" | "lowercase" => cs(Lower),
1387            "upper" | "uppercase" => cs(Upper),
1388            "verbatim" | "verbatimcase" => cs(Verbatim),
1389            s => abort!(name, "unsupported casing: `{}`", s),
1390        };
1391        Ok(s)
1392    }
1393}
1394
1395#[derive(Clone)]
1396pub enum Name {
1397    Derived(Ident),
1398    Assigned(TokenStream),
1399}
1400
1401impl Name {
1402    pub fn raw(self) -> TokenStream {
1403        match self {
1404            Name::Assigned(tokens) => tokens,
1405            Name::Derived(ident) => {
1406                let s = ident.unraw().to_string();
1407                quote_spanned!(ident.span()=> #s)
1408            }
1409        }
1410    }
1411
1412    pub fn translate(self, style: CasingStyle) -> TokenStream {
1413        use CasingStyle::*;
1414
1415        match self {
1416            Name::Assigned(tokens) => tokens,
1417            Name::Derived(ident) => {
1418                let s = ident.unraw().to_string();
1419                let s = match style {
1420                    Pascal => s.to_upper_camel_case(),
1421                    Kebab => s.to_kebab_case(),
1422                    Camel => s.to_lower_camel_case(),
1423                    ScreamingSnake => s.to_shouty_snake_case(),
1424                    Snake => s.to_snake_case(),
1425                    Lower => s.to_snake_case().replace('_', ""),
1426                    Upper => s.to_shouty_snake_case().replace('_', ""),
1427                    Verbatim => s,
1428                };
1429                quote_spanned!(ident.span()=> #s)
1430            }
1431        }
1432    }
1433
1434    pub fn translate_char(self, style: CasingStyle) -> TokenStream {
1435        use CasingStyle::*;
1436
1437        match self {
1438            Name::Assigned(tokens) => quote!( (#tokens).chars().next().unwrap() ),
1439            Name::Derived(ident) => {
1440                let s = ident.unraw().to_string();
1441                let s = match style {
1442                    Pascal => s.to_upper_camel_case(),
1443                    Kebab => s.to_kebab_case(),
1444                    Camel => s.to_lower_camel_case(),
1445                    ScreamingSnake => s.to_shouty_snake_case(),
1446                    Snake => s.to_snake_case(),
1447                    Lower => s.to_snake_case(),
1448                    Upper => s.to_shouty_snake_case(),
1449                    Verbatim => s,
1450                };
1451
1452                let s = s.chars().next().unwrap();
1453                quote_spanned!(ident.span()=> #s)
1454            }
1455        }
1456    }
1457}
1458