From 58906767102d57331cf58771161f266c7c207617 Mon Sep 17 00:00:00 2001
From: rsdy
Date: Mon, 26 Sep 2022 12:16:24 +0100
Subject: [PATCH] Implement better error reporting using spans of token
subtrees
---
instant-xml-macros/src/lib.rs | 35 ++++++++++++++++++-----------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/instant-xml-macros/src/lib.rs b/instant-xml-macros/src/lib.rs
index b2c8ef1..5a4b1d4 100644
--- a/instant-xml-macros/src/lib.rs
+++ b/instant-xml-macros/src/lib.rs
@@ -39,11 +39,11 @@ struct ContainerMeta {
impl ContainerMeta {
fn from_derive(input: &syn::DeriveInput) -> Result {
let mut meta = ContainerMeta::default();
- for item in meta_items(&input.attrs) {
+ for (item, span) in meta_items(&input.attrs) {
match item {
MetaItem::Attribute => {
return Err(syn::Error::new(
- input.span(),
+ span,
"attribute key invalid in container xml attribute",
))
}
@@ -52,7 +52,7 @@ impl ContainerMeta {
MetaItem::RenameAll(lit) => {
meta.rename_all = match RenameRule::from_str(&lit.to_string()) {
Ok(rule) => rule,
- Err(err) => return Err(syn::Error::new(input.span(), err)),
+ Err(err) => return Err(syn::Error::new(span, err)),
};
}
MetaItem::Scalar => meta.scalar = true,
@@ -72,20 +72,20 @@ struct FieldMeta {
impl FieldMeta {
fn from_field(input: &syn::Field) -> Result {
let mut meta = FieldMeta::default();
- for item in meta_items(&input.attrs) {
+ for (item, span) in meta_items(&input.attrs) {
match item {
MetaItem::Attribute => meta.attribute = true,
MetaItem::Ns(ns) => meta.ns = ns,
MetaItem::Rename(lit) => meta.rename = Some(lit),
MetaItem::RenameAll(_) => {
return Err(syn::Error::new(
- input.span(),
+ span,
"attribute 'rename_all' invalid in field xml attribute",
))
}
MetaItem::Scalar => {
return Err(syn::Error::new(
- input.span(),
+ span,
"attribute 'scalar' is invalid for struct fields",
))
}
@@ -114,31 +114,31 @@ impl VariantMeta {
}
let mut rename = None;
- for item in meta_items(&input.attrs) {
+ for (item, span) in meta_items(&input.attrs) {
match item {
MetaItem::Rename(lit) => rename = Some(lit.to_token_stream()),
MetaItem::Attribute => {
return Err(syn::Error::new(
- input.span(),
+ span,
"attribute 'attribute' is invalid for enum variants",
))
}
MetaItem::Ns(_ns) => {
return Err(syn::Error::new(
- input.span(),
+ span,
"attribute 'ns' is invalid for enum variants",
))
}
MetaItem::RenameAll(_) => {
return Err(syn::Error::new(
- input.span(),
+ span,
"attribute 'rename_all' invalid in field xml attribute",
))
}
MetaItem::Scalar => {
return Err(syn::Error::new(
- input.span(),
+ span,
"attribute 'scalar' is invalid for enum variants",
))
}
@@ -445,7 +445,7 @@ impl NamespaceMeta {
}
}
-fn meta_items(attrs: &[syn::Attribute]) -> Vec {
+fn meta_items(attrs: &[syn::Attribute]) -> Vec<(MetaItem, Span)> {
let mut items = Vec::new();
let attr = match attrs.iter().find(|attr| attr.path.is_ident("xml")) {
Some(attr) => attr,
@@ -466,10 +466,11 @@ fn meta_items(attrs: &[syn::Attribute]) -> Vec {
let mut state = MetaState::Start;
for tree in first {
+ let span = tree.span();
state = match (state, tree) {
(MetaState::Start, TokenTree::Ident(id)) => {
if id == "attribute" {
- items.push(MetaItem::Attribute);
+ items.push((MetaItem::Attribute, span));
MetaState::Comma
} else if id == "ns" {
MetaState::Ns
@@ -478,7 +479,7 @@ fn meta_items(attrs: &[syn::Attribute]) -> Vec {
} else if id == "rename_all" {
MetaState::RenameAll
} else if id == "scalar" {
- items.push(MetaItem::Scalar);
+ items.push((MetaItem::Scalar, span));
MetaState::Comma
} else {
panic!("unexpected key in xml attribute");
@@ -490,21 +491,21 @@ fn meta_items(attrs: &[syn::Attribute]) -> Vec {
(MetaState::Ns, TokenTree::Group(group))
if group.delimiter() == Delimiter::Parenthesis =>
{
- items.push(MetaItem::Ns(NamespaceMeta::from_tokens(group)));
+ items.push((MetaItem::Ns(NamespaceMeta::from_tokens(group)), span));
MetaState::Comma
}
(MetaState::Rename, TokenTree::Punct(punct)) if punct.as_char() == '=' => {
MetaState::RenameValue
}
(MetaState::RenameValue, TokenTree::Literal(lit)) => {
- items.push(MetaItem::Rename(lit));
+ items.push((MetaItem::Rename(lit), span));
MetaState::Comma
}
(MetaState::RenameAll, TokenTree::Punct(punct)) if punct.as_char() == '=' => {
MetaState::RenameAllValue
}
(MetaState::RenameAllValue, TokenTree::Literal(lit)) => {
- items.push(MetaItem::RenameAll(lit));
+ items.push((MetaItem::RenameAll(lit), span));
MetaState::Comma
}
(state, tree) => {