1use crate::syntax::cfg::CfgExpr;
2use crate::syntax::namespace::Namespace;
3use crate::syntax::report::Errors;
4use crate::syntax::repr::Repr;
5use crate::syntax::{cfg, Derive, Doc, ForeignName};
6use proc_macro2::{Ident, TokenStream};
7use quote::ToTokens;
8use syn::parse::ParseStream;
9use syn::{Attribute, Error, Expr, Lit, LitStr, Meta, Path, Result, Token};
10
11#[derive(Default)]
30pub(crate) struct Parser<'a> {
31 pub cfg: Option<&'a mut CfgExpr>,
32 pub doc: Option<&'a mut Doc>,
33 pub derives: Option<&'a mut Vec<Derive>>,
34 pub repr: Option<&'a mut Option<Repr>>,
35 pub namespace: Option<&'a mut Namespace>,
36 pub cxx_name: Option<&'a mut Option<ForeignName>>,
37 pub rust_name: Option<&'a mut Option<Ident>>,
38 pub self_type: Option<&'a mut Option<Ident>>,
39 pub ignore_unrecognized: bool,
40
41 pub(crate) _more: (),
45}
46
47pub(crate) fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> OtherAttrs {
48 let mut passthrough_attrs = Vec::new();
49 for attr in attrs {
50 let attr_path = attr.path();
51 if attr_path.is_ident("doc") {
52 match parse_doc_attribute(&attr.meta) {
53 Ok(attr) => {
54 if let Some(doc) = &mut parser.doc {
55 match attr {
56 DocAttribute::Doc(lit) => doc.push(lit),
57 DocAttribute::Hidden => doc.hidden = true,
58 }
59 continue;
60 }
61 }
62 Err(err) => {
63 cx.push(err);
64 break;
65 }
66 }
67 } else if attr_path.is_ident("derive") {
68 match attr.parse_args_with(|attr: ParseStream| parse_derive_attribute(cx, attr)) {
69 Ok(attr) => {
70 if let Some(derives) = &mut parser.derives {
71 derives.extend(attr);
72 continue;
73 }
74 }
75 Err(err) => {
76 cx.push(err);
77 break;
78 }
79 }
80 } else if attr_path.is_ident("repr") {
81 match attr.parse_args::<Repr>() {
82 Ok(attr) => {
83 if let Some(repr) = &mut parser.repr {
84 **repr = Some(attr);
85 continue;
86 }
87 }
88 Err(err) => {
89 cx.push(err);
90 break;
91 }
92 }
93 } else if attr_path.is_ident("namespace") {
94 match Namespace::parse_meta(&attr.meta) {
95 Ok(attr) => {
96 if let Some(namespace) = &mut parser.namespace {
97 **namespace = attr;
98 continue;
99 }
100 }
101 Err(err) => {
102 cx.push(err);
103 break;
104 }
105 }
106 } else if attr_path.is_ident("cxx_name") {
107 match parse_cxx_name_attribute(&attr.meta) {
108 Ok(attr) => {
109 if let Some(cxx_name) = &mut parser.cxx_name {
110 **cxx_name = Some(attr);
111 continue;
112 }
113 }
114 Err(err) => {
115 cx.push(err);
116 break;
117 }
118 }
119 } else if attr_path.is_ident("rust_name") {
120 match parse_rust_ident_attribute(&attr.meta) {
121 Ok(attr) => {
122 if let Some(rust_name) = &mut parser.rust_name {
123 **rust_name = Some(attr);
124 continue;
125 }
126 }
127 Err(err) => {
128 cx.push(err);
129 break;
130 }
131 }
132 } else if attr_path.is_ident("Self") {
133 match parse_rust_ident_attribute(&attr.meta) {
134 Ok(attr) => {
135 if let Some(self_type) = &mut parser.self_type {
136 **self_type = Some(attr);
137 continue;
138 }
139 }
140 Err(err) => {
141 cx.push(err);
142 break;
143 }
144 }
145 } else if attr_path.is_ident("cfg") {
146 match cfg::parse_attribute(&attr) {
147 Ok(cfg_expr) => {
148 if let Some(cfg) = &mut parser.cfg {
149 cfg.merge(cfg_expr);
150 passthrough_attrs.push(attr);
151 continue;
152 }
153 }
154 Err(err) => {
155 cx.push(err);
156 break;
157 }
158 }
159 } else if attr_path.is_ident("allow")
160 || attr_path.is_ident("warn")
161 || attr_path.is_ident("deny")
162 || attr_path.is_ident("forbid")
163 || attr_path.is_ident("deprecated")
164 || attr_path.is_ident("must_use")
165 {
166 passthrough_attrs.push(attr);
168 continue;
169 } else if attr_path.is_ident("serde") {
170 passthrough_attrs.push(attr);
171 continue;
172 } else if attr_path.segments.len() > 1 {
173 let tool = &attr_path.segments.first().unwrap().ident;
174 if tool == "rustfmt" {
175 continue;
177 } else if tool == "clippy" {
178 passthrough_attrs.push(attr);
179 continue;
180 }
181 }
182 if !parser.ignore_unrecognized {
183 cx.error(attr, "unsupported attribute");
184 break;
185 }
186 }
187 OtherAttrs(passthrough_attrs)
188}
189
190enum DocAttribute {
191 Doc(LitStr),
192 Hidden,
193}
194
195mod kw {
196 syn::custom_keyword!(hidden);
197}
198
199fn parse_doc_attribute(meta: &Meta) -> Result<DocAttribute> {
200 match meta {
201 Meta::NameValue(meta) => {
202 if let Expr::Lit(expr) = &meta.value {
203 if let Lit::Str(lit) = &expr.lit {
204 return Ok(DocAttribute::Doc(lit.clone()));
205 }
206 }
207 }
208 Meta::List(meta) => {
209 meta.parse_args::<kw::hidden>()?;
210 return Ok(DocAttribute::Hidden);
211 }
212 Meta::Path(_) => {}
213 }
214 Err(Error::new_spanned(meta, "unsupported doc attribute"))
215}
216
217fn parse_derive_attribute(cx: &mut Errors, input: ParseStream) -> Result<Vec<Derive>> {
218 let paths = input.parse_terminated(Path::parse_mod_style, Token![,])?;
219
220 let mut derives = Vec::new();
221 for path in paths {
222 if let Some(ident) = path.get_ident() {
223 if let Some(derive) = Derive::from(ident) {
224 derives.push(derive);
225 continue;
226 }
227 }
228 cx.error(path, "unsupported derive");
229 }
230 Ok(derives)
231}
232
233fn parse_cxx_name_attribute(meta: &Meta) -> Result<ForeignName> {
234 if let Meta::NameValue(meta) = meta {
235 match &meta.value {
236 Expr::Lit(expr) => {
237 if let Lit::Str(lit) = &expr.lit {
238 return ForeignName::parse(&lit.value(), lit.span());
239 }
240 }
241 Expr::Path(expr) => {
242 if let Some(ident) = expr.path.get_ident() {
243 return ForeignName::parse(&ident.to_string(), ident.span());
244 }
245 }
246 _ => {}
247 }
248 }
249 Err(Error::new_spanned(meta, "unsupported cxx_name attribute"))
250}
251
252fn parse_rust_ident_attribute(meta: &Meta) -> Result<Ident> {
253 if let Meta::NameValue(meta) = meta {
254 match &meta.value {
255 Expr::Lit(expr) => {
256 if let Lit::Str(lit) = &expr.lit {
257 return lit.parse();
258 }
259 }
260 Expr::Path(expr) => {
261 if let Some(ident) = expr.path.get_ident() {
262 return Ok(ident.clone());
263 }
264 }
265 _ => {}
266 }
267 }
268 Err(Error::new_spanned(
269 meta,
270 format!(
271 "unsupported `{}` attribute",
272 meta.path().get_ident().unwrap(),
273 ),
274 ))
275}
276
277#[derive(Clone)]
278pub(crate) struct OtherAttrs(Vec<Attribute>);
279
280impl OtherAttrs {
281 pub(crate) fn none() -> Self {
282 OtherAttrs(Vec::new())
283 }
284
285 pub(crate) fn extend(&mut self, other: Self) {
286 self.0.extend(other.0);
287 }
288}
289
290impl ToTokens for OtherAttrs {
291 fn to_tokens(&self, tokens: &mut TokenStream) {
292 for attr in &self.0 {
293 let Attribute {
294 pound_token,
295 style,
296 bracket_token,
297 meta,
298 } = attr;
299 pound_token.to_tokens(tokens);
300 let _ = style; bracket_token.surround(tokens, |tokens| meta.to_tokens(tokens));
302 }
303 }
304}