1#![allow(clippy::large_enum_variant)]
14#![allow(clippy::match_like_matches_macro)]
16#![forbid(unsafe_code)]
17
18extern crate proc_macro;
19
20mod attrs;
21mod doc_comments;
22mod parse;
23mod spanned;
24mod ty;
25
26use crate::{
27 attrs::{Attrs, CasingStyle, Kind, Name, ParserKind},
28 spanned::Sp,
29 ty::{is_simple_ty, sub_type, subty_if_name, Ty},
30};
31
32use proc_macro2::{Span, TokenStream};
33use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy};
34use quote::{format_ident, quote, quote_spanned};
35use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *};
36
37const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
39
40const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
42
43struct GenOutput {
49 tokens: TokenStream,
50 attrs: Attrs,
51}
52
53#[proc_macro_derive(StructOpt, attributes(structopt))]
55#[proc_macro_error]
56pub fn structopt(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
57 let input: DeriveInput = syn::parse(input).unwrap();
58 let gen = impl_structopt(&input);
59 gen.into()
60}
61
62fn gen_augmentation(
65 fields: &Punctuated<Field, Comma>,
66 app_var: &Ident,
67 parent_attribute: &Attrs,
68) -> TokenStream {
69 let mut subcmds = fields.iter().filter_map(|field| {
70 let attrs = Attrs::from_field(
71 field,
72 Some(parent_attribute),
73 parent_attribute.casing(),
74 parent_attribute.env_casing(),
75 );
76 let kind = attrs.kind();
77 if let Kind::Subcommand(ty) = &*kind {
78 let subcmd_type = match (**ty, sub_type(&field.ty)) {
79 (Ty::Option, Some(sub_type)) => sub_type,
80 _ => &field.ty,
81 };
82 let required = if **ty == Ty::Option {
83 quote!()
84 } else {
85 quote_spanned! { kind.span()=>
86 let #app_var = #app_var.setting(
87 structopt::clap::AppSettings::SubcommandRequiredElseHelp
88 );
89 }
90 };
91
92 let span = field.span();
93 let ts = quote! {
94 let #app_var = <#subcmd_type as structopt::StructOptInternal>::augment_clap(
95 #app_var
96 );
97 #required
98 };
99 Some((span, ts))
100 } else {
101 None
102 }
103 });
104
105 let subcmd = subcmds.next().map(|(_, ts)| ts);
106 if let Some((span, _)) = subcmds.next() {
107 abort!(span, "multiple subcommand sets are not allowed, that's the second");
108 }
109
110 let args = fields.iter().filter_map(|field| {
111 let attrs = Attrs::from_field(
112 field,
113 Some(parent_attribute),
114 parent_attribute.casing(),
115 parent_attribute.env_casing(),
116 );
117 let kind = attrs.kind();
118 match &*kind {
119 Kind::ExternalSubcommand => {
120 abort!(kind.span(), "`external_subcommand` is only allowed on enum variants")
121 }
122 Kind::Subcommand(_) | Kind::Skip(_) => None,
123 Kind::Flatten => {
124 let ty = &field.ty;
125 Some(quote_spanned! { kind.span()=>
126 let #app_var = <#ty as structopt::StructOptInternal>::augment_clap(#app_var);
127 let #app_var = if <#ty as structopt::StructOptInternal>::is_subcommand() {
128 #app_var.setting(structopt::clap::AppSettings::SubcommandRequiredElseHelp)
129 } else {
130 #app_var
131 };
132 })
133 }
134 Kind::Arg(ty) => {
135 let convert_type = match **ty {
136 Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
137 Ty::OptionOption | Ty::OptionVec => {
138 sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
139 }
140 _ => &field.ty,
141 };
142
143 let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
144 let flag = *attrs.parser().kind == ParserKind::FromFlag;
145
146 let parser = attrs.parser();
147 let func = &parser.func;
148 let validator = match *parser.kind {
149 ParserKind::TryFromStr => quote_spanned! { func.span()=>
150 .validator(|s| {
151 #func(s.as_str())
152 .map(|_: #convert_type| ())
153 .map_err(|e| e.to_string())
154 })
155 },
156 ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
157 .validator_os(|s| #func(&s).map(|_: #convert_type| ()))
158 },
159 _ => quote!(),
160 };
161
162 let modifier = match **ty {
163 Ty::Bool => quote_spanned! { ty.span()=>
164 .takes_value(false)
165 .multiple(false)
166 },
167
168 Ty::Option => quote_spanned! { ty.span()=>
169 .takes_value(true)
170 .multiple(false)
171 #validator
172 },
173
174 Ty::OptionOption => quote_spanned! { ty.span()=>
175 .takes_value(true)
176 .multiple(false)
177 .min_values(0)
178 .max_values(1)
179 #validator
180 },
181
182 Ty::OptionVec => quote_spanned! { ty.span()=>
183 .takes_value(true)
184 .multiple(true)
185 .min_values(0)
186 #validator
187 },
188
189 Ty::Vec => quote_spanned! { ty.span()=>
190 .takes_value(true)
191 .multiple(true)
192 #validator
193 },
194
195 Ty::Other if occurrences => quote_spanned! { ty.span()=>
196 .takes_value(false)
197 .multiple(true)
198 },
199
200 Ty::Other if flag => quote_spanned! { ty.span()=>
201 .takes_value(false)
202 .multiple(false)
203 },
204
205 Ty::Other => {
206 let required = !attrs.has_method("default_value");
207 quote_spanned! { ty.span()=>
208 .takes_value(true)
209 .multiple(false)
210 .required(#required)
211 #validator
212 }
213 }
214 };
215
216 let name = attrs.cased_name();
217 let methods = attrs.field_methods();
218
219 Some(quote_spanned! { field.span()=>
220 let #app_var = #app_var.arg(
221 structopt::clap::Arg::with_name(#name)
222 #modifier
223 #methods
224 );
225 })
226 }
227 }
228 });
229
230 let app_methods = parent_attribute.top_level_methods();
231 let version = parent_attribute.version();
232 quote! {{
233 let #app_var = #app_var#app_methods;
234 #( #args )*
235 #subcmd
236 #app_var#version
237 }}
238}
239
240fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
241 let matches = format_ident!("matches");
250
251 let fields = fields.iter().map(|field| {
252 let attrs = Attrs::from_field(
253 field,
254 Some(parent_attribute),
255 parent_attribute.casing(),
256 parent_attribute.env_casing(),
257 );
258 let field_name = field.ident.as_ref().unwrap();
259 let kind = attrs.kind();
260 match &*kind {
261 Kind::ExternalSubcommand => {
262 abort!(kind.span(), "`external_subcommand` is allowed only on enum variants")
263 }
264
265 Kind::Subcommand(ty) => {
266 let subcmd_type = match (**ty, sub_type(&field.ty)) {
267 (Ty::Option, Some(sub_type)) => sub_type,
268 _ => &field.ty,
269 };
270 let unwrapper = match **ty {
271 Ty::Option => quote!(),
272 _ => quote_spanned!( ty.span()=> .unwrap() ),
273 };
274 quote_spanned! { kind.span()=>
275 #field_name: <#subcmd_type as structopt::StructOptInternal>::from_subcommand(
276 #matches.subcommand())
277 #unwrapper
278 }
279 }
280
281 Kind::Flatten => quote_spanned! { kind.span()=>
282 #field_name: structopt::StructOpt::from_clap(#matches)
283 },
284
285 Kind::Skip(val) => match val {
286 None => quote_spanned!(kind.span()=> #field_name: Default::default()),
287 Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
288 },
289
290 Kind::Arg(ty) => {
291 use crate::attrs::ParserKind::*;
292
293 let parser = attrs.parser();
294 let func = &parser.func;
295 let span = parser.kind.span();
296 let (value_of, values_of, parse) = match *parser.kind {
297 FromStr => {
298 (quote_spanned!(span=> value_of), quote_spanned!(span=> values_of), func.clone())
299 }
300 TryFromStr => (
301 quote_spanned!(span=> value_of),
302 quote_spanned!(span=> values_of),
303 quote_spanned!(func.span()=> |s| #func(s).unwrap()),
304 ),
305 FromOsStr => {
306 (quote_spanned!(span=> value_of_os), quote_spanned!(span=> values_of_os), func.clone())
307 }
308 TryFromOsStr => (
309 quote_spanned!(span=> value_of_os),
310 quote_spanned!(span=> values_of_os),
311 quote_spanned!(func.span()=> |s| #func(s).unwrap()),
312 ),
313 FromOccurrences => (quote_spanned!(span=> occurrences_of), quote!(), func.clone()),
314 FromFlag => (quote!(), quote!(), func.clone()),
315 };
316
317 let flag = *attrs.parser().kind == ParserKind::FromFlag;
318 let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
319 let name = attrs.cased_name();
320 let field_value = match **ty {
321 Ty::Bool => quote_spanned!(ty.span()=> #matches.is_present(#name)),
322
323 Ty::Option => quote_spanned! { ty.span()=>
324 #matches.#value_of(#name)
325 .map(#parse)
326 },
327
328 Ty::OptionOption => quote_spanned! { ty.span()=>
329 if #matches.is_present(#name) {
330 Some(#matches.#value_of(#name).map(#parse))
331 } else {
332 None
333 }
334 },
335
336 Ty::OptionVec => quote_spanned! { ty.span()=>
337 if #matches.is_present(#name) {
338 Some(#matches.#values_of(#name)
339 .map_or_else(Vec::new, |v| v.map(#parse).collect()))
340 } else {
341 None
342 }
343 },
344
345 Ty::Vec => quote_spanned! { ty.span()=>
346 #matches.#values_of(#name)
347 .map_or_else(Vec::new, |v| v.map(#parse).collect())
348 },
349
350 Ty::Other if occurrences => quote_spanned! { ty.span()=>
351 #parse(#matches.#value_of(#name))
352 },
353
354 Ty::Other if flag => quote_spanned! { ty.span()=>
355 #parse(#matches.is_present(#name))
356 },
357
358 Ty::Other => quote_spanned! { ty.span()=>
359 #matches.#value_of(#name)
360 .map(#parse)
361 .unwrap()
362 },
363 };
364
365 quote_spanned!(field.span()=> #field_name: #field_value )
366 }
367 }
368 });
369
370 quote! {{
371 #( #fields ),*
372 }}
373}
374
375fn gen_from_clap(
376 struct_name: &Ident,
377 fields: &Punctuated<Field, Comma>,
378 parent_attribute: &Attrs,
379) -> TokenStream {
380 let field_block = gen_constructor(fields, parent_attribute);
381
382 quote! {
383 fn from_clap(matches: &structopt::clap::ArgMatches) -> Self {
384 #struct_name #field_block
385 }
386 }
387}
388
389fn gen_clap(attrs: &[Attribute]) -> GenOutput {
390 let name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
391
392 let attrs = Attrs::from_struct(
393 Span::call_site(),
394 attrs,
395 Name::Assigned(quote!(#name)),
396 None,
397 Sp::call_site(DEFAULT_CASING),
398 Sp::call_site(DEFAULT_ENV_CASING),
399 );
400 let tokens = {
401 let name = attrs.cased_name();
402 quote!(structopt::clap::App::new(#name))
403 };
404
405 GenOutput { tokens, attrs }
406}
407
408fn gen_clap_struct(struct_attrs: &[Attribute]) -> GenOutput {
409 let initial_clap_app_gen = gen_clap(struct_attrs);
410 let clap_tokens = initial_clap_app_gen.tokens;
411
412 let augmented_tokens = quote! {
413 fn clap<'a, 'b>() -> structopt::clap::App<'a, 'b> {
414 let app = #clap_tokens;
415 <Self as structopt::StructOptInternal>::augment_clap(app)
416 }
417 };
418
419 GenOutput { tokens: augmented_tokens, attrs: initial_clap_app_gen.attrs }
420}
421
422fn gen_augment_clap(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
423 let app_var = Ident::new("app", Span::call_site());
424 let augmentation = gen_augmentation(fields, &app_var, parent_attribute);
425 quote! {
426 fn augment_clap<'a, 'b>(
427 #app_var: structopt::clap::App<'a, 'b>
428 ) -> structopt::clap::App<'a, 'b> {
429 #augmentation
430 }
431 }
432}
433
434fn gen_clap_enum(enum_attrs: &[Attribute]) -> GenOutput {
435 let initial_clap_app_gen = gen_clap(enum_attrs);
436 let clap_tokens = initial_clap_app_gen.tokens;
437
438 let tokens = quote! {
439 fn clap<'a, 'b>() -> structopt::clap::App<'a, 'b> {
440 let app = #clap_tokens
441 .setting(structopt::clap::AppSettings::SubcommandRequiredElseHelp);
442 <Self as structopt::StructOptInternal>::augment_clap(app)
443 }
444 };
445
446 GenOutput { tokens, attrs: initial_clap_app_gen.attrs }
447}
448
449fn gen_augment_clap_enum(
450 variants: &Punctuated<Variant, Comma>,
451 parent_attribute: &Attrs,
452) -> TokenStream {
453 use syn::Fields::*;
454
455 let subcommands = variants.iter().map(|variant| {
456 let attrs = Attrs::from_struct(
457 variant.span(),
458 &variant.attrs,
459 Name::Derived(variant.ident.clone()),
460 Some(parent_attribute),
461 parent_attribute.casing(),
462 parent_attribute.env_casing(),
463 );
464
465 let kind = attrs.kind();
466 match &*kind {
467 Kind::ExternalSubcommand => {
468 let app_var = Ident::new("app", Span::call_site());
469 quote_spanned! { attrs.kind().span()=>
470 let #app_var = #app_var.setting(
471 structopt::clap::AppSettings::AllowExternalSubcommands
472 );
473 }
474 }
475
476 Kind::Flatten => match variant.fields {
477 Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
478 let ty = &unnamed[0];
479 quote! {
480 let app = <#ty as structopt::StructOptInternal>::augment_clap(app);
481 }
482 }
483 _ => abort!(variant, "`flatten` is usable only with single-typed tuple variants"),
484 },
485
486 _ => {
487 let app_var = Ident::new("subcommand", Span::call_site());
488 let arg_block = match variant.fields {
489 Named(ref fields) => gen_augmentation(&fields.named, &app_var, &attrs),
490 Unit => quote!( #app_var ),
491 Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
492 let ty = &unnamed[0];
493 quote_spanned! { ty.span()=>
494 {
495 let #app_var = <#ty as structopt::StructOptInternal>::augment_clap(
496 #app_var
497 );
498 if <#ty as structopt::StructOptInternal>::is_subcommand() {
499 #app_var.setting(
500 structopt::clap::AppSettings::SubcommandRequiredElseHelp
501 )
502 } else {
503 #app_var
504 }
505 }
506 }
507 }
508 Unnamed(..) => abort!(variant, "non single-typed tuple enums are not supported"),
509 };
510
511 let name = attrs.cased_name();
512 let from_attrs = attrs.top_level_methods();
513 let version = attrs.version();
514 quote! {
515 let app = app.subcommand({
516 let #app_var = structopt::clap::SubCommand::with_name(#name);
517 let #app_var = #arg_block;
518 #app_var#from_attrs#version
519 });
520 }
521 }
522 }
523 });
524
525 let app_methods = parent_attribute.top_level_methods();
526 let version = parent_attribute.version();
527 quote! {
528 fn augment_clap<'a, 'b>(
529 app: structopt::clap::App<'a, 'b>
530 ) -> structopt::clap::App<'a, 'b> {
531 let app = app #app_methods;
532 #( #subcommands )*;
533 app #version
534 }
535 }
536}
537
538fn gen_from_clap_enum(name: &Ident) -> TokenStream {
539 quote! {
540 fn from_clap(matches: &structopt::clap::ArgMatches) -> Self {
541 <#name as structopt::StructOptInternal>::from_subcommand(matches.subcommand())
542 .expect("structopt misuse: You likely tried to #[flatten] a struct \
543 that contains #[subcommand]. This is forbidden.")
544 }
545 }
546}
547
548fn gen_from_subcommand(
549 name: &Ident,
550 variants: &Punctuated<Variant, Comma>,
551 parent_attribute: &Attrs,
552) -> TokenStream {
553 use syn::Fields::*;
554
555 let mut ext_subcmd = None;
556
557 let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
558 .iter()
559 .filter_map(|variant| {
560 let attrs = Attrs::from_struct(
561 variant.span(),
562 &variant.attrs,
563 Name::Derived(variant.ident.clone()),
564 Some(parent_attribute),
565 parent_attribute.casing(),
566 parent_attribute.env_casing(),
567 );
568
569 let variant_name = &variant.ident;
570
571 if let Kind::ExternalSubcommand = *attrs.kind() {
572 if ext_subcmd.is_some() {
573 abort!(
574 attrs.kind().span(),
575 "Only one variant can be marked with `external_subcommand`, \
576 this is the second"
577 );
578 }
579
580 let ty = match variant.fields {
581 Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,
582
583 _ => abort!(
584 variant,
585 "The enum variant marked with `external_attribute` must be \
586 a single-typed tuple, and the type must be either `Vec<String>` \
587 or `Vec<OsString>`."
588 ),
589 };
590
591 let (span, str_ty, values_of) = match subty_if_name(ty, "Vec") {
592 Some(subty) => {
593 if is_simple_ty(subty, "String") {
594 (subty.span(), quote!(::std::string::String), quote!(values_of))
595 } else {
596 (subty.span(), quote!(::std::ffi::OsString), quote!(values_of_os))
597 }
598 }
599
600 None => abort!(
601 ty,
602 "The type must be either `Vec<String>` or `Vec<OsString>` \
603 to be used with `external_subcommand`."
604 ),
605 };
606
607 ext_subcmd = Some((span, variant_name, str_ty, values_of));
608 None
609 } else {
610 Some((variant, attrs))
611 }
612 })
613 .partition(|(_, attrs)| match &*attrs.kind() {
614 Kind::Flatten => true,
615 _ => false,
616 });
617
618 let other = format_ident!("other");
619 let matches = format_ident!("matches");
620
621 let external = match ext_subcmd {
622 Some((span, var_name, str_ty, values_of)) => quote_spanned! { span=>
623 match #other {
624 ("", ::std::option::Option::None) => None,
625
626 (external, Some(#matches)) => {
627 ::std::option::Option::Some(#name::#var_name(
628 ::std::iter::once(#str_ty::from(external))
629 .chain(
630 #matches.#values_of("").into_iter().flatten().map(#str_ty::from)
631 )
632 .collect::<::std::vec::Vec<_>>()
633 ))
634 }
635
636 (external, None) => {
637 ::std::option::Option::Some(#name::#var_name(
638 ::std::iter::once(#str_ty::from(external))
639 .collect::<::std::vec::Vec<_>>()
640 ))
641 }
642 }
643 },
644
645 None => quote!(None),
646 };
647
648 let match_arms = variants.iter().map(|(variant, attrs)| {
649 let sub_name = attrs.cased_name();
650 let variant_name = &variant.ident;
651 let constructor_block = match variant.fields {
652 Named(ref fields) => gen_constructor(&fields.named, &attrs),
653 Unit => quote!(),
654 Unnamed(ref fields) if fields.unnamed.len() == 1 => {
655 let ty = &fields.unnamed[0];
656 quote!( ( <#ty as structopt::StructOpt>::from_clap(#matches) ) )
657 }
658 Unnamed(..) => abort!(variant.ident, "non single-typed tuple enums are not supported"),
659 };
660
661 quote! {
662 (#sub_name, Some(#matches)) => {
663 Some(#name :: #variant_name #constructor_block)
664 }
665 }
666 });
667
668 let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| {
669 let variant_name = &variant.ident;
670 match variant.fields {
671 Unnamed(ref fields) if fields.unnamed.len() == 1 => {
672 let ty = &fields.unnamed[0];
673 quote! {
674 if let Some(res) =
675 <#ty as structopt::StructOptInternal>::from_subcommand(#other)
676 {
677 return Some(#name :: #variant_name (res));
678 }
679 }
680 }
681 _ => abort!(variant, "`flatten` is usable only with single-typed tuple variants"),
682 }
683 });
684
685 quote! {
686 fn from_subcommand<'a, 'b>(
687 sub: (&'b str, Option<&'b structopt::clap::ArgMatches<'a>>)
688 ) -> Option<Self> {
689 match sub {
690 #( #match_arms, )*
691 #other => {
692 #( #child_subcommands )else*;
693 #external
694 }
695 }
696 }
697 }
698}
699
700#[cfg(feature = "paw")]
701fn gen_paw_impl(name: &Ident) -> TokenStream {
702 quote! {
703 impl structopt::paw::ParseArgs for #name {
704 type Error = std::io::Error;
705
706 fn parse_args() -> std::result::Result<Self, Self::Error> {
707 Ok(<#name as structopt::StructOpt>::from_args())
708 }
709 }
710 }
711}
712#[cfg(not(feature = "paw"))]
713fn gen_paw_impl(_: &Ident) -> TokenStream {
714 TokenStream::new()
715}
716
717fn impl_structopt_for_struct(
718 name: &Ident,
719 fields: &Punctuated<Field, Comma>,
720 attrs: &[Attribute],
721) -> TokenStream {
722 let basic_clap_app_gen = gen_clap_struct(attrs);
723 let augment_clap = gen_augment_clap(fields, &basic_clap_app_gen.attrs);
724 let from_clap = gen_from_clap(name, fields, &basic_clap_app_gen.attrs);
725 let paw_impl = gen_paw_impl(name);
726
727 let clap_tokens = basic_clap_app_gen.tokens;
728 quote! {
729 #[allow(unused_variables)]
730 #[allow(unknown_lints)]
731 #[allow(
732 clippy::style,
733 clippy::complexity,
734 clippy::pedantic,
735 clippy::restriction,
736 clippy::perf,
737 clippy::deprecated,
738 clippy::nursery,
739 clippy::cargo
740 )]
741 #[deny(clippy::correctness)]
742 #[allow(dead_code, unreachable_code)]
743 impl structopt::StructOpt for #name {
744 #clap_tokens
745 #from_clap
746 }
747
748 #[allow(unused_variables)]
749 #[allow(unknown_lints)]
750 #[allow(
751 clippy::style,
752 clippy::complexity,
753 clippy::pedantic,
754 clippy::restriction,
755 clippy::perf,
756 clippy::deprecated,
757 clippy::nursery,
758 clippy::cargo
759 )]
760 #[deny(clippy::correctness)]
761 #[allow(dead_code, unreachable_code)]
762 impl structopt::StructOptInternal for #name {
763 #augment_clap
764 fn is_subcommand() -> bool { false }
765 }
766
767 #paw_impl
768 }
769}
770
771fn impl_structopt_for_enum(
772 name: &Ident,
773 variants: &Punctuated<Variant, Comma>,
774 attrs: &[Attribute],
775) -> TokenStream {
776 let basic_clap_app_gen = gen_clap_enum(attrs);
777 let clap_tokens = basic_clap_app_gen.tokens;
778 let attrs = basic_clap_app_gen.attrs;
779
780 let augment_clap = gen_augment_clap_enum(variants, &attrs);
781 let from_clap = gen_from_clap_enum(name);
782 let from_subcommand = gen_from_subcommand(name, variants, &attrs);
783 let paw_impl = gen_paw_impl(name);
784
785 quote! {
786 #[allow(unknown_lints)]
787 #[allow(unused_variables, dead_code, unreachable_code)]
788 #[allow(
789 clippy::style,
790 clippy::complexity,
791 clippy::pedantic,
792 clippy::restriction,
793 clippy::perf,
794 clippy::deprecated,
795 clippy::nursery,
796 clippy::cargo
797 )]
798 #[deny(clippy::correctness)]
799 impl structopt::StructOpt for #name {
800 #clap_tokens
801 #from_clap
802 }
803
804 #[allow(unused_variables)]
805 #[allow(unknown_lints)]
806 #[allow(
807 clippy::style,
808 clippy::complexity,
809 clippy::pedantic,
810 clippy::restriction,
811 clippy::perf,
812 clippy::deprecated,
813 clippy::nursery,
814 clippy::cargo
815 )]
816 #[deny(clippy::correctness)]
817 #[allow(dead_code, unreachable_code)]
818 impl structopt::StructOptInternal for #name {
819 #augment_clap
820 #from_subcommand
821 fn is_subcommand() -> bool { true }
822 }
823
824 #paw_impl
825 }
826}
827
828fn impl_structopt(input: &DeriveInput) -> TokenStream {
829 use syn::Data::*;
830
831 let struct_name = &input.ident;
832
833 set_dummy(quote! {
834 impl structopt::StructOpt for #struct_name {
835 fn clap<'a, 'b>() -> structopt::clap::App<'a, 'b> {
836 unimplemented!()
837 }
838 fn from_clap(_matches: &structopt::clap::ArgMatches) -> Self {
839 unimplemented!()
840 }
841 }
842
843 impl structopt::StructOptInternal for #struct_name {}
844 });
845
846 match input.data {
847 Struct(DataStruct { fields: syn::Fields::Named(ref fields), .. }) => {
848 impl_structopt_for_struct(struct_name, &fields.named, &input.attrs)
849 }
850 Enum(ref e) => impl_structopt_for_enum(struct_name, &e.variants, &input.attrs),
851 _ => abort_call_site!("structopt only supports non-tuple structs and enums"),
852 }
853}