1use proc_macro2::{Delimiter, TokenTree};
5use syn::{
6 spanned::Spanned,
7 visit_mut::{visit_item_trait_mut, VisitMut},
8 Attribute, Error, Meta, TraitItem,
9};
10
11use crate::proxy::{parse_types, ProxyType};
12
13pub(crate) fn remove_our_attrs(trait_def: &mut syn::ItemTrait) -> syn::Result<()> {
16 struct AttrRemover(syn::Result<()>);
17 impl VisitMut for AttrRemover {
18 fn visit_trait_item_mut(&mut self, item: &mut TraitItem) {
19 let item_span = item.span();
20 let (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 _ => {
26 let err = syn::Error::new(
27 item.span(),
28 "encountered unexpected `TraitItem`, cannot handle that, sorry!",
29 );
30
31 if let Err(ref mut current_err) = self.0 {
32 current_err.combine(err);
33 } else {
34 self.0 = Err(err);
35 };
36
37 return;
38 }
39 };
40
41 if !is_method && attrs.iter().any(is_our_attr) {
43 let err = syn::Error::new(
44 item_span,
45 "`#[auto_impl]` attributes are only allowed on methods",
46 );
47
48 if let Err(ref mut current_err) = self.0 {
49 current_err.combine(err);
50 } else {
51 self.0 = Err(err);
52 };
53
54 return;
55 }
56
57 attrs.retain(|a| !is_our_attr(a));
58 }
59 }
60
61 let mut visitor = AttrRemover(Ok(()));
62 visit_item_trait_mut(&mut visitor, trait_def);
63
64 visitor.0
65}
66
67pub(crate) fn is_our_attr(attr: &Attribute) -> bool {
70 attr.path().is_ident("auto_impl")
71}
72
73pub(crate) fn parse_our_attr(attr: &Attribute) -> syn::Result<OurAttr> {
78 assert!(is_our_attr(attr));
79
80 let body = match &attr.meta {
84 Meta::List(list) => list.tokens.clone(),
85 _ => {
86 return Err(Error::new(
87 attr.span(),
88 "expected single group delimited by `()`",
89 ));
90 }
91 };
92
93 let mut it = body.clone().into_iter();
94
95 let name = match it.next() {
97 Some(TokenTree::Ident(x)) => x,
98 Some(other) => {
99 return Err(Error::new(
100 other.span(),
101 format_args!("expected ident, found '{}'", other),
102 ));
103 }
104 None => {
105 return Err(Error::new(attr.span(), "expected ident, found nothing"));
106 }
107 };
108
109 let params = match it.next() {
112 Some(TokenTree::Group(ref g)) if g.delimiter() == Delimiter::Parenthesis => g.stream(),
113 Some(other) => {
114 return Err(Error::new(
115 other.span(),
116 format_args!(
117 "expected arguments for '{}' in parenthesis `()`, found `{}`",
118 name, other
119 ),
120 ));
121 }
122 None => {
123 return Err(Error::new(
124 body.span(),
125 format_args!(
126 "expected arguments for '{}' in parenthesis `()`, found nothing",
127 name,
128 ),
129 ));
130 }
131 };
132
133 let out = if name == "keep_default_for" {
135 let proxy_types = parse_types(params.into());
136 OurAttr::KeepDefaultFor(proxy_types)
137 } else {
138 return Err(Error::new(
139 name.span(),
140 format_args!(
141 "invalid attribute '{}'; only `keep_default_for` is supported",
142 name
143 ),
144 ));
145 };
146
147 Ok(out)
148}
149
150#[derive(Clone, PartialEq, Debug)]
153pub(crate) enum OurAttr {
154 KeepDefaultFor(Vec<ProxyType>),
155}