Skip to content

Commit

Permalink
Build attribute parse errors using std::fmt system
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Mar 18, 2023
1 parent e6cf741 commit 11c0b6c
Showing 1 changed file with 37 additions and 29 deletions.
66 changes: 37 additions & 29 deletions src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ use std::slice;
use crate::meta::{self, ParseNestedMeta};
#[cfg(feature = "parsing")]
use crate::parse::{Parse, ParseStream, Parser, Result};
#[cfg(feature = "parsing")]
use std::fmt::Write;

ast_struct! {
/// An attribute, like `#[repr(transparent)]`.
Expand Down Expand Up @@ -238,20 +236,23 @@ impl Attribute {
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
match &self.meta {
Meta::Path(path) => {
let expected = parsing::expected_parentheses(&self.style, path);
let msg = format!("expected attribute arguments in parentheses: {}", expected);
Err(crate::error::new2(
path.segments.first().unwrap().ident.span(),
path.segments.last().unwrap().ident.span(),
msg,
))
}
Meta::NameValue(meta) => {
let expected = parsing::expected_parentheses(&self.style, &meta.path);
let msg = format!("expected parentheses: {}", expected);
Err(Error::new(meta.eq_token.span, msg))
}
Meta::Path(path) => Err(crate::error::new2(
path.segments.first().unwrap().ident.span(),
path.segments.last().unwrap().ident.span(),
format!(
"expected attribute arguments in parentheses: {}[{}(...)]",
parsing::DisplayAttrStyle(&self.style),
parsing::DisplayPath(path),
),
)),
Meta::NameValue(meta) => Err(Error::new(
meta.eq_token.span,
format_args!(
"expected parentheses: {}[{}(...)]",
parsing::DisplayAttrStyle(&self.style),
parsing::DisplayPath(&meta.path),
),
)),
Meta::List(meta) => meta.parse_args_with(parser),
}
}
Expand Down Expand Up @@ -569,6 +570,7 @@ pub(crate) mod parsing {
use super::*;
use crate::parse::discouraged::Speculative;
use crate::parse::{Parse, ParseStream, Result};
use std::fmt::{self, Display};

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

pub(super) fn expected_parentheses(style: &AttrStyle, path: &Path) -> String {
let mut suggestion = String::new();
match style {
AttrStyle::Outer => suggestion.push('#'),
AttrStyle::Inner(_) => suggestion.push_str("#!"),
pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);

impl<'a> Display for DisplayAttrStyle<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(match self.0 {
AttrStyle::Outer => "#",
AttrStyle::Inner(_) => "#!",
})
}
suggestion.push('[');
}

for (i, segment) in path.segments.iter().enumerate() {
if i > 0 || path.leading_colon.is_some() {
suggestion.push_str("::");
pub(super) struct DisplayPath<'a>(pub &'a Path);

impl<'a> Display for DisplayPath<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
for (i, segment) in self.0.segments.iter().enumerate() {
if i > 0 || self.0.leading_colon.is_some() {
formatter.write_str("::")?;
}
write!(formatter, "{}", segment.ident)?;
}
write!(suggestion, "{}", segment.ident).unwrap();
Ok(())
}

suggestion.push_str("(...)]");
suggestion
}
}

Expand Down

0 comments on commit 11c0b6c

Please sign in to comment.