| // compile-flags: --emit=link |
| // no-prefer-dynamic |
| |
| #![crate_type = "proc-macro"] |
| #![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] |
| #![allow(incomplete_features)] |
| #![allow(clippy::useless_conversion)] |
| |
| extern crate proc_macro; |
| extern crate quote; |
| extern crate syn; |
| |
| use proc_macro::TokenStream; |
| use quote::{quote, quote_spanned}; |
| use syn::parse_macro_input; |
| use syn::spanned::Spanned; |
| use syn::token::Star; |
| use syn::{ |
| parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type, |
| }; |
| |
| #[proc_macro_attribute] |
| pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream { |
| let mut item = parse_macro_input!(input as ItemTrait); |
| for inner in &mut item.items { |
| if let TraitItem::Method(method) = inner { |
| let sig = &method.sig; |
| let block = &mut method.default; |
| if let Some(block) = block { |
| let brace = block.brace_token; |
| |
| let my_block = quote_spanned!( brace.span => { |
| // Should not trigger `empty_line_after_outer_attr` |
| #[crate_type = "lib"] |
| #sig #block |
| Vec::new() |
| }); |
| *block = parse_quote!(#my_block); |
| } |
| } |
| } |
| TokenStream::from(quote!(#item)) |
| } |
| |
| #[proc_macro_attribute] |
| pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream { |
| fn make_name(count: usize) -> String { |
| format!("'life{}", count) |
| } |
| |
| fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> { |
| let arg = sig.inputs.first_mut()?; |
| if let FnArg::Typed(PatType { pat, .. }) = arg { |
| if let Pat::Ident(PatIdent { ident, .. }) = &**pat { |
| if ident == "self" { |
| return Some(arg); |
| } |
| } |
| } |
| None |
| } |
| |
| let mut elided = 0; |
| let mut item = parse_macro_input!(input as ItemImpl); |
| |
| // Look for methods having arbitrary self type taken by &mut ref |
| for inner in &mut item.items { |
| if let ImplItem::Method(method) = inner { |
| if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) { |
| if let box Type::Reference(reference) = &mut pat_type.ty { |
| // Target only unnamed lifetimes |
| let name = match &reference.lifetime { |
| Some(lt) if lt.ident == "_" => make_name(elided), |
| None => make_name(elided), |
| _ => continue, |
| }; |
| elided += 1; |
| |
| // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it. |
| // In order to avoid adding the dependency, get a default span from a non-existent token. |
| // A default span is needed to mark the code as coming from expansion. |
| let span = Star::default().span(); |
| |
| // Replace old lifetime with the named one |
| let lifetime = Lifetime::new(&name, span); |
| reference.lifetime = Some(parse_quote!(#lifetime)); |
| |
| // Add lifetime to the generics of the method |
| method.sig.generics.params.push(parse_quote!(#lifetime)); |
| } |
| } |
| } |
| } |
| |
| TokenStream::from(quote!(#item)) |
| } |