aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Maurer <mmaurer@google.com>2023-05-27 02:07:12 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-05-27 02:07:12 +0000
commit101a22614f9753e1ed4830669e6b91057729c015 (patch)
treeab7629d3a6476d778f218e5134befd902245d692
parentb21be4b193c9e05e24cd11dc86455ac4cb093895 (diff)
parent0768caef015cf0c518c895014c7cb02ea9bfa228 (diff)
downloadargh_derive-101a22614f9753e1ed4830669e6b91057729c015.tar.gz
Update to syn-2 am: f58c27309a am: 63b88a06da am: aa6a8cefab am: f00e21b0de am: 0768caef01
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/argh_derive/+/2520875 Change-Id: I9bc4d79452eb901617a108b301c65fe79043622c Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--Cargo.toml2
-rw-r--r--patches/syn-2.patch383
-rw-r--r--src/errors.rs59
-rw-r--r--src/parse_attrs.rs130
4 files changed, 461 insertions, 113 deletions
diff --git a/Cargo.toml b/Cargo.toml
index b7ddfba..fcd6837 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,4 +36,4 @@ version = "1.0"
version = "1.0"
[dependencies.syn]
-version = "1.0"
+version = "2.0.1"
diff --git a/patches/syn-2.patch b/patches/syn-2.patch
new file mode 100644
index 0000000..ffe0488
--- /dev/null
+++ b/patches/syn-2.patch
@@ -0,0 +1,383 @@
+diff --git a/src/errors.rs b/src/errors.rs
+index cfad383..fc5b584 100644
+--- a/src/errors.rs
++++ b/src/errors.rs
+@@ -14,15 +14,15 @@ pub struct Errors {
+ errors: RefCell<Vec<syn::Error>>,
+ }
+
+-/// Produce functions to expect particular variants of `syn::Lit`
++/// Produce functions to expect particular literals in `syn::Expr`
+ macro_rules! expect_lit_fn {
+ ($(($fn_name:ident, $syn_type:ident, $variant:ident, $lit_name:literal),)*) => {
+ $(
+- pub fn $fn_name<'a>(&self, lit: &'a syn::Lit) -> Option<&'a syn::$syn_type> {
+- if let syn::Lit::$variant(inner) = lit {
++ pub fn $fn_name<'a>(&self, e: &'a syn::Expr) -> Option<&'a syn::$syn_type> {
++ if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::$variant(inner), .. }) = e {
+ Some(inner)
+ } else {
+- self.unexpected_lit($lit_name, lit);
++ self.unexpected_lit($lit_name, e);
+ None
+ }
+ }
+@@ -65,28 +65,6 @@ impl Errors {
+ self.err_span(first, &["First ", attr_kind, " attribute here"].concat());
+ }
+
+- /// Error on literals, expecting attribute syntax.
+- pub fn expect_nested_meta<'a>(&self, nm: &'a syn::NestedMeta) -> Option<&'a syn::Meta> {
+- match nm {
+- syn::NestedMeta::Lit(l) => {
+- self.err(l, "Unexpected literal");
+- None
+- }
+- syn::NestedMeta::Meta(m) => Some(m),
+- }
+- }
+-
+- /// Error on attribute syntax, expecting literals
+- pub fn expect_nested_lit<'a>(&self, nm: &'a syn::NestedMeta) -> Option<&'a syn::Lit> {
+- match nm {
+- syn::NestedMeta::Meta(m) => {
+- self.err(m, "Expected literal");
+- None
+- }
+- syn::NestedMeta::Lit(l) => Some(l),
+- }
+- }
+-
+ expect_lit_fn![
+ (expect_lit_str, LitStr, Str, "string"),
+ (expect_lit_char, LitChar, Char, "character"),
+@@ -99,7 +77,7 @@ impl Errors {
+ (expect_meta_name_value, MetaNameValue, NameValue, "name-value pair"),
+ ];
+
+- fn unexpected_lit(&self, expected: &str, found: &syn::Lit) {
++ fn unexpected_lit(&self, expected: &str, found: &syn::Expr) {
+ fn lit_kind(lit: &syn::Lit) -> &'static str {
+ use syn::Lit::{Bool, Byte, ByteStr, Char, Float, Int, Str, Verbatim};
+ match lit {
+@@ -111,13 +89,21 @@ impl Errors {
+ Float(_) => "float",
+ Bool(_) => "boolean",
+ Verbatim(_) => "unknown (possibly extra-large integer)",
++ _ => "unknown literal kind",
+ }
+ }
+
+- self.err(
+- found,
+- &["Expected ", expected, " literal, found ", lit_kind(found), " literal"].concat(),
+- )
++ if let syn::Expr::Lit(syn::ExprLit { lit, .. }) = found {
++ self.err(
++ found,
++ &["Expected ", expected, " literal, found ", lit_kind(lit), " literal"].concat(),
++ )
++ } else {
++ self.err(
++ found,
++ &["Expected ", expected, " literal, found non-literal expression."].concat(),
++ )
++ }
+ }
+
+ fn unexpected_meta(&self, expected: &str, found: &syn::Meta) {
+@@ -155,6 +141,17 @@ impl Errors {
+ pub fn push(&self, err: syn::Error) {
+ self.errors.borrow_mut().push(err);
+ }
++
++ /// Convert a `syn::Result` to an `Option`, logging the error if present.
++ pub fn ok<T>(&self, r: syn::Result<T>) -> Option<T> {
++ match r {
++ Ok(v) => Some(v),
++ Err(e) => {
++ self.push(e);
++ None
++ }
++ }
++ }
+ }
+
+ impl ToTokens for Errors {
+diff --git a/src/parse_attrs.rs b/src/parse_attrs.rs
+index 04dcbdd..10ebcb5 100644
+--- a/src/parse_attrs.rs
++++ b/src/parse_attrs.rs
+@@ -76,49 +76,47 @@ impl FieldAttrs {
+ continue;
+ };
+
+- for meta in &ml.nested {
+- let meta = if let Some(m) = errors.expect_nested_meta(meta) { m } else { continue };
+-
++ for meta in ml {
+ let name = meta.path();
+ if name.is_ident("arg_name") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ this.parse_attr_arg_name(errors, m);
+ }
+ } else if name.is_ident("default") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ this.parse_attr_default(errors, m);
+ }
+ } else if name.is_ident("description") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ parse_attr_description(errors, m, &mut this.description);
+ }
+ } else if name.is_ident("from_str_fn") {
+- if let Some(m) = errors.expect_meta_list(meta) {
++ if let Some(m) = errors.expect_meta_list(&meta) {
+ this.parse_attr_from_str_fn(errors, m);
+ }
+ } else if name.is_ident("long") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ this.parse_attr_long(errors, m);
+ }
+ } else if name.is_ident("option") {
+- parse_attr_field_type(errors, meta, FieldKind::Option, &mut this.field_type);
++ parse_attr_field_type(errors, &meta, FieldKind::Option, &mut this.field_type);
+ } else if name.is_ident("short") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ this.parse_attr_short(errors, m);
+ }
+ } else if name.is_ident("subcommand") {
+ parse_attr_field_type(
+ errors,
+- meta,
++ &meta,
+ FieldKind::SubCommand,
+ &mut this.field_type,
+ );
+ } else if name.is_ident("switch") {
+- parse_attr_field_type(errors, meta, FieldKind::Switch, &mut this.field_type);
++ parse_attr_field_type(errors, &meta, FieldKind::Switch, &mut this.field_type);
+ } else if name.is_ident("positional") {
+ parse_attr_field_type(
+ errors,
+- meta,
++ &meta,
+ FieldKind::Positional,
+ &mut this.field_type,
+ );
+@@ -189,7 +187,7 @@ impl FieldAttrs {
+ fn parse_attr_short(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
+ if let Some(first) = &self.short {
+ errors.duplicate_attrs("short", first, m);
+- } else if let Some(lit_char) = errors.expect_lit_char(&m.lit) {
++ } else if let Some(lit_char) = errors.expect_lit_char(&m.value) {
+ self.short = Some(lit_char.clone());
+ if !lit_char.value().is_ascii() {
+ errors.err(lit_char, "Short names must be ASCII");
+@@ -217,16 +215,7 @@ fn parse_attr_fn_name(
+ errors.duplicate_attrs(attr_name, first, m);
+ }
+
+- if m.nested.len() != 1 {
+- errors.err(&m.nested, "Expected a single argument containing the function name");
+- return;
+- }
+-
+- // `unwrap` will not fail because of the call above
+- let nested = m.nested.first().unwrap();
+- if let Some(path) = errors.expect_nested_meta(nested).and_then(|m| errors.expect_meta_word(m)) {
+- *slot = path.get_ident().cloned();
+- }
++ *slot = errors.ok(m.parse_args());
+ }
+
+ fn parse_attr_field_type(
+@@ -246,7 +235,7 @@ fn parse_attr_field_type(
+
+ // Whether the attribute is one like `#[<name> ...]`
+ fn is_matching_attr(name: &str, attr: &syn::Attribute) -> bool {
+- attr.path.segments.len() == 1 && attr.path.segments[0].ident == name
++ attr.path().segments.len() == 1 && attr.path().segments[0].ident == name
+ }
+
+ /// Checks for `#[doc ...]`, which is generated by doc comments.
+@@ -259,34 +248,18 @@ fn is_argh_attr(attr: &syn::Attribute) -> bool {
+ is_matching_attr("argh", attr)
+ }
+
+-fn attr_to_meta_subtype<R: Clone>(
++/// Filters out non-`#[argh(...)]` attributes and converts to a sequence of `syn::Meta`.
++fn argh_attr_to_meta_list(
+ errors: &Errors,
+ attr: &syn::Attribute,
+- f: impl FnOnce(&syn::Meta) -> Option<&R>,
+-) -> Option<R> {
+- match attr.parse_meta() {
+- Ok(meta) => f(&meta).cloned(),
+- Err(e) => {
+- errors.push(e);
+- None
+- }
+- }
+-}
+-
+-fn attr_to_meta_list(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaList> {
+- attr_to_meta_subtype(errors, attr, |m| errors.expect_meta_list(m))
+-}
+-
+-fn attr_to_meta_name_value(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaNameValue> {
+- attr_to_meta_subtype(errors, attr, |m| errors.expect_meta_name_value(m))
+-}
+-
+-/// Filters out non-`#[argh(...)]` attributes and converts to `syn::MetaList`.
+-fn argh_attr_to_meta_list(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaList> {
++) -> Option<impl IntoIterator<Item = syn::Meta>> {
+ if !is_argh_attr(attr) {
+ return None;
+ }
+- attr_to_meta_list(errors, attr)
++ let ml = errors.expect_meta_list(&attr.meta)?;
++ errors.ok(ml.parse_args_with(
++ syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated,
++ ))
+ }
+
+ /// Represents a `#[derive(FromArgs)]` type's top-level attributes.
+@@ -317,32 +290,31 @@ impl TypeAttrs {
+ continue;
+ };
+
+- for meta in &ml.nested {
+- let meta = if let Some(m) = errors.expect_nested_meta(meta) { m } else { continue };
+-
++ for meta in ml {
+ let name = meta.path();
+ if name.is_ident("description") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ parse_attr_description(errors, m, &mut this.description);
+ }
+ } else if name.is_ident("error_code") {
+- if let Some(m) = errors.expect_meta_list(meta) {
++ if let Some(m) = errors.expect_meta_list(&meta) {
+ this.parse_attr_error_code(errors, m);
+ }
+ } else if name.is_ident("example") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ this.parse_attr_example(errors, m);
+ }
+ } else if name.is_ident("name") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ this.parse_attr_name(errors, m);
+ }
+ } else if name.is_ident("note") {
+- if let Some(m) = errors.expect_meta_name_value(meta) {
++ if let Some(m) = errors.expect_meta_name_value(&meta) {
+ this.parse_attr_note(errors, m);
+ }
+ } else if name.is_ident("subcommand") {
+- if let Some(ident) = errors.expect_meta_word(meta).and_then(|p| p.get_ident()) {
++ if let Some(ident) = errors.expect_meta_word(&meta).and_then(|p| p.get_ident())
++ {
+ this.parse_attr_subcommand(errors, ident);
+ }
+ } else {
+@@ -396,20 +368,17 @@ impl TypeAttrs {
+ }
+
+ fn parse_attr_error_code(&mut self, errors: &Errors, ml: &syn::MetaList) {
+- if ml.nested.len() != 2 {
+- errors.err(&ml, "Expected two arguments, an error number and a string description");
+- return;
+- }
+-
+- let err_code = &ml.nested[0];
+- let err_msg = &ml.nested[1];
+-
+- let err_code = errors.expect_nested_lit(err_code).and_then(|l| errors.expect_lit_int(l));
+- let err_msg = errors.expect_nested_lit(err_msg).and_then(|l| errors.expect_lit_str(l));
+-
+- if let (Some(err_code), Some(err_msg)) = (err_code, err_msg) {
+- self.error_codes.push((err_code.clone(), err_msg.clone()));
+- }
++ errors.ok(ml.parse_args_with(|input: syn::parse::ParseStream| {
++ let err_code = input.parse()?;
++ input.parse::<syn::Token![,]>()?;
++ let err_msg = input.parse()?;
++ if let (Some(err_code), Some(err_msg)) =
++ (errors.expect_lit_int(&err_code), errors.expect_lit_str(&err_msg))
++ {
++ self.error_codes.push((err_code.clone(), err_msg.clone()));
++ }
++ Ok(())
++ }));
+ }
+
+ fn parse_attr_example(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
+@@ -470,15 +439,13 @@ impl VariantAttrs {
+ continue;
+ };
+
+- for meta in &ml.nested {
+- let meta = if let Some(m) = errors.expect_nested_meta(meta) { m } else { continue };
+-
++ for meta in ml {
+ let name = meta.path();
+ if name.is_ident("dynamic") {
+ if let Some(prev) = this.is_dynamic.as_ref() {
+- errors.duplicate_attrs("dynamic", prev, meta);
++ errors.duplicate_attrs("dynamic", prev, &meta);
+ } else {
+- this.is_dynamic = errors.expect_meta_word(meta).cloned();
++ this.is_dynamic = errors.expect_meta_word(&meta).cloned();
+ }
+ } else {
+ errors.err(
+@@ -515,19 +482,19 @@ fn parse_attr_single_string(
+ ) {
+ if let Some(first) = slot {
+ errors.duplicate_attrs(name, first, m);
+- } else if let Some(lit_str) = errors.expect_lit_str(&m.lit) {
++ } else if let Some(lit_str) = errors.expect_lit_str(&m.value) {
+ *slot = Some(lit_str.clone());
+ }
+ }
+
+ fn parse_attr_multi_string(errors: &Errors, m: &syn::MetaNameValue, list: &mut Vec<syn::LitStr>) {
+- if let Some(lit_str) = errors.expect_lit_str(&m.lit) {
++ if let Some(lit_str) = errors.expect_lit_str(&m.value) {
+ list.push(lit_str.clone());
+ }
+ }
+
+ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Description>) {
+- let nv = if let Some(nv) = attr_to_meta_name_value(errors, attr) {
++ let nv = if let Some(nv) = errors.expect_meta_name_value(&attr.meta) {
+ nv
+ } else {
+ return;
+@@ -538,7 +505,7 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
+ return;
+ }
+
+- if let Some(lit_str) = errors.expect_lit_str(&nv.lit) {
++ if let Some(lit_str) = errors.expect_lit_str(&nv.value) {
+ let lit_str = if let Some(previous) = slot {
+ let previous = &previous.content;
+ let previous_span = previous.span();
+@@ -551,7 +518,8 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
+ }
+
+ fn parse_attr_description(errors: &Errors, m: &syn::MetaNameValue, slot: &mut Option<Description>) {
+- let lit_str = if let Some(lit_str) = errors.expect_lit_str(&m.lit) { lit_str } else { return };
++ let lit_str =
++ if let Some(lit_str) = errors.expect_lit_str(&m.value) { lit_str } else { return };
+
+ // Don't allow multiple explicit (non doc-comment) descriptions
+ if let Some(description) = slot {
diff --git a/src/errors.rs b/src/errors.rs
index cfad383..fc5b584 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -14,15 +14,15 @@ pub struct Errors {
errors: RefCell<Vec<syn::Error>>,
}
-/// Produce functions to expect particular variants of `syn::Lit`
+/// Produce functions to expect particular literals in `syn::Expr`
macro_rules! expect_lit_fn {
($(($fn_name:ident, $syn_type:ident, $variant:ident, $lit_name:literal),)*) => {
$(
- pub fn $fn_name<'a>(&self, lit: &'a syn::Lit) -> Option<&'a syn::$syn_type> {
- if let syn::Lit::$variant(inner) = lit {
+ pub fn $fn_name<'a>(&self, e: &'a syn::Expr) -> Option<&'a syn::$syn_type> {
+ if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::$variant(inner), .. }) = e {
Some(inner)
} else {
- self.unexpected_lit($lit_name, lit);
+ self.unexpected_lit($lit_name, e);
None
}
}
@@ -65,28 +65,6 @@ impl Errors {
self.err_span(first, &["First ", attr_kind, " attribute here"].concat());
}
- /// Error on literals, expecting attribute syntax.
- pub fn expect_nested_meta<'a>(&self, nm: &'a syn::NestedMeta) -> Option<&'a syn::Meta> {
- match nm {
- syn::NestedMeta::Lit(l) => {
- self.err(l, "Unexpected literal");
- None
- }
- syn::NestedMeta::Meta(m) => Some(m),
- }
- }
-
- /// Error on attribute syntax, expecting literals
- pub fn expect_nested_lit<'a>(&self, nm: &'a syn::NestedMeta) -> Option<&'a syn::Lit> {
- match nm {
- syn::NestedMeta::Meta(m) => {
- self.err(m, "Expected literal");
- None
- }
- syn::NestedMeta::Lit(l) => Some(l),
- }
- }
-
expect_lit_fn![
(expect_lit_str, LitStr, Str, "string"),
(expect_lit_char, LitChar, Char, "character"),
@@ -99,7 +77,7 @@ impl Errors {
(expect_meta_name_value, MetaNameValue, NameValue, "name-value pair"),
];
- fn unexpected_lit(&self, expected: &str, found: &syn::Lit) {
+ fn unexpected_lit(&self, expected: &str, found: &syn::Expr) {
fn lit_kind(lit: &syn::Lit) -> &'static str {
use syn::Lit::{Bool, Byte, ByteStr, Char, Float, Int, Str, Verbatim};
match lit {
@@ -111,13 +89,21 @@ impl Errors {
Float(_) => "float",
Bool(_) => "boolean",
Verbatim(_) => "unknown (possibly extra-large integer)",
+ _ => "unknown literal kind",
}
}
- self.err(
- found,
- &["Expected ", expected, " literal, found ", lit_kind(found), " literal"].concat(),
- )
+ if let syn::Expr::Lit(syn::ExprLit { lit, .. }) = found {
+ self.err(
+ found,
+ &["Expected ", expected, " literal, found ", lit_kind(lit), " literal"].concat(),
+ )
+ } else {
+ self.err(
+ found,
+ &["Expected ", expected, " literal, found non-literal expression."].concat(),
+ )
+ }
}
fn unexpected_meta(&self, expected: &str, found: &syn::Meta) {
@@ -155,6 +141,17 @@ impl Errors {
pub fn push(&self, err: syn::Error) {
self.errors.borrow_mut().push(err);
}
+
+ /// Convert a `syn::Result` to an `Option`, logging the error if present.
+ pub fn ok<T>(&self, r: syn::Result<T>) -> Option<T> {
+ match r {
+ Ok(v) => Some(v),
+ Err(e) => {
+ self.push(e);
+ None
+ }
+ }
+ }
}
impl ToTokens for Errors {
diff --git a/src/parse_attrs.rs b/src/parse_attrs.rs
index 04dcbdd..10ebcb5 100644
--- a/src/parse_attrs.rs
+++ b/src/parse_attrs.rs
@@ -76,49 +76,47 @@ impl FieldAttrs {
continue;
};
- for meta in &ml.nested {
- let meta = if let Some(m) = errors.expect_nested_meta(meta) { m } else { continue };
-
+ for meta in ml {
let name = meta.path();
if name.is_ident("arg_name") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_arg_name(errors, m);
}
} else if name.is_ident("default") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_default(errors, m);
}
} else if name.is_ident("description") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
parse_attr_description(errors, m, &mut this.description);
}
} else if name.is_ident("from_str_fn") {
- if let Some(m) = errors.expect_meta_list(meta) {
+ if let Some(m) = errors.expect_meta_list(&meta) {
this.parse_attr_from_str_fn(errors, m);
}
} else if name.is_ident("long") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_long(errors, m);
}
} else if name.is_ident("option") {
- parse_attr_field_type(errors, meta, FieldKind::Option, &mut this.field_type);
+ parse_attr_field_type(errors, &meta, FieldKind::Option, &mut this.field_type);
} else if name.is_ident("short") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_short(errors, m);
}
} else if name.is_ident("subcommand") {
parse_attr_field_type(
errors,
- meta,
+ &meta,
FieldKind::SubCommand,
&mut this.field_type,
);
} else if name.is_ident("switch") {
- parse_attr_field_type(errors, meta, FieldKind::Switch, &mut this.field_type);
+ parse_attr_field_type(errors, &meta, FieldKind::Switch, &mut this.field_type);
} else if name.is_ident("positional") {
parse_attr_field_type(
errors,
- meta,
+ &meta,
FieldKind::Positional,
&mut this.field_type,
);
@@ -189,7 +187,7 @@ impl FieldAttrs {
fn parse_attr_short(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
if let Some(first) = &self.short {
errors.duplicate_attrs("short", first, m);
- } else if let Some(lit_char) = errors.expect_lit_char(&m.lit) {
+ } else if let Some(lit_char) = errors.expect_lit_char(&m.value) {
self.short = Some(lit_char.clone());
if !lit_char.value().is_ascii() {
errors.err(lit_char, "Short names must be ASCII");
@@ -217,16 +215,7 @@ fn parse_attr_fn_name(
errors.duplicate_attrs(attr_name, first, m);
}
- if m.nested.len() != 1 {
- errors.err(&m.nested, "Expected a single argument containing the function name");
- return;
- }
-
- // `unwrap` will not fail because of the call above
- let nested = m.nested.first().unwrap();
- if let Some(path) = errors.expect_nested_meta(nested).and_then(|m| errors.expect_meta_word(m)) {
- *slot = path.get_ident().cloned();
- }
+ *slot = errors.ok(m.parse_args());
}
fn parse_attr_field_type(
@@ -246,7 +235,7 @@ fn parse_attr_field_type(
// Whether the attribute is one like `#[<name> ...]`
fn is_matching_attr(name: &str, attr: &syn::Attribute) -> bool {
- attr.path.segments.len() == 1 && attr.path.segments[0].ident == name
+ attr.path().segments.len() == 1 && attr.path().segments[0].ident == name
}
/// Checks for `#[doc ...]`, which is generated by doc comments.
@@ -259,34 +248,18 @@ fn is_argh_attr(attr: &syn::Attribute) -> bool {
is_matching_attr("argh", attr)
}
-fn attr_to_meta_subtype<R: Clone>(
+/// Filters out non-`#[argh(...)]` attributes and converts to a sequence of `syn::Meta`.
+fn argh_attr_to_meta_list(
errors: &Errors,
attr: &syn::Attribute,
- f: impl FnOnce(&syn::Meta) -> Option<&R>,
-) -> Option<R> {
- match attr.parse_meta() {
- Ok(meta) => f(&meta).cloned(),
- Err(e) => {
- errors.push(e);
- None
- }
- }
-}
-
-fn attr_to_meta_list(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaList> {
- attr_to_meta_subtype(errors, attr, |m| errors.expect_meta_list(m))
-}
-
-fn attr_to_meta_name_value(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaNameValue> {
- attr_to_meta_subtype(errors, attr, |m| errors.expect_meta_name_value(m))
-}
-
-/// Filters out non-`#[argh(...)]` attributes and converts to `syn::MetaList`.
-fn argh_attr_to_meta_list(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaList> {
+) -> Option<impl IntoIterator<Item = syn::Meta>> {
if !is_argh_attr(attr) {
return None;
}
- attr_to_meta_list(errors, attr)
+ let ml = errors.expect_meta_list(&attr.meta)?;
+ errors.ok(ml.parse_args_with(
+ syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated,
+ ))
}
/// Represents a `#[derive(FromArgs)]` type's top-level attributes.
@@ -317,32 +290,31 @@ impl TypeAttrs {
continue;
};
- for meta in &ml.nested {
- let meta = if let Some(m) = errors.expect_nested_meta(meta) { m } else { continue };
-
+ for meta in ml {
let name = meta.path();
if name.is_ident("description") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
parse_attr_description(errors, m, &mut this.description);
}
} else if name.is_ident("error_code") {
- if let Some(m) = errors.expect_meta_list(meta) {
+ if let Some(m) = errors.expect_meta_list(&meta) {
this.parse_attr_error_code(errors, m);
}
} else if name.is_ident("example") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_example(errors, m);
}
} else if name.is_ident("name") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_name(errors, m);
}
} else if name.is_ident("note") {
- if let Some(m) = errors.expect_meta_name_value(meta) {
+ if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_note(errors, m);
}
} else if name.is_ident("subcommand") {
- if let Some(ident) = errors.expect_meta_word(meta).and_then(|p| p.get_ident()) {
+ if let Some(ident) = errors.expect_meta_word(&meta).and_then(|p| p.get_ident())
+ {
this.parse_attr_subcommand(errors, ident);
}
} else {
@@ -396,20 +368,17 @@ impl TypeAttrs {
}
fn parse_attr_error_code(&mut self, errors: &Errors, ml: &syn::MetaList) {
- if ml.nested.len() != 2 {
- errors.err(&ml, "Expected two arguments, an error number and a string description");
- return;
- }
-
- let err_code = &ml.nested[0];
- let err_msg = &ml.nested[1];
-
- let err_code = errors.expect_nested_lit(err_code).and_then(|l| errors.expect_lit_int(l));
- let err_msg = errors.expect_nested_lit(err_msg).and_then(|l| errors.expect_lit_str(l));
-
- if let (Some(err_code), Some(err_msg)) = (err_code, err_msg) {
- self.error_codes.push((err_code.clone(), err_msg.clone()));
- }
+ errors.ok(ml.parse_args_with(|input: syn::parse::ParseStream| {
+ let err_code = input.parse()?;
+ input.parse::<syn::Token![,]>()?;
+ let err_msg = input.parse()?;
+ if let (Some(err_code), Some(err_msg)) =
+ (errors.expect_lit_int(&err_code), errors.expect_lit_str(&err_msg))
+ {
+ self.error_codes.push((err_code.clone(), err_msg.clone()));
+ }
+ Ok(())
+ }));
}
fn parse_attr_example(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
@@ -470,15 +439,13 @@ impl VariantAttrs {
continue;
};
- for meta in &ml.nested {
- let meta = if let Some(m) = errors.expect_nested_meta(meta) { m } else { continue };
-
+ for meta in ml {
let name = meta.path();
if name.is_ident("dynamic") {
if let Some(prev) = this.is_dynamic.as_ref() {
- errors.duplicate_attrs("dynamic", prev, meta);
+ errors.duplicate_attrs("dynamic", prev, &meta);
} else {
- this.is_dynamic = errors.expect_meta_word(meta).cloned();
+ this.is_dynamic = errors.expect_meta_word(&meta).cloned();
}
} else {
errors.err(
@@ -515,19 +482,19 @@ fn parse_attr_single_string(
) {
if let Some(first) = slot {
errors.duplicate_attrs(name, first, m);
- } else if let Some(lit_str) = errors.expect_lit_str(&m.lit) {
+ } else if let Some(lit_str) = errors.expect_lit_str(&m.value) {
*slot = Some(lit_str.clone());
}
}
fn parse_attr_multi_string(errors: &Errors, m: &syn::MetaNameValue, list: &mut Vec<syn::LitStr>) {
- if let Some(lit_str) = errors.expect_lit_str(&m.lit) {
+ if let Some(lit_str) = errors.expect_lit_str(&m.value) {
list.push(lit_str.clone());
}
}
fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Description>) {
- let nv = if let Some(nv) = attr_to_meta_name_value(errors, attr) {
+ let nv = if let Some(nv) = errors.expect_meta_name_value(&attr.meta) {
nv
} else {
return;
@@ -538,7 +505,7 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
return;
}
- if let Some(lit_str) = errors.expect_lit_str(&nv.lit) {
+ if let Some(lit_str) = errors.expect_lit_str(&nv.value) {
let lit_str = if let Some(previous) = slot {
let previous = &previous.content;
let previous_span = previous.span();
@@ -551,7 +518,8 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
}
fn parse_attr_description(errors: &Errors, m: &syn::MetaNameValue, slot: &mut Option<Description>) {
- let lit_str = if let Some(lit_str) = errors.expect_lit_str(&m.lit) { lit_str } else { return };
+ let lit_str =
+ if let Some(lit_str) = errors.expect_lit_str(&m.value) { lit_str } else { return };
// Don't allow multiple explicit (non doc-comment) descriptions
if let Some(description) = slot {