Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.3.20 #440

Merged
merged 3 commits into from Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,8 @@
# v0.3.20 (2020-10-12)

* Fixed [a breakage](https://github.com/TeXitoi/structopt/issues/439)
when the struct is placed inside a `macro_rules!` macro.

# v0.3.19 (2020-10-08)

* Added [StructOpt::from_args_safe](https://docs.rs/structopt/0.3/structopt/trait.StructOpt.html#tymethod.from_args_safe) as a shortcut for `StructOpt::from_iter_safe(std::env::args_os())`.
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "structopt"
version = "0.3.19"
version = "0.3.20"
edition = "2018"
authors = ["Guillaume Pinot <texitoi@texitoi.eu>", "others"]
description = "Parse command line argument by defining a struct."
Expand Down Expand Up @@ -28,7 +28,7 @@ travis-ci = { repository = "TeXitoi/structopt" }

[dependencies]
clap = { version = "2.33", default-features = false }
structopt-derive = { path = "structopt-derive", version = "=0.4.12" }
structopt-derive = { path = "structopt-derive", version = "=0.4.13" }
lazy_static = "1.4.0"
paw_dep = { version = "1", optional = true, package = "paw" }

Expand Down
2 changes: 1 addition & 1 deletion structopt-derive/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "structopt-derive"
version = "0.4.12"
version = "0.4.13"
edition = "2018"
authors = ["Guillaume Pinot <texitoi@texitoi.eu>"]
description = "Parse command line argument by defining a struct, derive crate."
Expand Down
2 changes: 2 additions & 0 deletions structopt-derive/src/lib.rs
Expand Up @@ -11,6 +11,8 @@
//! for the usage of `#[derive(StructOpt)]`.

#![allow(clippy::large_enum_variant)]
// FIXME: remove when and if our MSRV hits 1.42
#![allow(clippy::match_like_matches_macro)]
#![forbid(unsafe_code)]

extern crate proc_macro;
Expand Down
21 changes: 21 additions & 0 deletions structopt-derive/src/ty.rs
Expand Up @@ -63,6 +63,8 @@ fn subty_if<F>(ty: &syn::Type, f: F) -> Option<&syn::Type>
where
F: FnOnce(&PathSegment) -> bool,
{
let ty = strip_group(ty);

only_last_segment(ty)
.filter(|segment| f(segment))
.and_then(|segment| {
Expand All @@ -85,6 +87,8 @@ pub fn subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type>
}

pub fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
let ty = strip_group(ty);

only_last_segment(ty)
.map(|segment| {
if let PathArguments::None = segment.arguments {
Expand All @@ -96,6 +100,23 @@ pub fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
.unwrap_or(false)
}

// If the struct is placed inside of a macro_rules! declaration,
// in some circumstances, the tokens inside will be enclosed
// in `proc_macro::Group` delimited by invisible `proc_macro::Delimiter::None`.
//
// In syn speak, this is encoded via `*::Group` variants. We don't really care about
// that, so let's just strip it.
//
// Details: https://doc.rust-lang.org/proc_macro/enum.Delimiter.html#variant.None
// See also: https://github.com/TeXitoi/structopt/issues/439
fn strip_group(mut ty: &syn::Type) -> &syn::Type {
while let Type::Group(group) = ty {
ty = &*group.elem;
}

ty
}

fn is_generic_ty(ty: &syn::Type, name: &str) -> bool {
subty_if_name(ty, name).is_some()
}
Expand Down
25 changes: 25 additions & 0 deletions tests/regressions.rs
@@ -0,0 +1,25 @@
use structopt::StructOpt;

mod utils;
use utils::*;

#[test]
fn invisible_group_issue_439() {
macro_rules! m {
($bool:ty) => {
#[derive(Debug, StructOpt)]
struct Opts {
#[structopt(long = "x")]
x: $bool,
}
};
}

m!(bool);

let help = get_long_help::<Opts>();

assert!(help.contains("--x"));
assert!(!help.contains("--x <x>"));
Opts::from_iter_safe(&["test", "--x"]).unwrap();
}