1 use crate::syntax::attrs::OtherAttrs;
2 use crate::syntax::discriminant::DiscriminantSet;
3 use crate::syntax::file::{Item, ItemForeignMod};
4 use crate::syntax::report::Errors;
5 use crate::syntax::Atom::*;
6 use crate::syntax::{
7     attrs, error, Api, Array, Derive, Doc, Enum, EnumRepr, ExternFn, ExternType, ForeignName, Impl,
8     Include, IncludeKind, Lang, Lifetimes, NamedType, Namespace, Pair, Ptr, Receiver, Ref,
9     Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var, Variant,
10 };
11 use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
12 use quote::{format_ident, quote, quote_spanned};
13 use std::mem;
14 use syn::parse::{ParseStream, Parser};
15 use syn::punctuated::Punctuated;
16 use syn::{
17     Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
18     GenericArgument, GenericParam, Generics, Ident, ItemEnum, ItemImpl, ItemStruct, Lit, LitStr,
19     Pat, PathArguments, Result, ReturnType, Signature as RustSignature, Token, TraitBound,
20     TraitBoundModifier, Type as RustType, TypeArray, TypeBareFn, TypeParamBound, TypePath, TypePtr,
21     TypeReference, Variant as RustVariant, Visibility,
22 };
23 
24 pub mod kw {
25     syn::custom_keyword!(Pin);
26     syn::custom_keyword!(Result);
27 }
28 
parse_items( cx: &mut Errors, items: Vec<Item>, trusted: bool, namespace: &Namespace, ) -> Vec<Api>29 pub fn parse_items(
30     cx: &mut Errors,
31     items: Vec<Item>,
32     trusted: bool,
33     namespace: &Namespace,
34 ) -> Vec<Api> {
35     let mut apis = Vec::new();
36     for item in items {
37         match item {
38             Item::Struct(item) => match parse_struct(cx, item, namespace) {
39                 Ok(strct) => apis.push(strct),
40                 Err(err) => cx.push(err),
41             },
42             Item::Enum(item) => apis.push(parse_enum(cx, item, namespace)),
43             Item::ForeignMod(foreign_mod) => {
44                 parse_foreign_mod(cx, foreign_mod, &mut apis, trusted, namespace)
45             }
46             Item::Impl(item) => match parse_impl(item) {
47                 Ok(imp) => apis.push(imp),
48                 Err(err) => cx.push(err),
49             },
50             Item::Use(item) => cx.error(item, error::USE_NOT_ALLOWED),
51             Item::Other(item) => cx.error(item, "unsupported item"),
52         }
53     }
54     apis
55 }
56 
parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> Result<Api>57 fn parse_struct(cx: &mut Errors, mut item: ItemStruct, namespace: &Namespace) -> Result<Api> {
58     let mut doc = Doc::new();
59     let mut derives = Vec::new();
60     let mut namespace = namespace.clone();
61     let mut cxx_name = None;
62     let mut rust_name = None;
63     let attrs = attrs::parse(
64         cx,
65         mem::take(&mut item.attrs),
66         attrs::Parser {
67             doc: Some(&mut doc),
68             derives: Some(&mut derives),
69             namespace: Some(&mut namespace),
70             cxx_name: Some(&mut cxx_name),
71             rust_name: Some(&mut rust_name),
72             ..Default::default()
73         },
74     );
75 
76     let named_fields = match item.fields {
77         Fields::Named(fields) => fields,
78         Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
79         Fields::Unnamed(_) => {
80             return Err(Error::new_spanned(item, "tuple structs are not supported"));
81         }
82     };
83 
84     let mut lifetimes = Punctuated::new();
85     let mut has_unsupported_generic_param = false;
86     for pair in item.generics.params.into_pairs() {
87         let (param, punct) = pair.into_tuple();
88         match param {
89             GenericParam::Lifetime(param) => {
90                 if !param.bounds.is_empty() && !has_unsupported_generic_param {
91                     let msg = "lifetime parameter with bounds is not supported yet";
92                     cx.error(¶m, msg);
93                     has_unsupported_generic_param = true;
94                 }
95                 lifetimes.push_value(param.lifetime);
96                 if let Some(punct) = punct {
97                     lifetimes.push_punct(punct);
98                 }
99             }
100             GenericParam::Type(param) => {
101                 if !has_unsupported_generic_param {
102                     let msg = "struct with generic type parameter is not supported yet";
103                     cx.error(¶m, msg);
104                     has_unsupported_generic_param = true;
105                 }
106             }
107             GenericParam::Const(param) => {
108                 if !has_unsupported_generic_param {
109                     let msg = "struct with const generic parameter is not supported yet";
110                     cx.error(¶m, msg);
111                     has_unsupported_generic_param = true;
112                 }
113             }
114         }
115     }
116 
117     if let Some(where_clause) = &item.generics.where_clause {
118         cx.error(
119             where_clause,
120             "struct with where-clause is not supported yet",
121         );
122     }
123 
124     let mut fields = Vec::new();
125     for field in named_fields.named {
126         let ident = field.ident.unwrap();
127         let mut doc = Doc::new();
128         let mut cxx_name = None;
129         let mut rust_name = None;
130         let attrs = attrs::parse(
131             cx,
132             field.attrs,
133             attrs::Parser {
134                 doc: Some(&mut doc),
135                 cxx_name: Some(&mut cxx_name),
136                 rust_name: Some(&mut rust_name),
137                 ..Default::default()
138             },
139         );
140         let ty = match parse_type(&field.ty) {
141             Ok(ty) => ty,
142             Err(err) => {
143                 cx.push(err);
144                 continue;
145             }
146         };
147         let visibility = visibility_pub(&field.vis, ident.span());
148         let name = pair(Namespace::default(), &ident, cxx_name, rust_name);
149         let colon_token = field.colon_token.unwrap();
150         fields.push(Var {
151             doc,
152             attrs,
153             visibility,
154             name,
155             colon_token,
156             ty,
157         });
158     }
159 
160     let struct_token = item.struct_token;
161     let visibility = visibility_pub(&item.vis, struct_token.span);
162     let name = pair(namespace, &item.ident, cxx_name, rust_name);
163     let generics = Lifetimes {
164         lt_token: item.generics.lt_token,
165         lifetimes,
166         gt_token: item.generics.gt_token,
167     };
168     let brace_token = named_fields.brace_token;
169 
170     Ok(Api::Struct(Struct {
171         doc,
172         derives,
173         attrs,
174         visibility,
175         struct_token,
176         name,
177         generics,
178         brace_token,
179         fields,
180     }))
181 }
182 
parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api183 fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Api {
184     let mut doc = Doc::new();
185     let mut derives = Vec::new();
186     let mut repr = None;
187     let mut namespace = namespace.clone();
188     let mut cxx_name = None;
189     let mut rust_name = None;
190     let mut variants_from_header = None;
191     let attrs = attrs::parse(
192         cx,
193         item.attrs,
194         attrs::Parser {
195             doc: Some(&mut doc),
196             derives: Some(&mut derives),
197             repr: Some(&mut repr),
198             namespace: Some(&mut namespace),
199             cxx_name: Some(&mut cxx_name),
200             rust_name: Some(&mut rust_name),
201             variants_from_header: Some(&mut variants_from_header),
202             ..Default::default()
203         },
204     );
205 
206     if !item.generics.params.is_empty() {
207         let vis = &item.vis;
208         let enum_token = item.enum_token;
209         let ident = &item.ident;
210         let generics = &item.generics;
211         let span = quote!(#vis #enum_token #ident #generics);
212         cx.error(span, "enum with generic parameters is not supported");
213     } else if let Some(where_clause) = &item.generics.where_clause {
214         cx.error(where_clause, "enum with where-clause is not supported");
215     }
216 
217     let mut variants = Vec::new();
218     let mut discriminants = DiscriminantSet::new(repr);
219     for variant in item.variants {
220         match parse_variant(cx, variant, &mut discriminants) {
221             Ok(variant) => variants.push(variant),
222             Err(err) => cx.push(err),
223         }
224     }
225 
226     let enum_token = item.enum_token;
227     let visibility = visibility_pub(&item.vis, enum_token.span);
228     let brace_token = item.brace_token;
229 
230     let explicit_repr = repr.is_some();
231     let mut repr = U8;
232     match discriminants.inferred_repr() {
233         Ok(inferred) => repr = inferred,
234         Err(err) => {
235             let span = quote_spanned!(brace_token.span=> #enum_token {});
236             cx.error(span, err);
237             variants.clear();
238         }
239     }
240 
241     let name = pair(namespace, &item.ident, cxx_name, rust_name);
242     let repr_ident = Ident::new(repr.as_ref(), Span::call_site());
243     let repr_type = Type::Ident(NamedType::new(repr_ident));
244     let repr = EnumRepr::Native {
245         atom: repr,
246         repr_type,
247     };
248     let generics = Lifetimes {
249         lt_token: None,
250         lifetimes: Punctuated::new(),
251         gt_token: None,
252     };
253     let variants_from_header_attr = variants_from_header;
254     let variants_from_header = variants_from_header_attr.is_some();
255 
256     Api::Enum(Enum {
257         doc,
258         derives,
259         attrs,
260         visibility,
261         enum_token,
262         name,
263         generics,
264         brace_token,
265         variants,
266         variants_from_header,
267         variants_from_header_attr,
268         repr,
269         explicit_repr,
270     })
271 }
272 
parse_variant( cx: &mut Errors, mut variant: RustVariant, discriminants: &mut DiscriminantSet, ) -> Result<Variant>273 fn parse_variant(
274     cx: &mut Errors,
275     mut variant: RustVariant,
276     discriminants: &mut DiscriminantSet,
277 ) -> Result<Variant> {
278     let mut doc = Doc::new();
279     let mut cxx_name = None;
280     let mut rust_name = None;
281     let attrs = attrs::parse(
282         cx,
283         mem::take(&mut variant.attrs),
284         attrs::Parser {
285             doc: Some(&mut doc),
286             cxx_name: Some(&mut cxx_name),
287             rust_name: Some(&mut rust_name),
288             ..Default::default()
289         },
290     );
291 
292     match variant.fields {
293         Fields::Unit => {}
294         _ => {
295             let msg = "enums with data are not supported yet";
296             return Err(Error::new_spanned(variant, msg));
297         }
298     }
299 
300     let expr = variant.discriminant.as_ref().map(|(_, expr)| expr);
301     let try_discriminant = match &expr {
302         Some(lit) => discriminants.insert(lit),
303         None => discriminants.insert_next(),
304     };
305     let discriminant = match try_discriminant {
306         Ok(discriminant) => discriminant,
307         Err(err) => return Err(Error::new_spanned(variant, err)),
308     };
309 
310     let name = pair(Namespace::ROOT, &variant.ident, cxx_name, rust_name);
311     let expr = variant.discriminant.map(|(_, expr)| expr);
312 
313     Ok(Variant {
314         doc,
315         attrs,
316         name,
317         discriminant,
318         expr,
319     })
320 }
321 
parse_foreign_mod( cx: &mut Errors, foreign_mod: ItemForeignMod, out: &mut Vec<Api>, trusted: bool, namespace: &Namespace, )322 fn parse_foreign_mod(
323     cx: &mut Errors,
324     foreign_mod: ItemForeignMod,
325     out: &mut Vec<Api>,
326     trusted: bool,
327     namespace: &Namespace,
328 ) {
329     let lang = match parse_lang(&foreign_mod.abi) {
330         Ok(lang) => lang,
331         Err(err) => return cx.push(err),
332     };
333 
334     match lang {
335         Lang::Rust => {
336             if foreign_mod.unsafety.is_some() {
337                 let unsafety = foreign_mod.unsafety;
338                 let abi = &foreign_mod.abi;
339                 let span = quote!(#unsafety #abi);
340                 cx.error(span, "extern \"Rust\" block does not need to be unsafe");
341             }
342         }
343         Lang::Cxx => {}
344     }
345 
346     let trusted = trusted || foreign_mod.unsafety.is_some();
347 
348     let mut namespace = namespace.clone();
349     attrs::parse(
350         cx,
351         foreign_mod.attrs,
352         attrs::Parser {
353             namespace: Some(&mut namespace),
354             ..Default::default()
355         },
356     );
357 
358     let mut items = Vec::new();
359     for foreign in foreign_mod.items {
360         match foreign {
361             ForeignItem::Type(foreign) => {
362                 let ety = parse_extern_type(cx, foreign, lang, trusted, &namespace);
363                 items.push(ety);
364             }
365             ForeignItem::Fn(foreign) => {
366                 match parse_extern_fn(cx, foreign, lang, trusted, &namespace) {
367                     Ok(efn) => items.push(efn),
368                     Err(err) => cx.push(err),
369                 }
370             }
371             ForeignItem::Macro(foreign) if foreign.mac.path.is_ident("include") => {
372                 match foreign.mac.parse_body_with(parse_include) {
373                     Ok(include) => items.push(Api::Include(include)),
374                     Err(err) => cx.push(err),
375                 }
376             }
377             ForeignItem::Verbatim(tokens) => {
378                 match parse_extern_verbatim(cx, tokens, lang, trusted, &namespace) {
379                     Ok(api) => items.push(api),
380                     Err(err) => cx.push(err),
381                 }
382             }
383             _ => cx.error(foreign, "unsupported foreign item"),
384         }
385     }
386 
387     if !trusted
388         && items.iter().any(|api| match api {
389             Api::CxxFunction(efn) => efn.unsafety.is_none(),
390             _ => false,
391         })
392     {
393         cx.error(
394             foreign_mod.abi,
395             "block must be declared `unsafe extern \"C++\"` if it contains any safe-to-call C++ functions",
396         );
397     }
398 
399     let mut types = items.iter().filter_map(|item| match item {
400         Api::CxxType(ety) | Api::RustType(ety) => Some(&ety.name),
401         Api::TypeAlias(alias) => Some(&alias.name),
402         _ => None,
403     });
404     if let (Some(single_type), None) = (types.next(), types.next()) {
405         let single_type = single_type.clone();
406         for item in &mut items {
407             if let Api::CxxFunction(efn) | Api::RustFunction(efn) = item {
408                 if let Some(receiver) = &mut efn.receiver {
409                     if receiver.ty.rust == "Self" {
410                         receiver.ty.rust = single_type.rust.clone();
411                     }
412                 }
413             }
414         }
415     }
416 
417     out.extend(items);
418 }
419 
parse_lang(abi: &Abi) -> Result<Lang>420 fn parse_lang(abi: &Abi) -> Result<Lang> {
421     let name = match &abi.name {
422         Some(name) => name,
423         None => {
424             return Err(Error::new_spanned(
425                 abi,
426                 "ABI name is required, extern \"C++\" or extern \"Rust\"",
427             ));
428         }
429     };
430 
431     match name.value().as_str() {
432         "C++" => Ok(Lang::Cxx),
433         "Rust" => Ok(Lang::Rust),
434         _ => Err(Error::new_spanned(
435             abi,
436             "unrecognized ABI, requires either \"C++\" or \"Rust\"",
437         )),
438     }
439 }
440 
parse_extern_type( cx: &mut Errors, foreign_type: ForeignItemType, lang: Lang, trusted: bool, namespace: &Namespace, ) -> Api441 fn parse_extern_type(
442     cx: &mut Errors,
443     foreign_type: ForeignItemType,
444     lang: Lang,
445     trusted: bool,
446     namespace: &Namespace,
447 ) -> Api {
448     let mut doc = Doc::new();
449     let mut derives = Vec::new();
450     let mut namespace = namespace.clone();
451     let mut cxx_name = None;
452     let mut rust_name = None;
453     let attrs = attrs::parse(
454         cx,
455         foreign_type.attrs,
456         attrs::Parser {
457             doc: Some(&mut doc),
458             derives: Some(&mut derives),
459             namespace: Some(&mut namespace),
460             cxx_name: Some(&mut cxx_name),
461             rust_name: Some(&mut rust_name),
462             ..Default::default()
463         },
464     );
465 
466     let type_token = foreign_type.type_token;
467     let visibility = visibility_pub(&foreign_type.vis, type_token.span);
468     let name = pair(namespace, &foreign_type.ident, cxx_name, rust_name);
469     let generics = Lifetimes {
470         lt_token: None,
471         lifetimes: Punctuated::new(),
472         gt_token: None,
473     };
474     let colon_token = None;
475     let bounds = Vec::new();
476     let semi_token = foreign_type.semi_token;
477 
478     (match lang {
479         Lang::Cxx => Api::CxxType,
480         Lang::Rust => Api::RustType,
481     })(ExternType {
482         lang,
483         doc,
484         derives,
485         attrs,
486         visibility,
487         type_token,
488         name,
489         generics,
490         colon_token,
491         bounds,
492         semi_token,
493         trusted,
494     })
495 }
496 
parse_extern_fn( cx: &mut Errors, mut foreign_fn: ForeignItemFn, lang: Lang, trusted: bool, namespace: &Namespace, ) -> Result<Api>497 fn parse_extern_fn(
498     cx: &mut Errors,
499     mut foreign_fn: ForeignItemFn,
500     lang: Lang,
501     trusted: bool,
502     namespace: &Namespace,
503 ) -> Result<Api> {
504     let mut doc = Doc::new();
505     let mut namespace = namespace.clone();
506     let mut cxx_name = None;
507     let mut rust_name = None;
508     let attrs = attrs::parse(
509         cx,
510         mem::take(&mut foreign_fn.attrs),
511         attrs::Parser {
512             doc: Some(&mut doc),
513             namespace: Some(&mut namespace),
514             cxx_name: Some(&mut cxx_name),
515             rust_name: Some(&mut rust_name),
516             ..Default::default()
517         },
518     );
519 
520     let generics = &foreign_fn.sig.generics;
521     if generics.where_clause.is_some()
522         || generics.params.iter().any(|param| match param {
523             GenericParam::Lifetime(lifetime) => !lifetime.bounds.is_empty(),
524             GenericParam::Type(_) | GenericParam::Const(_) => true,
525         })
526     {
527         return Err(Error::new_spanned(
528             foreign_fn,
529             "extern function with generic parameters is not supported yet",
530         ));
531     }
532 
533     if let Some(variadic) = &foreign_fn.sig.variadic {
534         return Err(Error::new_spanned(
535             variadic,
536             "variadic function is not supported yet",
537         ));
538     }
539 
540     if foreign_fn.sig.asyncness.is_some() {
541         return Err(Error::new_spanned(
542             foreign_fn,
543             "async function is not directly supported yet, but see https://cxx.rs/async.html for a working approach",
544         ));
545     }
546 
547     if foreign_fn.sig.constness.is_some() {
548         return Err(Error::new_spanned(
549             foreign_fn,
550             "const extern function is not supported",
551         ));
552     }
553 
554     if let Some(abi) = &foreign_fn.sig.abi {
555         return Err(Error::new_spanned(
556             abi,
557             "explicit ABI on extern function is not supported",
558         ));
559     }
560 
561     let mut receiver = None;
562     let mut args = Punctuated::new();
563     for arg in foreign_fn.sig.inputs.pairs() {
564         let (arg, comma) = arg.into_tuple();
565         match arg {
566             FnArg::Receiver(arg) => {
567                 if let Some((ampersand, lifetime)) = &arg.reference {
568                     receiver = Some(Receiver {
569                         pinned: false,
570                         ampersand: *ampersand,
571                         lifetime: lifetime.clone(),
572                         mutable: arg.mutability.is_some(),
573                         var: arg.self_token,
574                         colon_token: Token,
575                         ty: NamedType::new(Ident::new("Self", arg.self_token.span)),
576                         shorthand: true,
577                         pin_tokens: None,
578                         mutability: arg.mutability,
579                     });
580                     continue;
581                 }
582                 return Err(Error::new_spanned(arg, "unsupported signature"));
583             }
584             FnArg::Typed(arg) => {
585                 let ident = match arg.pat.as_ref() {
586                     Pat::Ident(pat) => pat.ident.clone(),
587                     Pat::Wild(pat) => {
588                         Ident::new(&format!("arg{}", args.len()), pat.underscore_token.span)
589                     }
590                     _ => return Err(Error::new_spanned(arg, "unsupported signature")),
591                 };
592                 let ty = parse_type(&arg.ty)?;
593                 if ident != "self" {
594                     let doc = Doc::new();
595                     let attrs = OtherAttrs::none();
596                     let visibility = Token);
597                     let name = pair(Namespace::default(), &ident, None, None);
598                     let colon_token = arg.colon_token;
599                     args.push_value(Var {
600                         doc,
601                         attrs,
602                         visibility,
603                         name,
604                         colon_token,
605                         ty,
606                     });
607                     if let Some(comma) = comma {
608                         args.push_punct(*comma);
609                     }
610                     continue;
611                 }
612                 if let Type::Ref(reference) = ty {
613                     if let Type::Ident(ident) = reference.inner {
614                         receiver = Some(Receiver {
615                             pinned: reference.pinned,
616                             ampersand: reference.ampersand,
617                             lifetime: reference.lifetime,
618                             mutable: reference.mutable,
619                             var: Token),
620                             colon_token: arg.colon_token,
621                             ty: ident,
622                             shorthand: false,
623                             pin_tokens: reference.pin_tokens,
624                             mutability: reference.mutability,
625                         });
626                         continue;
627                     }
628                 }
629                 return Err(Error::new_spanned(arg, "unsupported method receiver"));
630             }
631         }
632     }
633 
634     let mut throws_tokens = None;
635     let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
636     let throws = throws_tokens.is_some();
637     let unsafety = foreign_fn.sig.unsafety;
638     let fn_token = foreign_fn.sig.fn_token;
639     let inherited_span = unsafety.map_or(fn_token.span, |unsafety| unsafety.span);
640     let visibility = visibility_pub(&foreign_fn.vis, inherited_span);
641     let name = pair(namespace, &foreign_fn.sig.ident, cxx_name, rust_name);
642     let generics = generics.clone();
643     let paren_token = foreign_fn.sig.paren_token;
644     let semi_token = foreign_fn.semi_token;
645 
646     Ok(match lang {
647         Lang::Cxx => Api::CxxFunction,
648         Lang::Rust => Api::RustFunction,
649     }(ExternFn {
650         lang,
651         doc,
652         attrs,
653         visibility,
654         name,
655         sig: Signature {
656             unsafety,
657             fn_token,
658             generics,
659             receiver,
660             args,
661             ret,
662             throws,
663             paren_token,
664             throws_tokens,
665         },
666         semi_token,
667         trusted,
668     }))
669 }
670 
parse_extern_verbatim( cx: &mut Errors, tokens: TokenStream, lang: Lang, trusted: bool, namespace: &Namespace, ) -> Result<Api>671 fn parse_extern_verbatim(
672     cx: &mut Errors,
673     tokens: TokenStream,
674     lang: Lang,
675     trusted: bool,
676     namespace: &Namespace,
677 ) -> Result<Api> {
678     |input: ParseStream| -> Result<Api> {
679         let attrs = input.call(Attribute::parse_outer)?;
680         let visibility: Visibility = input.parse()?;
681         if input.peek(Token![type]) {
682             parse_extern_verbatim_type(cx, attrs, visibility, input, lang, trusted, namespace)
683         } else if input.peek(Token![fn]) {
684             parse_extern_verbatim_fn(input)
685         } else {
686             let span = input.cursor().token_stream();
687             Err(Error::new_spanned(
688                 span,
689                 "unsupported foreign item, expected `type` or `fn`",
690             ))
691         }
692     }
693     .parse2(tokens)
694 }
695 
parse_extern_verbatim_type( cx: &mut Errors, attrs: Vec<Attribute>, visibility: Visibility, input: ParseStream, lang: Lang, trusted: bool, namespace: &Namespace, ) -> Result<Api>696 fn parse_extern_verbatim_type(
697     cx: &mut Errors,
698     attrs: Vec<Attribute>,
699     visibility: Visibility,
700     input: ParseStream,
701     lang: Lang,
702     trusted: bool,
703     namespace: &Namespace,
704 ) -> Result<Api> {
705     let type_token: Token![type] = input.parse()?;
706     let ident: Ident = input.parse()?;
707     let generics: Generics = input.parse()?;
708     let mut lifetimes = Punctuated::new();
709     let mut has_unsupported_generic_param = false;
710     for pair in generics.params.into_pairs() {
711         let (param, punct) = pair.into_tuple();
712         match param {
713             GenericParam::Lifetime(param) => {
714                 if !param.bounds.is_empty() && !has_unsupported_generic_param {
715                     let msg = "lifetime parameter with bounds is not supported yet";
716                     cx.error(¶m, msg);
717                     has_unsupported_generic_param = true;
718                 }
719                 lifetimes.push_value(param.lifetime);
720                 if let Some(punct) = punct {
721                     lifetimes.push_punct(punct);
722                 }
723             }
724             GenericParam::Type(param) => {
725                 if !has_unsupported_generic_param {
726                     let msg = "extern type with generic type parameter is not supported yet";
727                     cx.error(¶m, msg);
728                     has_unsupported_generic_param = true;
729                 }
730             }
731             GenericParam::Const(param) => {
732                 if !has_unsupported_generic_param {
733                     let msg = "extern type with const generic parameter is not supported yet";
734                     cx.error(¶m, msg);
735                     has_unsupported_generic_param = true;
736                 }
737             }
738         }
739     }
740     let lifetimes = Lifetimes {
741         lt_token: generics.lt_token,
742         lifetimes,
743         gt_token: generics.gt_token,
744     };
745     let lookahead = input.lookahead1();
746     if lookahead.peek(Token![=]) {
747         // type Alias = crate::path::to::Type;
748         parse_type_alias(
749             cx, attrs, visibility, type_token, ident, lifetimes, input, lang, namespace,
750         )
751     } else if lookahead.peek(Token![:]) || lookahead.peek(Token![;]) {
752         // type Opaque: Bound2 + Bound2;
753         parse_extern_type_bounded(
754             cx, attrs, visibility, type_token, ident, lifetimes, input, lang, trusted, namespace,
755         )
756     } else {
757         Err(lookahead.error())
758     }
759 }
760 
parse_extern_verbatim_fn(input: ParseStream) -> Result<Api>761 fn parse_extern_verbatim_fn(input: ParseStream) -> Result<Api> {
762     input.parse::<RustSignature>()?;
763     input.parse::<Token![;]>()?;
764     unreachable!()
765 }
766 
parse_type_alias( cx: &mut Errors, attrs: Vec<Attribute>, visibility: Visibility, type_token: Token![type], ident: Ident, generics: Lifetimes, input: ParseStream, lang: Lang, namespace: &Namespace, ) -> Result<Api>767 fn parse_type_alias(
768     cx: &mut Errors,
769     attrs: Vec<Attribute>,
770     visibility: Visibility,
771     type_token: Token![type],
772     ident: Ident,
773     generics: Lifetimes,
774     input: ParseStream,
775     lang: Lang,
776     namespace: &Namespace,
777 ) -> Result<Api> {
778     let eq_token: Token![=] = input.parse()?;
779     let ty: RustType = input.parse()?;
780     let semi_token: Token![;] = input.parse()?;
781 
782     let mut doc = Doc::new();
783     let mut derives = Vec::new();
784     let mut namespace = namespace.clone();
785     let mut cxx_name = None;
786     let mut rust_name = None;
787     let attrs = attrs::parse(
788         cx,
789         attrs,
790         attrs::Parser {
791             doc: Some(&mut doc),
792             derives: Some(&mut derives),
793             namespace: Some(&mut namespace),
794             cxx_name: Some(&mut cxx_name),
795             rust_name: Some(&mut rust_name),
796             ..Default::default()
797         },
798     );
799 
800     if lang == Lang::Rust {
801         let span = quote!(#type_token #semi_token);
802         let msg = "type alias in extern \"Rust\" block is not supported";
803         return Err(Error::new_spanned(span, msg));
804     }
805 
806     let visibility = visibility_pub(&visibility, type_token.span);
807     let name = pair(namespace, &ident, cxx_name, rust_name);
808 
809     Ok(Api::TypeAlias(TypeAlias {
810         doc,
811         derives,
812         attrs,
813         visibility,
814         type_token,
815         name,
816         generics,
817         eq_token,
818         ty,
819         semi_token,
820     }))
821 }
822 
parse_extern_type_bounded( cx: &mut Errors, attrs: Vec<Attribute>, visibility: Visibility, type_token: Token![type], ident: Ident, generics: Lifetimes, input: ParseStream, lang: Lang, trusted: bool, namespace: &Namespace, ) -> Result<Api>823 fn parse_extern_type_bounded(
824     cx: &mut Errors,
825     attrs: Vec<Attribute>,
826     visibility: Visibility,
827     type_token: Token![type],
828     ident: Ident,
829     generics: Lifetimes,
830     input: ParseStream,
831     lang: Lang,
832     trusted: bool,
833     namespace: &Namespace,
834 ) -> Result<Api> {
835     let mut bounds = Vec::new();
836     let colon_token: Option<Token![:]> = input.parse()?;
837     if colon_token.is_some() {
838         loop {
839             match input.parse()? {
840                 TypeParamBound::Trait(TraitBound {
841                     paren_token: None,
842                     modifier: TraitBoundModifier::None,
843                     lifetimes: None,
844                     path,
845                 }) if if let Some(derive) = path.get_ident().and_then(Derive::from) {
846                     bounds.push(derive);
847                     true
848                 } else {
849                     false
850                 } => {}
851                 bound @ TypeParamBound::Trait(_) | bound @ TypeParamBound::Lifetime(_) => {
852                     cx.error(bound, "unsupported trait");
853                 }
854             }
855 
856             let lookahead = input.lookahead1();
857             if lookahead.peek(Token![+]) {
858                 input.parse::<Token![+]>()?;
859             } else if lookahead.peek(Token![;]) {
860                 break;
861             } else {
862                 return Err(lookahead.error());
863             }
864         }
865     }
866     let semi_token: Token![;] = input.parse()?;
867 
868     let mut doc = Doc::new();
869     let mut derives = Vec::new();
870     let mut namespace = namespace.clone();
871     let mut cxx_name = None;
872     let mut rust_name = None;
873     let attrs = attrs::parse(
874         cx,
875         attrs,
876         attrs::Parser {
877             doc: Some(&mut doc),
878             derives: Some(&mut derives),
879             namespace: Some(&mut namespace),
880             cxx_name: Some(&mut cxx_name),
881             rust_name: Some(&mut rust_name),
882             ..Default::default()
883         },
884     );
885 
886     let visibility = visibility_pub(&visibility, type_token.span);
887     let name = pair(namespace, &ident, cxx_name, rust_name);
888 
889     Ok(match lang {
890         Lang::Cxx => Api::CxxType,
891         Lang::Rust => Api::RustType,
892     }(ExternType {
893         lang,
894         doc,
895         derives,
896         attrs,
897         visibility,
898         type_token,
899         name,
900         generics,
901         colon_token,
902         bounds,
903         semi_token,
904         trusted,
905     }))
906 }
907 
parse_impl(imp: ItemImpl) -> Result<Api>908 fn parse_impl(imp: ItemImpl) -> Result<Api> {
909     let impl_token = imp.impl_token;
910 
911     if !imp.items.is_empty() {
912         let mut span = Group::new(Delimiter::Brace, TokenStream::new());
913         span.set_span(imp.brace_token.span);
914         return Err(Error::new_spanned(span, "expected an empty impl block"));
915     }
916 
917     if let Some((bang, path, for_token)) = &imp.trait_ {
918         let self_ty = &imp.self_ty;
919         let span = quote!(#bang #path #for_token #self_ty);
920         return Err(Error::new_spanned(
921             span,
922             "unexpected impl, expected something like `impl UniquePtr<T> {}`",
923         ));
924     }
925 
926     if let Some(where_clause) = imp.generics.where_clause {
927         return Err(Error::new_spanned(
928             where_clause,
929             "where-clause on an impl is not supported yet",
930         ));
931     }
932     let mut impl_generics = Lifetimes {
933         lt_token: imp.generics.lt_token,
934         lifetimes: Punctuated::new(),
935         gt_token: imp.generics.gt_token,
936     };
937     for pair in imp.generics.params.into_pairs() {
938         let (param, punct) = pair.into_tuple();
939         match param {
940             GenericParam::Lifetime(def) if def.bounds.is_empty() => {
941                 impl_generics.lifetimes.push_value(def.lifetime);
942                 if let Some(punct) = punct {
943                     impl_generics.lifetimes.push_punct(punct);
944                 }
945             }
946             _ => {
947                 let span = quote!(#impl_token #impl_generics);
948                 return Err(Error::new_spanned(
949                     span,
950                     "generic parameter on an impl is not supported yet",
951                 ));
952             }
953         }
954     }
955 
956     let mut negative_token = None;
957     let mut self_ty = *imp.self_ty;
958     if let RustType::Verbatim(ty) = &self_ty {
959         let mut iter = ty.clone().into_iter();
960         if let Some(TokenTree::Punct(punct)) = iter.next() {
961             if punct.as_char() == '!' {
962                 let ty = iter.collect::<TokenStream>();
963                 if !ty.is_empty() {
964                     negative_token = Some(Token));
965                     self_ty = syn::parse2(ty)?;
966                 }
967             }
968         }
969     }
970 
971     let ty = parse_type(&self_ty)?;
972     let ty_generics = match &ty {
973         Type::RustBox(ty)
974         | Type::RustVec(ty)
975         | Type::UniquePtr(ty)
976         | Type::SharedPtr(ty)
977         | Type::WeakPtr(ty)
978         | Type::CxxVector(ty) => match &ty.inner {
979             Type::Ident(ident) => ident.generics.clone(),
980             _ => Lifetimes::default(),
981         },
982         Type::Ident(_)
983         | Type::Ref(_)
984         | Type::Ptr(_)
985         | Type::Str(_)
986         | Type::Fn(_)
987         | Type::Void(_)
988         | Type::SliceRef(_)
989         | Type::Array(_) => Lifetimes::default(),
990     };
991 
992     let negative = negative_token.is_some();
993     let brace_token = imp.brace_token;
994 
995     Ok(Api::Impl(Impl {
996         impl_token,
997         impl_generics,
998         negative,
999         ty,
1000         ty_generics,
1001         brace_token,
1002         negative_token,
1003     }))
1004 }
1005 
parse_include(input: ParseStream) -> Result<Include>1006 fn parse_include(input: ParseStream) -> Result<Include> {
1007     if input.peek(LitStr) {
1008         let lit: LitStr = input.parse()?;
1009         let span = lit.span();
1010         return Ok(Include {
1011             path: lit.value(),
1012             kind: IncludeKind::Quoted,
1013             begin_span: span,
1014             end_span: span,
1015         });
1016     }
1017 
1018     if input.peek(Token![<]) {
1019         let mut path = String::new();
1020 
1021         let langle: Token![<] = input.parse()?;
1022         while !input.is_empty() && !input.peek(Token![>]) {
1023             let token: TokenTree = input.parse()?;
1024             match token {
1025                 TokenTree::Ident(token) => path += &token.to_string(),
1026                 TokenTree::Literal(token)
1027                     if token
1028                         .to_string()
1029                         .starts_with(|ch: char| ch.is_ascii_digit()) =>
1030                 {
1031                     path += &token.to_string();
1032                 }
1033                 TokenTree::Punct(token) => path.push(token.as_char()),
1034                 _ => return Err(Error::new(token.span(), "unexpected token in include path")),
1035             }
1036         }
1037         let rangle: Token![>] = input.parse()?;
1038 
1039         return Ok(Include {
1040             path,
1041             kind: IncludeKind::Bracketed,
1042             begin_span: langle.span,
1043             end_span: rangle.span,
1044         });
1045     }
1046 
1047     Err(input.error("expected \"quoted/path/to\" or <bracketed/path/to>"))
1048 }
1049 
parse_type(ty: &RustType) -> Result<Type>1050 fn parse_type(ty: &RustType) -> Result<Type> {
1051     match ty {
1052         RustType::Reference(ty) => parse_type_reference(ty),
1053         RustType::Ptr(ty) => parse_type_ptr(ty),
1054         RustType::Path(ty) => parse_type_path(ty),
1055         RustType::Array(ty) => parse_type_array(ty),
1056         RustType::BareFn(ty) => parse_type_fn(ty),
1057         RustType::Tuple(ty) if ty.elems.is_empty() => Ok(Type::Void(ty.paren_token.span)),
1058         _ => Err(Error::new_spanned(ty, "unsupported type")),
1059     }
1060 }
1061 
parse_type_reference(ty: &TypeReference) -> Result<Type>1062 fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
1063     let ampersand = ty.and_token;
1064     let lifetime = ty.lifetime.clone();
1065     let mutable = ty.mutability.is_some();
1066     let mutability = ty.mutability;
1067 
1068     if let RustType::Slice(slice) = ty.elem.as_ref() {
1069         let inner = parse_type(&slice.elem)?;
1070         let bracket = slice.bracket_token;
1071         return Ok(Type::SliceRef(Box::new(SliceRef {
1072             ampersand,
1073             lifetime,
1074             mutable,
1075             bracket,
1076             inner,
1077             mutability,
1078         })));
1079     }
1080 
1081     let inner = parse_type(&ty.elem)?;
1082     let pinned = false;
1083     let pin_tokens = None;
1084 
1085     Ok(match &inner {
1086         Type::Ident(ident) if ident.rust == "str" => {
1087             if ty.mutability.is_some() {
1088                 return Err(Error::new_spanned(ty, "unsupported type"));
1089             } else {
1090                 Type::Str
1091             }
1092         }
1093         _ => Type::Ref,
1094     }(Box::new(Ref {
1095         pinned,
1096         ampersand,
1097         lifetime,
1098         mutable,
1099         inner,
1100         pin_tokens,
1101         mutability,
1102     })))
1103 }
1104 
parse_type_ptr(ty: &TypePtr) -> Result<Type>1105 fn parse_type_ptr(ty: &TypePtr) -> Result<Type> {
1106     let star = ty.star_token;
1107     let mutable = ty.mutability.is_some();
1108     let constness = ty.const_token;
1109     let mutability = ty.mutability;
1110 
1111     let inner = parse_type(&ty.elem)?;
1112 
1113     Ok(Type::Ptr(Box::new(Ptr {
1114         star,
1115         mutable,
1116         inner,
1117         mutability,
1118         constness,
1119     })))
1120 }
1121 
parse_type_path(ty: &TypePath) -> Result<Type>1122 fn parse_type_path(ty: &TypePath) -> Result<Type> {
1123     let path = &ty.path;
1124     if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
1125         let segment = &path.segments[0];
1126         let ident = segment.ident.clone();
1127         match &segment.arguments {
1128             PathArguments::None => return Ok(Type::Ident(NamedType::new(ident))),
1129             PathArguments::AngleBracketed(generic) => {
1130                 if ident == "UniquePtr" && generic.args.len() == 1 {
1131                     if let GenericArgument::Type(arg) = &generic.args[0] {
1132                         let inner = parse_type(arg)?;
1133                         return Ok(Type::UniquePtr(Box::new(Ty1 {
1134                             name: ident,
1135                             langle: generic.lt_token,
1136                             inner,
1137                             rangle: generic.gt_token,
1138                         })));
1139                     }
1140                 } else if ident == "SharedPtr" && generic.args.len() == 1 {
1141                     if let GenericArgument::Type(arg) = &generic.args[0] {
1142                         let inner = parse_type(arg)?;
1143                         return Ok(Type::SharedPtr(Box::new(Ty1 {
1144                             name: ident,
1145                             langle: generic.lt_token,
1146                             inner,
1147                             rangle: generic.gt_token,
1148                         })));
1149                     }
1150                 } else if ident == "WeakPtr" && generic.args.len() == 1 {
1151                     if let GenericArgument::Type(arg) = &generic.args[0] {
1152                         let inner = parse_type(arg)?;
1153                         return Ok(Type::WeakPtr(Box::new(Ty1 {
1154                             name: ident,
1155                             langle: generic.lt_token,
1156                             inner,
1157                             rangle: generic.gt_token,
1158                         })));
1159                     }
1160                 } else if ident == "CxxVector" && generic.args.len() == 1 {
1161                     if let GenericArgument::Type(arg) = &generic.args[0] {
1162                         let inner = parse_type(arg)?;
1163                         return Ok(Type::CxxVector(Box::new(Ty1 {
1164                             name: ident,
1165                             langle: generic.lt_token,
1166                             inner,
1167                             rangle: generic.gt_token,
1168                         })));
1169                     }
1170                 } else if ident == "Box" && generic.args.len() == 1 {
1171                     if let GenericArgument::Type(arg) = &generic.args[0] {
1172                         let inner = parse_type(arg)?;
1173                         return Ok(Type::RustBox(Box::new(Ty1 {
1174                             name: ident,
1175                             langle: generic.lt_token,
1176                             inner,
1177                             rangle: generic.gt_token,
1178                         })));
1179                     }
1180                 } else if ident == "Vec" && generic.args.len() == 1 {
1181                     if let GenericArgument::Type(arg) = &generic.args[0] {
1182                         let inner = parse_type(arg)?;
1183                         return Ok(Type::RustVec(Box::new(Ty1 {
1184                             name: ident,
1185                             langle: generic.lt_token,
1186                             inner,
1187                             rangle: generic.gt_token,
1188                         })));
1189                     }
1190                 } else if ident == "Pin" && generic.args.len() == 1 {
1191                     if let GenericArgument::Type(arg) = &generic.args[0] {
1192                         let inner = parse_type(arg)?;
1193                         let pin_token = kw::Pin(ident.span());
1194                         if let Type::Ref(mut inner) = inner {
1195                             inner.pinned = true;
1196                             inner.pin_tokens =
1197                                 Some((pin_token, generic.lt_token, generic.gt_token));
1198                             return Ok(Type::Ref(inner));
1199                         }
1200                     }
1201                 } else {
1202                     let mut lifetimes = Punctuated::new();
1203                     let mut only_lifetimes = true;
1204                     for pair in generic.args.pairs() {
1205                         let (param, punct) = pair.into_tuple();
1206                         if let GenericArgument::Lifetime(param) = param {
1207                             lifetimes.push_value(param.clone());
1208                             if let Some(punct) = punct {
1209                                 lifetimes.push_punct(*punct);
1210                             }
1211                         } else {
1212                             only_lifetimes = false;
1213                             break;
1214                         }
1215                     }
1216                     if only_lifetimes {
1217                         return Ok(Type::Ident(NamedType {
1218                             rust: ident,
1219                             generics: Lifetimes {
1220                                 lt_token: Some(generic.lt_token),
1221                                 lifetimes,
1222                                 gt_token: Some(generic.gt_token),
1223                             },
1224                         }));
1225                     }
1226                 }
1227             }
1228             PathArguments::Parenthesized(_) => {}
1229         }
1230     }
1231 
1232     Err(Error::new_spanned(ty, "unsupported type"))
1233 }
1234 
parse_type_array(ty: &TypeArray) -> Result<Type>1235 fn parse_type_array(ty: &TypeArray) -> Result<Type> {
1236     let inner = parse_type(&ty.elem)?;
1237 
1238     let len_expr = if let Expr::Lit(lit) = &ty.len {
1239         lit
1240     } else {
1241         let msg = "unsupported expression, array length must be an integer literal";
1242         return Err(Error::new_spanned(&ty.len, msg));
1243     };
1244 
1245     let len_token = if let Lit::Int(int) = &len_expr.lit {
1246         int.clone()
1247     } else {
1248         let msg = "array length must be an integer literal";
1249         return Err(Error::new_spanned(len_expr, msg));
1250     };
1251 
1252     let len = len_token.base10_parse::<usize>()?;
1253     if len == 0 {
1254         let msg = "array with zero size is not supported";
1255         return Err(Error::new_spanned(ty, msg));
1256     }
1257 
1258     let bracket = ty.bracket_token;
1259     let semi_token = ty.semi_token;
1260 
1261     Ok(Type::Array(Box::new(Array {
1262         bracket,
1263         inner,
1264         semi_token,
1265         len,
1266         len_token,
1267     })))
1268 }
1269 
parse_type_fn(ty: &TypeBareFn) -> Result<Type>1270 fn parse_type_fn(ty: &TypeBareFn) -> Result<Type> {
1271     if ty.lifetimes.is_some() {
1272         return Err(Error::new_spanned(
1273             ty,
1274             "function pointer with lifetime parameters is not supported yet",
1275         ));
1276     }
1277 
1278     if ty.variadic.is_some() {
1279         return Err(Error::new_spanned(
1280             ty,
1281             "variadic function pointer is not supported yet",
1282         ));
1283     }
1284 
1285     let args = ty
1286         .inputs
1287         .iter()
1288         .enumerate()
1289         .map(|(i, arg)| {
1290             let (ident, colon_token) = match &arg.name {
1291                 Some((ident, colon_token)) => (ident.clone(), *colon_token),
1292                 None => {
1293                     let fn_span = ty.paren_token.span;
1294                     let ident = format_ident!("arg{}", i, span = fn_span);
1295                     let colon_token = Token;
1296                     (ident, colon_token)
1297                 }
1298             };
1299             let ty = parse_type(&arg.ty)?;
1300             let doc = Doc::new();
1301             let attrs = OtherAttrs::none();
1302             let visibility = Token);
1303             let name = pair(Namespace::default(), &ident, None, None);
1304             Ok(Var {
1305                 doc,
1306                 attrs,
1307                 visibility,
1308                 name,
1309                 colon_token,
1310                 ty,
1311             })
1312         })
1313         .collect::<Result<_>>()?;
1314 
1315     let mut throws_tokens = None;
1316     let ret = parse_return_type(&ty.output, &mut throws_tokens)?;
1317     let throws = throws_tokens.is_some();
1318 
1319     let unsafety = ty.unsafety;
1320     let fn_token = ty.fn_token;
1321     let generics = Generics::default();
1322     let receiver = None;
1323     let paren_token = ty.paren_token;
1324 
1325     Ok(Type::Fn(Box::new(Signature {
1326         unsafety,
1327         fn_token,
1328         generics,
1329         receiver,
1330         args,
1331         ret,
1332         throws,
1333         paren_token,
1334         throws_tokens,
1335     })))
1336 }
1337 
parse_return_type( ty: &ReturnType, throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>, ) -> Result<Option<Type>>1338 fn parse_return_type(
1339     ty: &ReturnType,
1340     throws_tokens: &mut Option<(kw::Result, Token![<], Token![>])>,
1341 ) -> Result<Option<Type>> {
1342     let mut ret = match ty {
1343         ReturnType::Default => return Ok(None),
1344         ReturnType::Type(_, ret) => ret.as_ref(),
1345     };
1346 
1347     if let RustType::Path(ty) = ret {
1348         let path = &ty.path;
1349         if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
1350             let segment = &path.segments[0];
1351             let ident = segment.ident.clone();
1352             if let PathArguments::AngleBracketed(generic) = &segment.arguments {
1353                 if ident == "Result" && generic.args.len() == 1 {
1354                     if let GenericArgument::Type(arg) = &generic.args[0] {
1355                         ret = arg;
1356                         *throws_tokens =
1357                             Some((kw::Result(ident.span()), generic.lt_token, generic.gt_token));
1358                     }
1359                 }
1360             }
1361         }
1362     }
1363 
1364     match parse_type(ret)? {
1365         Type::Void(_) => Ok(None),
1366         ty => Ok(Some(ty)),
1367     }
1368 }
1369 
visibility_pub(vis: &Visibility, inherited: Span) -> Token![pub]1370 fn visibility_pub(vis: &Visibility, inherited: Span) -> Token![pub] {
1371     Token => vis.pub_token.span,
1373         Visibility::Crate(vis) => vis.crate_token.span,
1374         Visibility::Restricted(vis) => vis.pub_token.span,
1375         Visibility::Inherited => inherited,
1376     })
1377 }
1378 
pair( namespace: Namespace, default: &Ident, cxx: Option<ForeignName>, rust: Option<Ident>, ) -> Pair1379 fn pair(
1380     namespace: Namespace,
1381     default: &Ident,
1382     cxx: Option<ForeignName>,
1383     rust: Option<Ident>,
1384 ) -> Pair {
1385     Pair {
1386         namespace,
1387         cxx: cxx
1388             .unwrap_or_else(|| ForeignName::parse(&default.to_string(), default.span()).unwrap()),
1389         rust: rust.unwrap_or_else(|| default.clone()),
1390     }
1391 }
1392