/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs

https://gitlab.com/rust-lang/rust · Rust · 101 lines · 77 code · 14 blank · 10 comment · 14 complexity · e52da7db8dc58af6ea8c2f250102d2a4 MD5 · raw file

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