From c837b285525b869ffc3b05ba8f92d0679661bb93 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 29 Jun 2020 10:35:41 -0400 Subject: [PATCH] fix(clap_derive): Unwrap `syn::TypeGroup` when checking field types Due to macro expansions, a `syn` type may be wrapped in multiple 'layers' of `syn::Type::Group`. However, `clap_derive` currently does not check for `syn::Type::Group`, which will cause an `Option` (along with other matched types) to fail to be detected when it results from a macro expansion. This commit 'unwraps' outer type groups before checking the user-provided types against well-known types. Currently, these groups may not be present due to a rustc bug (rust-lang/rust#43081) However, once https://github.com/rust-lang/rust/pull/73084 is merged, these groups will be present in more cases. This commit makes `clap` compatible with both older and newer versions of rustc. --- clap_derive/src/utils/ty.rs | 5 ++++- clap_derive/tests/nested.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 clap_derive/tests/nested.rs diff --git a/clap_derive/src/utils/ty.rs b/clap_derive/src/utils/ty.rs index c2cec83fb56..e180758ea86 100644 --- a/clap_derive/src/utils/ty.rs +++ b/clap_derive/src/utils/ty.rs @@ -44,7 +44,10 @@ pub fn sub_type(ty: &syn::Type) -> Option<&syn::Type> { subty_if(ty, |_| true) } -fn only_last_segment(ty: &syn::Type) -> Option<&PathSegment> { +fn only_last_segment(mut ty: &syn::Type) -> Option<&PathSegment> { + while let syn::Type::Group(syn::TypeGroup { elem, .. }) = ty { + ty = elem; + } match ty { Type::Path(TypePath { qself: None, diff --git a/clap_derive/tests/nested.rs b/clap_derive/tests/nested.rs new file mode 100644 index 00000000000..1642aba04fa --- /dev/null +++ b/clap_derive/tests/nested.rs @@ -0,0 +1,33 @@ +// Copyright 2018 Guillaume Pinot (@TeXitoi) , +// Kevin Knapp (@kbknapp) , and +// Andrew Hobden (@hoverbear) +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// This work was derived from Structopt (https://github.com/TeXitoi/structopt) +// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the +// MIT/Apache 2.0 license. + +use clap::Clap; + +// Tests that clap_derive properly detects an `Option` field +// that results from a macro expansion +#[test] +fn use_option() { + macro_rules! expand_ty { + ($name:ident: $ty:ty) => { + #[derive(Clap)] + struct Outer { + #[clap(short, long)] + #[allow(dead_code)] + $name: $ty, + } + }; + } + + expand_ty!(my_field: Option); +}