cxx_build/syntax/
attrs.rs1use 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;
7use syn::parse::ParseStream;
8use syn::{Attribute, Error, Expr, Lit, LitStr, Meta, Path, Result, Token};
9
10)]
29pub(crate) struct Parser<'a> {
30 pub cfg: Option<&'a mut CfgExpr>,
31 pub doc: Option<&'a mut Doc>,
32 pub derives: Option<&'a mut Vec<Derive>>,
33 pub repr: Option<&'a mut Option<Repr>>,
34 pub default: Option<&'a mut bool>,
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
47#[must_use]
48pub(crate) fn parse(cx: &mut Errors, attrs: Vec<Attribute>, mut parser: Parser) -> OtherAttrs {
49 let mut other_attrs = OtherAttrs::new();
50 for attr in attrs {
51 let attr_path = attr.path();
52 if attr_path.is_ident("doc") {
53 match parse_doc_attribute(&attr.meta) {
54 Ok(attr) => {
55 if let Some(doc) = &mut parser.doc {
56 match attr {
57 DocAttribute::Doc(lit) => doc.push(lit),
58 DocAttribute::Hidden => doc.hidden = true,
59 }
60 continue;
61 }
62 }
63 Err(err) => {
64 cx.push(err);
65 break;
66 }
67 }
68 } else if attr_path.is_ident("derive") {
69 match attr.parse_args_with(|attr: ParseStream| parse_derive_attribute(cx, attr)) {
70 Ok(attr) => {
71 if let Some(derives) = &mut parser.derives {
72 derives.extend(attr);
73 continue;
74 }
75 }
76 Err(err) => {
77 cx.push(err);
78 break;
79 }
80 }
81 } else if attr_path.is_ident("repr") {
82 match attr.parse_args::<Repr>() {
83 Ok(attr) => {
84 if let Some(repr) = &mut parser.repr {
85 **repr = Some(attr);
86 continue;
87 }
88 }
89 Err(err) => {
90 cx.push(err);
91 break;
92 }
93 }
94 } else if attr_path.is_ident("default") {
95 match parse_default_attribute(&attr.meta) {
96 Ok(()) => {
97 if let Some(default) = &mut parser.default {
98 **default = true;
99 continue;
100 }
101 }
102 Err(err) => {
103 cx.push(err);
104 break;
105 }
106 }
107 } else if attr_path.is_ident("namespace") {
108 match Namespace::parse_meta(&attr.meta) {
109 Ok(attr) => {
110 if let Some(namespace) = &mut parser.namespace {
111 **namespace = attr;
112 continue;
113 }
114 }
115 Err(err) => {
116 cx.push(err);
117 break;
118 }
119 }
120 } else if attr_path.is_ident("cxx_name") {
121 match parse_cxx_name_attribute(&attr.meta) {
122 Ok(attr) => {
123 if let Some(cxx_name) = &mut parser.cxx_name {
124 **cxx_name = Some(attr);
125 continue;
126 }
127 }
128 Err(err) => {
129 cx.push(err);
130 break;
131 }
132 }
133 } else if attr_path.is_ident("rust_name") {
134 match parse_rust_ident_attribute(&attr.meta) {
135 Ok(attr) => {
136 if let Some(rust_name) = &mut parser.rust_name {
137 **rust_name = Some(attr);
138 continue;
139 }
140 }
141 Err(err) => {
142 cx.push(err);
143 break;
144 }
145 }
146 } else if attr_path.is_ident("Self") {
147 match parse_rust_ident_attribute(&attr.meta) {
148 Ok(attr) => {
149 if let Some(self_type) = &mut parser.self_type {
150 **self_type = Some(attr);
151 continue;
152 }
153 }
154 Err(err) => {
155 cx.push(err);
156 break;
157 }
158 }
159 } else if attr_path.is_ident("cfg") {
160 match cfg::parse_attribute(&attr) {
161 Ok(cfg_expr) => {
162 if let Some(cfg) = &mut parser.cfg {
163 cfg.merge_and(cfg_expr);
164 other_attrs.cfg.push(attr);
165 continue;
166 }
167 }
168 Err(err) => {
169 cx.push(err);
170 break;
171 }
172 }
173 } else if attr_path.is_ident("allow")
174 || attr_path.is_ident("warn")
175 || attr_path.is_ident("deny")
176 || attr_path.is_ident("forbid")
177 {
178 other_attrs.lint.push(attr);
179 continue;
180 } else if attr_path.is_ident("deprecated")
181 || attr_path.is_ident("must_use")
182 || attr_path.is_ident("serde")
183 {
184 other_attrs.passthrough.push(attr);
185 continue;
186 } else if attr_path.segments.len() > 1 {
187 let tool = &attr_path.segments.first().unwrap().ident;
188 if tool == "rustfmt" {
189 continue;
191 } else if tool == "clippy" {
192 other_attrs.lint.push(attr);
193 continue;
194 }
195 }
196 if !parser.ignore_unrecognized {
197 cx.error(attr, "unsupported attribute");
198 break;
199 }
200 }
201 other_attrs
202}
203
204enum DocAttribute {
205 Doc(LitStr),
206 Hidden,
207}
208
209mod kw {
210 #[allow(non_camel_case_types)]
pub struct hidden {
#[allow(dead_code)]
pub span: ::syn::__private::Span,
}
#[doc(hidden)]
#[allow(dead_code, non_snake_case)]
pub fn hidden<__S: ::syn::__private::IntoSpans<::syn::__private::Span>>(span:
__S) -> hidden {
hidden { span: ::syn::__private::IntoSpans::into_spans(span) }
}
const _: () =
{
impl ::syn::__private::Default for hidden {
fn default() -> Self {
hidden { span: ::syn::__private::Span::call_site() }
}
}
impl ::syn::__private::CustomToken for hidden {
fn peek(cursor: ::syn::buffer::Cursor) -> ::syn::__private::bool {
if let ::syn::__private::Some((ident, _rest)) = cursor.ident()
{
ident == "hidden"
} else { false }
}
fn display() -> &'static ::syn::__private::str { "`hidden`" }
}
impl ::syn::parse::Parse for hidden {
fn parse(input: ::syn::parse::ParseStream)
-> ::syn::parse::Result<hidden> {
input.step(|cursor|
{
if let ::syn::__private::Some((ident, rest)) =
cursor.ident() {
if ident == "hidden" {
return ::syn::__private::Ok((hidden { span: ident.span() },
rest));
}
}
::syn::__private::Err(cursor.error("expected `hidden`"))
})
}
}
impl ::syn::__private::ToTokens for hidden {
fn to_tokens(&self, tokens: &mut ::syn::__private::TokenStream2) {
let ident = ::syn::Ident::new("hidden", self.span);
::syn::__private::TokenStreamExt::append(tokens, ident);
}
}
impl ::syn::__private::Copy for hidden {}
#[allow(clippy :: expl_impl_clone_on_copy)]
impl ::syn::__private::Clone for hidden {
fn clone(&self) -> Self { *self }
}
;
};syn::custom_keyword!(hidden);
211}
212
213fn parse_doc_attribute(meta: &Meta) -> Result<DocAttribute> {
214 match meta {
215 Meta::NameValue(meta) => {
216 if let Expr::Lit(expr) = &meta.value {
217 if let Lit::Str(lit) = &expr.lit {
218 return Ok(DocAttribute::Doc(lit.clone()));
219 }
220 }
221 }
222 Meta::List(meta) => {
223 meta.parse_args::<kw::hidden>()?;
224 return Ok(DocAttribute::Hidden);
225 }
226 Meta::Path(_) => {}
227 }
228 Err(Error::new_spanned(meta, "unsupported doc attribute"))
229}
230
231fn parse_derive_attribute(cx: &mut Errors, input: ParseStream) -> Result<Vec<Derive>> {
232 let paths = input.parse_terminated(Path::parse_mod_style, ::syn::token::CommaToken![,])?;
233
234 let mut derives = Vec::new();
235 for path in paths {
236 if let Some(ident) = path.get_ident() {
237 if let Some(derive) = Derive::from(ident) {
238 derives.push(derive);
239 continue;
240 }
241 }
242 cx.error(path, "unsupported derive");
243 }
244 Ok(derives)
245}
246
247fn parse_default_attribute(meta: &Meta) -> Result<()> {
248 let error_span = match meta {
249 Meta::Path(_) => return Ok(()),
250 Meta::List(meta) => meta.delimiter.span().open(),
251 Meta::NameValue(meta) => meta.eq_token.span,
252 };
253 Err(Error::new(
254 error_span,
255 "#[default] attribute does not accept an argument",
256 ))
257}
258
259fn parse_cxx_name_attribute(meta: &Meta) -> Result<ForeignName> {
260 if let Meta::NameValue(meta) = meta {
261 match &meta.value {
262 Expr::Lit(expr) => {
263 if let Lit::Str(lit) = &expr.lit {
264 return ForeignName::parse(&lit.value(), lit.span());
265 }
266 }
267 Expr::Path(expr) => {
268 if let Some(ident) = expr.path.get_ident() {
269 return ForeignName::parse(&ident.to_string(), ident.span());
270 }
271 }
272 _ => {}
273 }
274 }
275 Err(Error::new_spanned(meta, "unsupported cxx_name attribute"))
276}
277
278fn parse_rust_ident_attribute(meta: &Meta) -> Result<Ident> {
279 if let Meta::NameValue(meta) = meta {
280 match &meta.value {
281 Expr::Lit(expr) => {
282 if let Lit::Str(lit) = &expr.lit {
283 return lit.parse();
284 }
285 }
286 Expr::Path(expr) => {
287 if let Some(ident) = expr.path.get_ident() {
288 return Ok(ident.clone());
289 }
290 }
291 _ => {}
292 }
293 }
294 Err(Error::new_spanned(
295 meta,
296 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unsupported `{0}` attribute",
meta.path().get_ident().unwrap()))
})format!(
297 "unsupported `{}` attribute",
298 meta.path().get_ident().unwrap(),
299 ),
300 ))
301}
302
303#[derive(#[automatically_derived]
impl ::core::clone::Clone for OtherAttrs {
#[inline]
fn clone(&self) -> OtherAttrs {
OtherAttrs {
cfg: ::core::clone::Clone::clone(&self.cfg),
lint: ::core::clone::Clone::clone(&self.lint),
passthrough: ::core::clone::Clone::clone(&self.passthrough),
}
}
}Clone)]
304pub(crate) struct OtherAttrs {
305 pub cfg: Vec<Attribute>,
306 pub lint: Vec<Attribute>,
307 pub passthrough: Vec<Attribute>,
308}
309
310impl OtherAttrs {
311 pub(crate) fn new() -> Self {
312 OtherAttrs {
313 cfg: Vec::new(),
314 lint: Vec::new(),
315 passthrough: Vec::new(),
316 }
317 }
318
319 pub(crate) fn extend(&mut self, other: Self) {
320 self.cfg.extend(other.cfg);
321 self.lint.extend(other.lint);
322 self.passthrough.extend(other.passthrough);
323 }
324}