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