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

Further improve error messages #346

Merged
merged 2 commits into from
Feb 1, 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
2 changes: 1 addition & 1 deletion structopt-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ syn = { version = "1", default-features = false, features = ["derive", "parsing"
quote = "1"
proc-macro2 = "1"
heck = "0.3.0"
proc-macro-error = "0.4.3"
proc-macro-error = "0.4.7"

[features]
paw = []
Expand Down
32 changes: 16 additions & 16 deletions structopt-derive/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl Method {
None => match env::var(env_var) {
Ok(val) => LitStr::new(&val, ident.span()),
Err(_) => {
abort!(ident.span(),
abort!(ident,
"cannot derive `{}` from Cargo.toml", ident;
note = "`{}` environment variable is not set", env_var;
help = "use `{} = \"...\"` to set {} manually", ident, ident;
Expand Down Expand Up @@ -145,7 +145,7 @@ impl Parser {
"try_from_os_str" => TryFromOsStr,
"from_occurrences" => FromOccurrences,
"from_flag" => FromFlag,
s => abort!(spec.kind.span(), "unsupported parser `{}`", s),
s => abort!(spec.kind, "unsupported parser `{}`", s),
};

let func = match spec.parse_func {
Expand All @@ -155,7 +155,7 @@ impl Parser {
}
TryFromStr => quote_spanned!(spec.kind.span()=> ::std::str::FromStr::from_str),
TryFromOsStr => abort!(
spec.kind.span(),
spec.kind,
"you must set parser for `try_from_os_str` explicitly"
),
FromOccurrences => quote_spanned!(spec.kind.span()=> { |v| v as _ }),
Expand All @@ -164,7 +164,7 @@ impl Parser {

Some(func) => match func {
syn::Expr::Path(_) => quote!(#func),
_ => abort!(func.span(), "`parse` argument must be a function path"),
_ => abort!(func, "`parse` argument must be a function path"),
},
};

Expand All @@ -188,7 +188,7 @@ impl CasingStyle {
"screamingsnake" | "screamingsnakecase" => cs(ScreamingSnake),
"snake" | "snakecase" => cs(Snake),
"verbatim" | "verbatimcase" => cs(Verbatim),
s => abort!(name.span(), "unsupported casing: `{}`", s),
s => abort!(name, "unsupported casing: `{}`", s),
}
}
}
Expand Down Expand Up @@ -303,7 +303,7 @@ impl Attrs {
ty
} else {
abort!(
ident.span(),
ident,
"#[structopt(default_value)] (without an argument) can be used \
only on field level";

Expand Down Expand Up @@ -420,7 +420,7 @@ impl Attrs {
let name = field.ident.clone().unwrap();
let mut res = Self::new(
field.span(),
Name::Derived(name.clone()),
Name::Derived(name),
parent_attrs,
Some(field.ty.clone()),
struct_casing,
Expand Down Expand Up @@ -465,13 +465,13 @@ impl Attrs {
match *ty {
Ty::OptionOption => {
abort!(
ty.span(),
field.ty,
"Option<Option<T>> type is not allowed for subcommand"
);
}
Ty::OptionVec => {
abort!(
ty.span(),
field.ty,
"Option<Vec<T>> type is not allowed for subcommand"
);
}
Expand Down Expand Up @@ -500,7 +500,7 @@ impl Attrs {
match *ty {
Ty::Bool => {
if res.is_positional() && !res.has_custom_parser {
abort!(ty.span(),
abort!(field.ty,
"`bool` cannot be used as positional parameter with default parser";
help = "if you want to create a flag add `long` or `short`";
help = "If you really want a boolean parameter \
Expand All @@ -509,32 +509,32 @@ impl Attrs {
)
}
if let Some(m) = res.find_method("default_value") {
abort!(m.name.span(), "default_value is meaningless for bool")
abort!(m.name, "default_value is meaningless for bool")
}
if let Some(m) = res.find_method("required") {
abort!(m.name.span(), "required is meaningless for bool")
abort!(m.name, "required is meaningless for bool")
}
}
Ty::Option => {
if let Some(m) = res.find_method("default_value") {
abort!(m.name.span(), "default_value is meaningless for Option")
abort!(m.name, "default_value is meaningless for Option")
}
if let Some(m) = res.find_method("required") {
abort!(m.name.span(), "required is meaningless for Option")
abort!(m.name, "required is meaningless for Option")
}
}
Ty::OptionOption => {
if res.is_positional() {
abort!(
ty.span(),
field.ty,
"Option<Option<T>> type is meaningless for positional argument"
)
}
}
Ty::OptionVec => {
if res.is_positional() {
abort!(
ty.span(),
field.ty,
"Option<Vec<T>> type is meaningless for positional argument"
)
}
Expand Down
2 changes: 1 addition & 1 deletion structopt-derive/src/doc_comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fn split_paragraphs(lines: &[&str]) -> Vec<String> {
let len = slice
.iter()
.position(|s| is_blank(s))
.unwrap_or(slice.len());
.unwrap_or_else(|| slice.len());

last_line += start + len;

Expand Down
12 changes: 6 additions & 6 deletions structopt-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ fn gen_augment_clap_enum(
}
},
_ => abort!(
variant.span(),
variant,
"`flatten` is usable only with single-typed tuple variants"
),
}
Expand Down Expand Up @@ -515,7 +515,7 @@ fn gen_augment_clap_enum(
}
}
}
Unnamed(..) => abort!(variant.span(), "non single-typed tuple enums are not supported"),
Unnamed(..) => abort!(variant, "non single-typed tuple enums are not supported"),
};

let name = attrs.cased_name();
Expand Down Expand Up @@ -590,7 +590,7 @@ fn gen_from_subcommand(
Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,

_ => abort!(
variant.span(),
variant,
"The enum variant marked with `external_attribute` must be \
a single-typed tuple, and the type must be either `Vec<String>` \
or `Vec<OsString>`."
Expand All @@ -615,7 +615,7 @@ fn gen_from_subcommand(
}

None => abort!(
ty.span(),
ty,
"The type must be either `Vec<String>` or `Vec<OsString>` \
to be used with `external_subcommand`."
),
Expand Down Expand Up @@ -670,7 +670,7 @@ fn gen_from_subcommand(
quote!( ( <#ty as ::structopt::StructOpt>::from_clap(matches) ) )
}
Unnamed(..) => abort!(
variant.ident.span(),
variant.ident,
"non single-typed tuple enums are not supported"
),
};
Expand All @@ -696,7 +696,7 @@ fn gen_from_subcommand(
}
}
_ => abort!(
variant.span(),
variant,
"`flatten` is usable only with single-typed tuple variants"
),
}
Expand Down
15 changes: 7 additions & 8 deletions structopt-derive/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use syn::{
self, parenthesized,
parse::{Parse, ParseBuffer, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
Attribute, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Token,
};

Expand Down Expand Up @@ -63,15 +62,15 @@ impl Parse for StructOptAttr {
let check_empty_lit = |s| {
if lit_str.is_empty() {
abort!(
lit.span(),
lit,
"`#[structopt({} = \"\")]` is deprecated in structopt 0.3, \
now it's default behavior",
s
);
}
};

match &*name_str.to_string() {
match &*name_str {
"rename_all" => Ok(RenameAll(name, lit)),
"rename_all_env" => Ok(RenameAllEnv(name, lit)),
"default_value" => Ok(DefaultValue(name, Some(lit))),
Expand Down Expand Up @@ -113,7 +112,7 @@ impl Parse for StructOptAttr {
}

Err(_) => abort! {
assign_token.span(),
assign_token,
"expected `string literal` or `expression` after `=`"
},
}
Expand All @@ -131,7 +130,7 @@ impl Parse for StructOptAttr {
if parser_specs.len() == 1 {
Ok(Parse(name, parser_specs[0].clone()))
} else {
abort!(name.span(), "parse must have exactly one argument")
abort!(name, "`parse` must have exactly one argument")
}
}

Expand All @@ -146,7 +145,7 @@ impl Parse for StructOptAttr {
}

Err(_) => {
abort!(name.span(),
abort!(name,
"`#[structopt(raw(...))` attributes are removed in structopt 0.3, \
they are replaced with raw methods";
help = "if you meant to call `clap::Arg::raw()` method \
Expand Down Expand Up @@ -181,13 +180,13 @@ impl Parse for StructOptAttr {
"skip" => Ok(Skip(name, None)),

"version" => abort!(
name.span(),
name,
"#[structopt(version)] is invalid attribute, \
structopt 0.3 inherits version from Cargo.toml by default, \
no attribute needed"
),

_ => abort!(name.span(), "unexpected attribute: {}", name_str),
_ => abort!(name, "unexpected attribute: {}", name_str),
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions tests/ui/enum_flatten.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
error: `flatten` is usable only with single-typed tuple variants
--> $DIR/enum_flatten.rs:14:5
|
14 | #[structopt(flatten)]
| ^
14 | / #[structopt(flatten)]
15 | | Variant1,
| |____________^
4 changes: 2 additions & 2 deletions tests/ui/external_subcommand_wrong_type.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ error[E0308]: mismatched types
13 | Other(Vec<CString>)
| ^^^^^^^ expected struct `std::ffi::CString`, found struct `std::ffi::OsString`
|
= note: expected type `std::vec::Vec<std::ffi::CString>`
found type `std::vec::Vec<std::ffi::OsString>`
= note: expected struct `std::vec::Vec<std::ffi::CString>`
found struct `std::vec::Vec<std::ffi::OsString>`
2 changes: 1 addition & 1 deletion tests/ui/opt_opt_nonpositional.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ error: Option<Option<T>> type is meaningless for positional argument
--> $DIR/opt_opt_nonpositional.rs:14:8
|
14 | n: Option<Option<u32>>,
| ^^^^^^
| ^^^^^^^^^^^^^^^^^^^
2 changes: 1 addition & 1 deletion tests/ui/opt_vec_nonpositional.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ error: Option<Vec<T>> type is meaningless for positional argument
--> $DIR/opt_vec_nonpositional.rs:14:8
|
14 | n: Option<Vec<u32>>,
| ^^^^^^
| ^^^^^^^^^^^^^^^^
2 changes: 1 addition & 1 deletion tests/ui/parse_not_zero_args.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: parse must have exactly one argument
error: `parse` must have exactly one argument
--> $DIR/parse_not_zero_args.rs:14:17
|
14 | #[structopt(parse(from_str, from_str))]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/structopt_empty_attr.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ error: expected attribute arguments in parentheses: #[structopt(...)]
--> $DIR/structopt_empty_attr.rs:14:5
|
14 | #[structopt]
| ^
| ^^^^^^^^^^^^
2 changes: 1 addition & 1 deletion tests/ui/subcommand_opt_opt.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ error: Option<Option<T>> type is not allowed for subcommand
--> $DIR/subcommand_opt_opt.rs:18:10
|
18 | cmd: Option<Option<Command>>,
| ^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^
2 changes: 1 addition & 1 deletion tests/ui/subcommand_opt_vec.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ error: Option<Vec<T>> type is not allowed for subcommand
--> $DIR/subcommand_opt_vec.rs:18:10
|
18 | cmd: Option<Vec<Command>>,
| ^^^^^^
| ^^^^^^^^^^^^^^^^^^^^