1 // compile-flags: --emit=link
2 // no-prefer-dynamic
3 
4 #![crate_type = "proc-macro"]
5 #![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
6 #![allow(incomplete_features)]
7 #![allow(clippy::useless_conversion)]
8 
9 extern crate proc_macro;
10 extern crate quote;
11 extern crate syn;
12 
13 use proc_macro::TokenStream;
14 use quote::{quote, quote_spanned};
15 use syn::parse_macro_input;
16 use syn::spanned::Spanned;
17 use syn::token::Star;
18 use syn::{
19     parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type,
20 };
21 
22 #[proc_macro_attribute]
fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream23 pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
24     let mut item = parse_macro_input!(input as ItemTrait);
25     for inner in &mut item.items {
26         if let TraitItem::Method(method) = inner {
27             let sig = &method.sig;
28             let block = &mut method.default;
29             if let Some(block) = block {
30                 let brace = block.brace_token;
31 
32                 let my_block = quote_spanned!( brace.span => {
33                     // Should not trigger `empty_line_after_outer_attr`
34                     #[crate_type = "lib"]
35                     #sig #block
36                     Vec::new()
37                 });
38                 *block = parse_quote!(#my_block);
39             }
40         }
41     }
42     TokenStream::from(quote!(#item))
43 }
44 
45 #[proc_macro_attribute]
rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream46 pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream {
47     fn make_name(count: usize) -> String {
48         format!("'life{}", count)
49     }
50 
51     fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> {
52         let arg = sig.inputs.first_mut()?;
53         if let FnArg::Typed(PatType { pat, .. }) = arg {
54             if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
55                 if ident == "self" {
56                     return Some(arg);
57                 }
58             }
59         }
60         None
61     }
62 
63     let mut elided = 0;
64     let mut item = parse_macro_input!(input as ItemImpl);
65 
66     // Look for methods having arbitrary self type taken by &mut ref
67     for inner in &mut item.items {
68         if let ImplItem::Method(method) = inner {
69             if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) {
70                 if let box Type::Reference(reference) = &mut pat_type.ty {
71                     // Target only unnamed lifetimes
72                     let name = match &reference.lifetime {
73                         Some(lt) if lt.ident == "_" => make_name(elided),
74                         None => make_name(elided),
75                         _ => continue,
76                     };
77                     elided += 1;
78 
79                     // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
80                     // In order to avoid adding the dependency, get a default span from a non-existent token.
81                     // A default span is needed to mark the code as coming from expansion.
82                     let span = Star::default().span();
83 
84                     // Replace old lifetime with the named one
85                     let lifetime = Lifetime::new(&name, span);
86                     reference.lifetime = Some(parse_quote!(#lifetime));
87 
88                     // Add lifetime to the generics of the method
89                     method.sig.generics.params.push(parse_quote!(#lifetime));
90                 }
91             }
92         }
93     }
94 
95     TokenStream::from(quote!(#item))
96 }
97