1//! Internal attributes of the form `#[auto_impl(name(...))]` that can be
2//! attached to trait items.
34use proc_macro2::{Delimiter, TokenTree};
5use syn::{
6 spanned::Spanned,
7 visit_mut::{visit_item_trait_mut, VisitMut},
8 Attribute, Error, Meta, TraitItem,
9};
1011use crate::proxy::{parse_types, ProxyType};
1213/// Removes all `#[auto_impl]` attributes that are attached to methods of the
14/// given trait.
15pub(crate) fn remove_our_attrs(trait_def: &mut syn::ItemTrait) -> syn::Result<()> {
16struct AttrRemover(syn::Result<()>);
17impl VisitMut for AttrRemover {
18fn visit_trait_item_mut(&mut self, item: &mut TraitItem) {
19let item_span = item.span();
20let (attrs, is_method) = match item {
21 TraitItem::Fn(m) => (&mut m.attrs, true),
22 TraitItem::Const(c) => (&mut c.attrs, false),
23 TraitItem::Type(t) => (&mut t.attrs, false),
24 TraitItem::Macro(m) => (&mut m.attrs, false),
25_ => {
26let err = syn::Error::new(
27 item.span(),
28"encountered unexpected `TraitItem`, cannot handle that, sorry!",
29 );
3031if let Err(ref mut current_err) = self.0 {
32 current_err.combine(err);
33 } else {
34self.0 = Err(err);
35 };
3637return;
38 }
39 };
4041// Make sure non-methods do not have our attributes.
42if !is_method && attrs.iter().any(is_our_attr) {
43let err = syn::Error::new(
44 item_span,
45"`#[auto_impl]` attributes are only allowed on methods",
46 );
4748if let Err(ref mut current_err) = self.0 {
49 current_err.combine(err);
50 } else {
51self.0 = Err(err);
52 };
5354return;
55 }
5657 attrs.retain(|a| !is_our_attr(a));
58 }
59 }
6061let mut visitor = AttrRemover(Ok(()));
62 visit_item_trait_mut(&mut visitor, trait_def);
6364 visitor.0
65}
6667/// Checks if the given attribute is "our" attribute. That means that it's path
68/// is `auto_impl`.
69pub(crate) fn is_our_attr(attr: &Attribute) -> bool {
70 attr.path().is_ident("auto_impl")
71}
7273/// Tries to parse the given attribute as one of our own `auto_impl`
74/// attributes. If it's invalid, an error is emitted and `Err(())` is returned.
75/// You have to make sure that `attr` is one of our attrs with `is_our_attr`
76/// before calling this function!
77pub(crate) fn parse_our_attr(attr: &Attribute) -> syn::Result<OurAttr> {
78assert!(is_our_attr(attr));
7980// Get the body of the attribute (which has to be a ground, because we
81 // required the syntax `auto_impl(...)` and forbid stuff like
82 // `auto_impl = ...`).
83let body = match &attr.meta {
84 Meta::List(list) => list.tokens.clone(),
85_ => {
86return Err(Error::new(
87 attr.span(),
88"expected single group delimited by `()`",
89 ));
90 }
91 };
9293let mut it = body.clone().into_iter();
9495// Try to extract the name (we require the body to be `name(...)`).
96let name = match it.next() {
97Some(TokenTree::Ident(x)) => x,
98Some(other) => {
99return Err(Error::new(
100 other.span(),
101format_args!("expected ident, found '{}'", other),
102 ));
103 }
104None => {
105return Err(Error::new(attr.span(), "expected ident, found nothing"));
106 }
107 };
108109// Extract the parameters (which again, have to be a group delimited by
110 // `()`)
111let params = match it.next() {
112Some(TokenTree::Group(ref g)) if g.delimiter() == Delimiter::Parenthesis => g.stream(),
113Some(other) => {
114return Err(Error::new(
115 other.span(),
116format_args!(
117"expected arguments for '{}' in parenthesis `()`, found `{}`",
118 name, other
119 ),
120 ));
121 }
122None => {
123return Err(Error::new(
124 body.span(),
125format_args!(
126"expected arguments for '{}' in parenthesis `()`, found nothing",
127 name,
128 ),
129 ));
130 }
131 };
132133// Finally match over the name of the attribute.
134let out = if name == "keep_default_for" {
135let proxy_types = parse_types(params.into());
136 OurAttr::KeepDefaultFor(proxy_types)
137 } else {
138return Err(Error::new(
139 name.span(),
140format_args!(
141"invalid attribute '{}'; only `keep_default_for` is supported",
142 name
143 ),
144 ));
145 };
146147Ok(out)
148}
149150/// Attributes of the form `#[auto_impl(...)]` that can be attached to items of
151/// the trait.
152#[derive(Clone, PartialEq, Debug)]
153pub(crate) enum OurAttr {
154 KeepDefaultFor(Vec<ProxyType>),
155}