Skip to content

Commit 11c0b6c

Browse files
committed
Build attribute parse errors using std::fmt system
1 parent e6cf741 commit 11c0b6c

File tree

1 file changed

+37
-29
lines changed

1 file changed

+37
-29
lines changed

src/attr.rs

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ use std::slice;
77
use crate::meta::{self, ParseNestedMeta};
88
#[cfg(feature = "parsing")]
99
use crate::parse::{Parse, ParseStream, Parser, Result};
10-
#[cfg(feature = "parsing")]
11-
use std::fmt::Write;
1210

1311
ast_struct! {
1412
/// An attribute, like `#[repr(transparent)]`.
@@ -238,20 +236,23 @@ impl Attribute {
238236
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
239237
pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
240238
match &self.meta {
241-
Meta::Path(path) => {
242-
let expected = parsing::expected_parentheses(&self.style, path);
243-
let msg = format!("expected attribute arguments in parentheses: {}", expected);
244-
Err(crate::error::new2(
245-
path.segments.first().unwrap().ident.span(),
246-
path.segments.last().unwrap().ident.span(),
247-
msg,
248-
))
249-
}
250-
Meta::NameValue(meta) => {
251-
let expected = parsing::expected_parentheses(&self.style, &meta.path);
252-
let msg = format!("expected parentheses: {}", expected);
253-
Err(Error::new(meta.eq_token.span, msg))
254-
}
239+
Meta::Path(path) => Err(crate::error::new2(
240+
path.segments.first().unwrap().ident.span(),
241+
path.segments.last().unwrap().ident.span(),
242+
format!(
243+
"expected attribute arguments in parentheses: {}[{}(...)]",
244+
parsing::DisplayAttrStyle(&self.style),
245+
parsing::DisplayPath(path),
246+
),
247+
)),
248+
Meta::NameValue(meta) => Err(Error::new(
249+
meta.eq_token.span,
250+
format_args!(
251+
"expected parentheses: {}[{}(...)]",
252+
parsing::DisplayAttrStyle(&self.style),
253+
parsing::DisplayPath(&meta.path),
254+
),
255+
)),
255256
Meta::List(meta) => meta.parse_args_with(parser),
256257
}
257258
}
@@ -569,6 +570,7 @@ pub(crate) mod parsing {
569570
use super::*;
570571
use crate::parse::discouraged::Speculative;
571572
use crate::parse::{Parse, ParseStream, Result};
573+
use std::fmt::{self, Display};
572574

573575
pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
574576
while input.peek(Token![#]) && input.peek2(Token![!]) {
@@ -662,23 +664,29 @@ pub(crate) mod parsing {
662664
})
663665
}
664666

665-
pub(super) fn expected_parentheses(style: &AttrStyle, path: &Path) -> String {
666-
let mut suggestion = String::new();
667-
match style {
668-
AttrStyle::Outer => suggestion.push('#'),
669-
AttrStyle::Inner(_) => suggestion.push_str("#!"),
667+
pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);
668+
669+
impl<'a> Display for DisplayAttrStyle<'a> {
670+
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
671+
formatter.write_str(match self.0 {
672+
AttrStyle::Outer => "#",
673+
AttrStyle::Inner(_) => "#!",
674+
})
670675
}
671-
suggestion.push('[');
676+
}
672677

673-
for (i, segment) in path.segments.iter().enumerate() {
674-
if i > 0 || path.leading_colon.is_some() {
675-
suggestion.push_str("::");
678+
pub(super) struct DisplayPath<'a>(pub &'a Path);
679+
680+
impl<'a> Display for DisplayPath<'a> {
681+
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
682+
for (i, segment) in self.0.segments.iter().enumerate() {
683+
if i > 0 || self.0.leading_colon.is_some() {
684+
formatter.write_str("::")?;
685+
}
686+
write!(formatter, "{}", segment.ident)?;
676687
}
677-
write!(suggestion, "{}", segment.ident).unwrap();
688+
Ok(())
678689
}
679-
680-
suggestion.push_str("(...)]");
681-
suggestion
682690
}
683691
}
684692

0 commit comments

Comments
 (0)