1 //! A procedural macro attribute for instrumenting functions with [`tracing`].
2 //!
3 //! [`tracing`] is a framework for instrumenting Rust programs to collect
4 //! structured, event-based diagnostic information. This crate provides the
5 //! [`#[instrument]`][instrument] procedural macro attribute.
6 //!
7 //! Note that this macro is also re-exported by the main `tracing` crate.
8 //!
9 //! *Compiler support: [requires `rustc` 1.42+][msrv]*
10 //!
11 //! [msrv]: #supported-rust-versions
12 //!
13 //! ## Usage
14 //!
15 //! First, add this to your `Cargo.toml`:
16 //!
17 //! ```toml
18 //! [dependencies]
19 //! tracing-attributes = "0.1.16"
20 //! ```
21 //!
22 //! The [`#[instrument]`][instrument] attribute can now be added to a function
23 //! to automatically create and enter `tracing` [span] when that function is
24 //! called. For example:
25 //!
26 //! ```
27 //! use tracing_attributes::instrument;
28 //!
29 //! #[instrument]
30 //! pub fn my_function(my_arg: usize) {
31 //!     // ...
32 //! }
33 //!
34 //! # fn main() {}
35 //! ```
36 //!
37 //! [`tracing`]: https://crates.io/crates/tracing
38 //! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
39 //! [instrument]: attr.instrument.html
40 //!
41 //! ## Supported Rust Versions
42 //!
43 //! Tracing is built against the latest stable release. The minimum supported
44 //! version is 1.42. The current Tracing version is not guaranteed to build on
45 //! Rust versions earlier than the minimum supported version.
46 //!
47 //! Tracing follows the same compiler support policies as the rest of the Tokio
48 //! project. The current stable Rust compiler and the three most recent minor
49 //! versions before it will always be supported. For example, if the current
50 //! stable compiler version is 1.45, the minimum supported version will not be
51 //! increased past 1.42, three minor versions prior. Increasing the minimum
52 //! supported compiler version is not considered a semver breaking change as
53 //! long as doing so complies with this policy.
54 //!
55 #![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.16")]
56 #![doc(
57     html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
58     issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
59 )]
60 #![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
61 #![warn(
62     missing_debug_implementations,
63     missing_docs,
64     rust_2018_idioms,
65     unreachable_pub,
66     bad_style,
67     const_err,
68     dead_code,
69     improper_ctypes,
70     non_shorthand_field_patterns,
71     no_mangle_generic_items,
72     overflowing_literals,
73     path_statements,
74     patterns_in_fns_without_body,
75     private_in_public,
76     unconditional_recursion,
77     unused_allocation,
78     unused_comparisons,
79     unused_parens,
80     while_true
81 )]
82 // TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
83 #![allow(unused)]
84 extern crate proc_macro;
85 
86 use std::collections::{HashMap, HashSet};
87 use std::iter;
88 
89 use proc_macro2::TokenStream;
90 use quote::{quote, quote_spanned, ToTokens, TokenStreamExt as _};
91 use syn::ext::IdentExt as _;
92 use syn::parse::{Parse, ParseStream};
93 use syn::{
94     punctuated::Punctuated, spanned::Spanned, Block, Expr, ExprAsync, ExprCall, FieldPat, FnArg,
95     Ident, Item, ItemFn, LitInt, LitStr, Pat, PatIdent, PatReference, PatStruct, PatTuple,
96     PatTupleStruct, PatType, Path, Signature, Stmt, Token, TypePath,
97 };
98 /// Instruments a function to create and enter a `tracing` [span] every time
99 /// the function is called.
100 ///
101 /// Unless overriden, a span with `info` level will be generated.
102 /// The generated span's name will be the name of the function.
103 /// By default, all arguments to the function are included as fields on the
104 /// span. Arguments that are `tracing` [primitive types] implementing the
105 /// [`Value` trait] will be recorded as fields of that type. Types which do
106 /// not implement `Value` will be recorded using [`std::fmt::Debug`].
107 ///
108 /// [primitive types]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html#foreign-impls
109 /// [`Value` trait]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html.
110 ///
111 /// # Overriding Span Attributes
112 ///
113 /// To change the [name] of the generated span, add a `name` argument to the
114 /// `#[instrument]` macro, followed by an equals sign and a string literal. For
115 /// example:
116 ///
117 /// ```
118 /// # use tracing_attributes::instrument;
119 ///
120 /// // The generated span's name will be "my_span" rather than "my_function".
121 /// #[instrument(name = "my_span")]
122 /// pub fn my_function() {
123 ///     // ... do something incredibly interesting and important ...
124 /// }
125 /// ```
126 ///
127 /// To override the [target] of the generated span, add a `target` argument to
128 /// the `#[instrument]` macro, followed by an equals sign and a string literal
129 /// for the new target. The [module path] is still recorded separately. For
130 /// example:
131 ///
132 /// ```
133 /// pub mod my_module {
134 ///     # use tracing_attributes::instrument;
135 ///     // The generated span's target will be "my_crate::some_special_target",
136 ///     // rather than "my_crate::my_module".
137 ///     #[instrument(target = "my_crate::some_special_target")]
138 ///     pub fn my_function() {
139 ///         // ... all kinds of neat code in here ...
140 ///     }
141 /// }
142 /// ```
143 ///
144 /// Finally, to override the [level] of the generated span, add a `level`
145 /// argument, followed by an equals sign and a string literal with the name of
146 /// the desired level. Level names are not case sensitive. For example:
147 ///
148 /// ```
149 /// # use tracing_attributes::instrument;
150 /// // The span's level will be TRACE rather than INFO.
151 /// #[instrument(level = "trace")]
152 /// pub fn my_function() {
153 ///     // ... I have written a truly marvelous implementation of this function,
154 ///     // which this example is too narrow to contain ...
155 /// }
156 /// ```
157 ///
158 /// # Skipping Fields
159 ///
160 /// To skip recording one or more arguments to a function or method, pass
161 /// the argument's name inside the `skip()` argument on the `#[instrument]`
162 /// macro. This can be used when an argument to an instrumented function does
163 /// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
164 /// costly `Debug` implementation. Note that:
165 ///
166 /// - multiple argument names can be passed to `skip`.
167 /// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
168 ///
169 /// You can also use `skip_all` to skip all arguments.
170 ///
171 /// ## Examples
172 ///
173 /// ```
174 /// # use tracing_attributes::instrument;
175 /// # use std::collections::HashMap;
176 /// // This type doesn't implement `fmt::Debug`!
177 /// struct NonDebug;
178 ///
179 /// // `arg` will be recorded, while `non_debug` will not.
180 /// #[instrument(skip(non_debug))]
181 /// fn my_function(arg: usize, non_debug: NonDebug) {
182 ///     // ...
183 /// }
184 ///
185 /// // These arguments are huge
186 /// #[instrument(skip_all)]
187 /// fn my_big_data_function(large: Vec<u8>, also_large: HashMap<String, String>) {
188 ///     // ...
189 /// }
190 /// ```
191 ///
192 /// Skipping the `self` parameter:
193 ///
194 /// ```
195 /// # use tracing_attributes::instrument;
196 /// #[derive(Debug)]
197 /// struct MyType {
198 ///    data: Vec<u8>, // Suppose this buffer is often quite long...
199 /// }
200 ///
201 /// impl MyType {
202 ///     // Suppose we don't want to print an entire kilobyte of `data`
203 ///     // every time this is called...
204 ///     #[instrument(skip(self))]
205 ///     pub fn my_method(&mut self, an_interesting_argument: usize) {
206 ///          // ... do something (hopefully, using all that `data`!)
207 ///     }
208 /// }
209 /// ```
210 ///
211 /// # Adding Fields
212 ///
213 /// Additional fields (key-value pairs with arbitrary data) may be added to the
214 /// generated span using the `fields` argument on the `#[instrument]` macro. Any
215 /// Rust expression can be used as a field value in this manner. These
216 /// expressions will be evaluated at the beginning of the function's body, so
217 /// arguments to the function may be used in these expressions. Field names may
218 /// also be specified *without* values. Doing so will result in an [empty field]
219 /// whose value may be recorded later within the function body.
220 ///
221 /// This supports the same [field syntax] as the `span!` and `event!` macros.
222 ///
223 /// Note that overlap between the names of fields and (non-skipped) arguments
224 /// will result in a compile error.
225 ///
226 /// ## Examples
227 ///
228 /// Adding a new field based on the value of an argument:
229 ///
230 /// ```
231 /// # use tracing_attributes::instrument;
232 ///
233 /// // This will record a field named "i" with the value of `i` *and* a field
234 /// // named "next" with the value of `i` + 1.
235 /// #[instrument(fields(next = i + 1))]
236 /// pub fn my_function(i: usize) {
237 ///     // ...
238 /// }
239 /// ```
240 ///
241 /// Recording specific properties of a struct as their own fields:
242 ///
243 /// ```
244 /// # mod http {
245 /// #   pub struct Error;
246 /// #   pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
247 /// #   pub struct Request<B> { _b: B }
248 /// #   impl<B> std::fmt::Debug for Request<B> {
249 /// #       fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 /// #           f.pad("request")
251 /// #       }
252 /// #   }
253 /// #   impl<B> Request<B> {
254 /// #       pub fn uri(&self) -> &str { "fake" }
255 /// #       pub fn method(&self) -> &str { "GET" }
256 /// #   }
257 /// # }
258 /// # use tracing_attributes::instrument;
259 ///
260 /// // This will record the request's URI and HTTP method as their own separate
261 /// // fields.
262 /// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
263 /// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
264 ///     // ... handle the request ...
265 ///     # http::Response { _b: std::marker::PhantomData }
266 /// }
267 /// ```
268 ///
269 /// This can be used in conjunction with `skip` or `skip_all` to record only
270 /// some fields of a struct:
271 /// ```
272 /// # use tracing_attributes::instrument;
273 /// // Remember the struct with the very large `data` field from the earlier
274 /// // example? Now it also has a `name`, which we might want to include in
275 /// // our span.
276 /// #[derive(Debug)]
277 /// struct MyType {
278 ///    name: &'static str,
279 ///    data: Vec<u8>,
280 /// }
281 ///
282 /// impl MyType {
283 ///     // This will skip the `data` field, but will include `self.name`,
284 ///     // formatted using `fmt::Display`.
285 ///     #[instrument(skip(self), fields(self.name = %self.name))]
286 ///     pub fn my_method(&mut self, an_interesting_argument: usize) {
287 ///          // ... do something (hopefully, using all that `data`!)
288 ///     }
289 /// }
290 /// ```
291 ///
292 /// Adding an empty field to be recorded later:
293 ///
294 /// ```
295 /// # use tracing_attributes::instrument;
296 ///
297 /// // This function does a very interesting and important mathematical calculation.
298 /// // Suppose we want to record both the inputs to the calculation *and* its result...
299 /// #[instrument(fields(result))]
300 /// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
301 ///     // Rerform the calculation.
302 ///     let result = input_1 + input_2;
303 ///
304 ///     // Record the result as part of the current span.
305 ///     tracing::Span::current().record("result", &result);
306 ///
307 ///     // Now, the result will also be included on this event!
308 ///     tracing::info!("calculation complete!");
309 ///
310 ///     // ... etc ...
311 ///     # 0
312 /// }
313 /// ```
314 ///
315 /// # Examples
316 ///
317 /// Instrumenting a function:
318 ///
319 /// ```
320 /// # use tracing_attributes::instrument;
321 /// #[instrument]
322 /// pub fn my_function(my_arg: usize) {
323 ///     // This event will be recorded inside a span named `my_function` with the
324 ///     // field `my_arg`.
325 ///     tracing::info!("inside my_function!");
326 ///     // ...
327 /// }
328 /// ```
329 /// Setting the level for the generated span:
330 /// ```
331 /// # use tracing_attributes::instrument;
332 /// #[instrument(level = "debug")]
333 /// pub fn my_function() {
334 ///     // ...
335 /// }
336 /// ```
337 /// Overriding the generated span's name:
338 /// ```
339 /// # use tracing_attributes::instrument;
340 /// #[instrument(name = "my_name")]
341 /// pub fn my_function() {
342 ///     // ...
343 /// }
344 /// ```
345 /// Overriding the generated span's target:
346 /// ```
347 /// # use tracing_attributes::instrument;
348 /// #[instrument(target = "my_target")]
349 /// pub fn my_function() {
350 ///     // ...
351 /// }
352 /// ```
353 ///
354 /// To skip recording an argument, pass the argument's name to the `skip`:
355 ///
356 /// ```
357 /// # use tracing_attributes::instrument;
358 /// struct NonDebug;
359 ///
360 /// #[instrument(skip(non_debug))]
361 /// fn my_function(arg: usize, non_debug: NonDebug) {
362 ///     // ...
363 /// }
364 /// ```
365 ///
366 /// To add an additional context to the span, pass key-value pairs to `fields`:
367 ///
368 /// ```
369 /// # use tracing_attributes::instrument;
370 /// #[instrument(fields(foo="bar", id=1, show=true))]
371 /// fn my_function(arg: usize) {
372 ///     // ...
373 /// }
374 /// ```
375 ///
376 /// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, you can add
377 /// `err` to emit error events when the function returns `Err`:
378 ///
379 /// ```
380 /// # use tracing_attributes::instrument;
381 /// #[instrument(err)]
382 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
383 ///     Ok(())
384 /// }
385 /// ```
386 ///
387 /// `async fn`s may also be instrumented:
388 ///
389 /// ```
390 /// # use tracing_attributes::instrument;
391 /// #[instrument]
392 /// pub async fn my_function() -> Result<(), ()> {
393 ///     // ...
394 ///     # Ok(())
395 /// }
396 /// ```
397 ///
398 /// It also works with [async-trait](https://crates.io/crates/async-trait)
399 /// (a crate that allows defining async functions in traits,
400 /// something not currently possible in Rust),
401 /// and hopefully most libraries that exhibit similar behaviors:
402 ///
403 /// ```
404 /// # use tracing::instrument;
405 /// use async_trait::async_trait;
406 ///
407 /// #[async_trait]
408 /// pub trait Foo {
409 ///     async fn foo(&self, arg: usize);
410 /// }
411 ///
412 /// #[derive(Debug)]
413 /// struct FooImpl(usize);
414 ///
415 /// #[async_trait]
416 /// impl Foo for FooImpl {
417 ///     #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
418 ///     async fn foo(&self, arg: usize) {}
419 /// }
420 /// ```
421 ///
422 /// Note than on `async-trait` <= 0.1.43, references to the `Self`
423 /// type inside the `fields` argument were only allowed when the instrumented
424 /// function is a method (i.e., the function receives `self` as an argument).
425 /// For example, this *used to not work* because the instrument function
426 /// didn't receive `self`:
427 /// ```
428 /// # use tracing::instrument;
429 /// use async_trait::async_trait;
430 ///
431 /// #[async_trait]
432 /// pub trait Bar {
433 ///     async fn bar();
434 /// }
435 ///
436 /// #[derive(Debug)]
437 /// struct BarImpl(usize);
438 ///
439 /// #[async_trait]
440 /// impl Bar for BarImpl {
441 ///     #[instrument(fields(tmp = std::any::type_name::<Self>()))]
442 ///     async fn bar() {}
443 /// }
444 /// ```
445 /// Instead, you should manually rewrite any `Self` types as the type for
446 /// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`
447 /// (or maybe you can just bump `async-trait`).
448 ///
449 /// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
450 /// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
451 /// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
452 /// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
453 /// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
454 /// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
455 /// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
456 /// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
457 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
458 #[proc_macro_attribute]
instrument( args: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream459 pub fn instrument(
460     args: proc_macro::TokenStream,
461     item: proc_macro::TokenStream,
462 ) -> proc_macro::TokenStream {
463     let input = syn::parse_macro_input!(item as ItemFn);
464     let args = syn::parse_macro_input!(args as InstrumentArgs);
465 
466     let instrumented_function_name = input.sig.ident.to_string();
467 
468     // check for async_trait-like patterns in the block, and instrument
469     // the future instead of the wrapper
470     if let Some(internal_fun) = get_async_trait_info(&input.block, input.sig.asyncness.is_some()) {
471         // let's rewrite some statements!
472         let mut out_stmts: Vec<TokenStream> = input
473             .block
474             .stmts
475             .iter()
476             .map(|stmt| stmt.to_token_stream())
477             .collect();
478 
479         if let Some((iter, _stmt)) = input
480             .block
481             .stmts
482             .iter()
483             .enumerate()
484             .find(|(_iter, stmt)| *stmt == internal_fun.source_stmt)
485         {
486             // instrument the future by rewriting the corresponding statement
487             out_stmts[iter] = match internal_fun.kind {
488                 // async-trait <= 0.1.43
489                 AsyncTraitKind::Function(fun) => gen_function(
490                     fun,
491                     args,
492                     instrumented_function_name.as_str(),
493                     internal_fun.self_type.as_ref(),
494                 ),
495                 // async-trait >= 0.1.44
496                 AsyncTraitKind::Async(async_expr) => {
497                     let instrumented_block = gen_block(
498                         &async_expr.block,
499                         &input.sig.inputs,
500                         true,
501                         args,
502                         instrumented_function_name.as_str(),
503                         None,
504                     );
505                     let async_attrs = &async_expr.attrs;
506                     quote! {
507                         Box::pin(#(#async_attrs) * async move { #instrumented_block })
508                     }
509                 }
510             };
511         }
512 
513         let vis = &input.vis;
514         let sig = &input.sig;
515         let attrs = &input.attrs;
516         quote!(
517             #(#attrs) *
518             #vis #sig {
519                 #(#out_stmts) *
520             }
521         )
522         .into()
523     } else {
524         gen_function(&input, args, instrumented_function_name.as_str(), None).into()
525     }
526 }
527 
528 /// Given an existing function, generate an instrumented version of that function
gen_function( input: &ItemFn, args: InstrumentArgs, instrumented_function_name: &str, self_type: Option<&syn::TypePath>, ) -> proc_macro2::TokenStream529 fn gen_function(
530     input: &ItemFn,
531     args: InstrumentArgs,
532     instrumented_function_name: &str,
533     self_type: Option<&syn::TypePath>,
534 ) -> proc_macro2::TokenStream {
535     // these are needed ahead of time, as ItemFn contains the function body _and_
536     // isn't representable inside a quote!/quote_spanned! macro
537     // (Syn's ToTokens isn't implemented for ItemFn)
538     let ItemFn {
539         attrs,
540         vis,
541         block,
542         sig,
543         ..
544     } = input;
545 
546     let Signature {
547         output: return_type,
548         inputs: params,
549         unsafety,
550         asyncness,
551         constness,
552         abi,
553         ident,
554         generics:
555             syn::Generics {
556                 params: gen_params,
557                 where_clause,
558                 ..
559             },
560         ..
561     } = sig;
562 
563     let warnings = args.warnings();
564 
565     let body = gen_block(
566         block,
567         params,
568         asyncness.is_some(),
569         args,
570         instrumented_function_name,
571         self_type,
572     );
573 
574     quote!(
575         #(#attrs) *
576         #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #return_type
577         #where_clause
578         {
579             #warnings
580             #body
581         }
582     )
583 }
584 
585 /// Instrument a block
gen_block( block: &Block, params: &Punctuated<FnArg, Token![,]>, async_context: bool, mut args: InstrumentArgs, instrumented_function_name: &str, self_type: Option<&syn::TypePath>, ) -> proc_macro2::TokenStream586 fn gen_block(
587     block: &Block,
588     params: &Punctuated<FnArg, Token![,]>,
589     async_context: bool,
590     mut args: InstrumentArgs,
591     instrumented_function_name: &str,
592     self_type: Option<&syn::TypePath>,
593 ) -> proc_macro2::TokenStream {
594     let err = args.err;
595 
596     // generate the span's name
597     let span_name = args
598         // did the user override the span's name?
599         .name
600         .as_ref()
601         .map(|name| quote!(#name))
602         .unwrap_or_else(|| quote!(#instrumented_function_name));
603 
604     // generate this inside a closure, so we can return early on errors.
605     let span = (|| {
606         // Pull out the arguments-to-be-skipped first, so we can filter results
607         // below.
608         let param_names: Vec<(Ident, (Ident, RecordType))> = params
609             .clone()
610             .into_iter()
611             .flat_map(|param| match param {
612                 FnArg::Typed(PatType { pat, ty, .. }) => {
613                     param_names(*pat, RecordType::parse_from_ty(&*ty))
614                 }
615                 FnArg::Receiver(_) => Box::new(iter::once((
616                     Ident::new("self", param.span()),
617                     RecordType::Debug,
618                 ))),
619             })
620             // Little dance with new (user-exposed) names and old (internal)
621             // names of identifiers. That way, we could do the following
622             // even though async_trait (<=0.1.43) rewrites "self" as "_self":
623             // ```
624             // #[async_trait]
625             // impl Foo for FooImpl {
626             //     #[instrument(skip(self))]
627             //     async fn foo(&self, v: usize) {}
628             // }
629             // ```
630             .map(|(x, record_type)| {
631                 // if we are inside a function generated by async-trait <=0.1.43, we need to
632                 // take care to rewrite "_self" as "self" for 'user convenience'
633                 if self_type.is_some() && x == "_self" {
634                     (Ident::new("self", x.span()), (x, record_type))
635                 } else {
636                     (x.clone(), (x, record_type))
637                 }
638             })
639             .collect();
640 
641         for skip in &args.skips {
642             if !param_names.iter().map(|(user, _)| user).any(|y| y == skip) {
643                 return quote_spanned! {skip.span()=>
644                     compile_error!("attempting to skip non-existent parameter")
645                 };
646             }
647         }
648 
649         let level = args.level();
650         let target = args.target();
651 
652         // filter out skipped fields
653         let quoted_fields: Vec<_> = param_names
654             .iter()
655             .filter(|(param, _)| {
656                 if args.skip_all || args.skips.contains(param) {
657                     return false;
658                 }
659 
660                 // If any parameters have the same name as a custom field, skip
661                 // and allow them to be formatted by the custom field.
662                 if let Some(ref fields) = args.fields {
663                     fields.0.iter().all(|Field { ref name, .. }| {
664                         let first = name.first();
665                         first != name.last() || !first.iter().any(|name| name == &param)
666                     })
667                 } else {
668                     true
669                 }
670             })
671             .map(|(user_name, (real_name, record_type))| match record_type {
672                 RecordType::Value => quote!(#user_name = #real_name),
673                 RecordType::Debug => quote!(#user_name = tracing::field::debug(&#real_name)),
674             })
675             .collect();
676 
677         // replace every use of a variable with its original name
678         if let Some(Fields(ref mut fields)) = args.fields {
679             let mut replacer = IdentAndTypesRenamer {
680                 idents: param_names.into_iter().map(|(a, (b, _))| (a, b)).collect(),
681                 types: Vec::new(),
682             };
683 
684             // when async-trait <=0.1.43 is in use, replace instances
685             // of the "Self" type inside the fields values
686             if let Some(self_type) = self_type {
687                 replacer.types.push(("Self", self_type.clone()));
688             }
689 
690             for e in fields.iter_mut().filter_map(|f| f.value.as_mut()) {
691                 syn::visit_mut::visit_expr_mut(&mut replacer, e);
692             }
693         }
694 
695         let custom_fields = &args.fields;
696 
697         quote!(tracing::span!(
698             target: #target,
699             #level,
700             #span_name,
701             #(#quoted_fields,)*
702             #custom_fields
703 
704         ))
705     })();
706 
707     // Generate the instrumented function body.
708     // If the function is an `async fn`, this will wrap it in an async block,
709     // which is `instrument`ed using `tracing-futures`. Otherwise, this will
710     // enter the span and then perform the rest of the body.
711     // If `err` is in args, instrument any resulting `Err`s.
712     if async_context {
713         if err {
714             quote_spanned!(block.span()=>
715                 let __tracing_attr_span = #span;
716                 tracing::Instrument::instrument(async move {
717                     match async move { #block }.await {
718                         #[allow(clippy::unit_arg)]
719                         Ok(x) => Ok(x),
720                         Err(e) => {
721                             tracing::error!(error = %e);
722                             Err(e)
723                         }
724                     }
725                 }, __tracing_attr_span).await
726             )
727         } else {
728             quote_spanned!(block.span()=>
729                 let __tracing_attr_span = #span;
730                     tracing::Instrument::instrument(
731                         async move { #block },
732                         __tracing_attr_span
733                     )
734                     .await
735             )
736         }
737     } else if err {
738         quote_spanned!(block.span()=>
739             let __tracing_attr_span = #span;
740             let __tracing_attr_guard = __tracing_attr_span.enter();
741             #[allow(clippy::redundant_closure_call)]
742             match (move || #block)() {
743                 #[allow(clippy::unit_arg)]
744                 Ok(x) => Ok(x),
745                 Err(e) => {
746                     tracing::error!(error = %e);
747                     Err(e)
748                 }
749             }
750         )
751     } else {
752         quote_spanned!(block.span()=>
753             let __tracing_attr_span = #span;
754             let __tracing_attr_guard = __tracing_attr_span.enter();
755             #block
756         )
757     }
758 }
759 
760 #[derive(Default, Debug)]
761 struct InstrumentArgs {
762     level: Option<Level>,
763     name: Option<LitStr>,
764     target: Option<LitStr>,
765     skips: HashSet<Ident>,
766     skip_all: bool,
767     fields: Option<Fields>,
768     err: bool,
769     /// Errors describing any unrecognized parse inputs that we skipped.
770     parse_warnings: Vec<syn::Error>,
771 }
772 
773 impl InstrumentArgs {
level(&self) -> impl ToTokens774     fn level(&self) -> impl ToTokens {
775         fn is_level(lit: &LitInt, expected: u64) -> bool {
776             match lit.base10_parse::<u64>() {
777                 Ok(value) => value == expected,
778                 Err(_) => false,
779             }
780         }
781 
782         match &self.level {
783             Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("trace") => {
784                 quote!(tracing::Level::TRACE)
785             }
786             Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("debug") => {
787                 quote!(tracing::Level::DEBUG)
788             }
789             Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("info") => {
790                 quote!(tracing::Level::INFO)
791             }
792             Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("warn") => {
793                 quote!(tracing::Level::WARN)
794             }
795             Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("error") => {
796                 quote!(tracing::Level::ERROR)
797             }
798             Some(Level::Int(ref lit)) if is_level(lit, 1) => quote!(tracing::Level::TRACE),
799             Some(Level::Int(ref lit)) if is_level(lit, 2) => quote!(tracing::Level::DEBUG),
800             Some(Level::Int(ref lit)) if is_level(lit, 3) => quote!(tracing::Level::INFO),
801             Some(Level::Int(ref lit)) if is_level(lit, 4) => quote!(tracing::Level::WARN),
802             Some(Level::Int(ref lit)) if is_level(lit, 5) => quote!(tracing::Level::ERROR),
803             Some(Level::Path(ref pat)) => quote!(#pat),
804             Some(lit) => quote! {
805                 compile_error!(
806                     "unknown verbosity level, expected one of \"trace\", \
807                      \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5"
808                 )
809             },
810             None => quote!(tracing::Level::INFO),
811         }
812     }
813 
target(&self) -> impl ToTokens814     fn target(&self) -> impl ToTokens {
815         if let Some(ref target) = self.target {
816             quote!(#target)
817         } else {
818             quote!(module_path!())
819         }
820     }
821 
822     /// Generate "deprecation" warnings for any unrecognized attribute inputs
823     /// that we skipped.
824     ///
825     /// For backwards compatibility, we need to emit compiler warnings rather
826     /// than errors for unrecognized inputs. Generating a fake deprecation is
827     /// the only way to do this on stable Rust right now.
warnings(&self) -> impl ToTokens828     fn warnings(&self) -> impl ToTokens {
829         let warnings = self.parse_warnings.iter().map(|err| {
830             let msg = format!("found unrecognized input, {}", err);
831             let msg = LitStr::new(&msg, err.span());
832             // TODO(eliza): This is a bit of a hack, but it's just about the
833             // only way to emit warnings from a proc macro on stable Rust.
834             // Eventually, when the `proc_macro::Diagnostic` API stabilizes, we
835             // should definitely use that instead.
836             quote_spanned! {err.span()=>
837                 #[warn(deprecated)]
838                 {
839                     #[deprecated(since = "not actually deprecated", note = #msg)]
840                     const TRACING_INSTRUMENT_WARNING: () = ();
841                     let _ = TRACING_INSTRUMENT_WARNING;
842                 }
843             }
844         });
845         quote! {
846             { #(#warnings)* }
847         }
848     }
849 }
850 
851 impl Parse for InstrumentArgs {
parse(input: ParseStream<'_>) -> syn::Result<Self>852     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
853         let mut args = Self::default();
854         while !input.is_empty() {
855             let lookahead = input.lookahead1();
856             if lookahead.peek(kw::name) {
857                 if args.name.is_some() {
858                     return Err(input.error("expected only a single `name` argument"));
859                 }
860                 let name = input.parse::<StrArg<kw::name>>()?.value;
861                 args.name = Some(name);
862             } else if lookahead.peek(LitStr) {
863                 // XXX: apparently we support names as either named args with an
864                 // sign, _or_ as unnamed string literals. That's weird, but
865                 // changing it is apparently breaking.
866                 if args.name.is_some() {
867                     return Err(input.error("expected only a single `name` argument"));
868                 }
869                 args.name = Some(input.parse()?);
870             } else if lookahead.peek(kw::target) {
871                 if args.target.is_some() {
872                     return Err(input.error("expected only a single `target` argument"));
873                 }
874                 let target = input.parse::<StrArg<kw::target>>()?.value;
875                 args.target = Some(target);
876             } else if lookahead.peek(kw::level) {
877                 if args.level.is_some() {
878                     return Err(input.error("expected only a single `level` argument"));
879                 }
880                 args.level = Some(input.parse()?);
881             } else if lookahead.peek(kw::skip) {
882                 if !args.skips.is_empty() {
883                     return Err(input.error("expected only a single `skip` argument"));
884                 }
885                 if args.skip_all {
886                     return Err(input.error("expected either `skip` or `skip_all` argument"));
887                 }
888                 let Skips(skips) = input.parse()?;
889                 args.skips = skips;
890             } else if lookahead.peek(kw::skip_all) {
891                 if args.skip_all {
892                     return Err(input.error("expected only a single `skip_all` argument"));
893                 }
894                 if !args.skips.is_empty() {
895                     return Err(input.error("expected either `skip` or `skip_all` argument"));
896                 }
897                 let _ = input.parse::<kw::skip_all>()?;
898                 args.skip_all = true;
899             } else if lookahead.peek(kw::fields) {
900                 if args.fields.is_some() {
901                     return Err(input.error("expected only a single `fields` argument"));
902                 }
903                 args.fields = Some(input.parse()?);
904             } else if lookahead.peek(kw::err) {
905                 let _ = input.parse::<kw::err>()?;
906                 args.err = true;
907             } else if lookahead.peek(Token![,]) {
908                 let _ = input.parse::<Token![,]>()?;
909             } else {
910                 // We found a token that we didn't expect!
911                 // We want to emit warnings for these, rather than errors, so
912                 // we'll add it to the list of unrecognized inputs we've seen so
913                 // far and keep going.
914                 args.parse_warnings.push(lookahead.error());
915                 // Parse the unrecognized token tree to advance the parse
916                 // stream, and throw it away so we can keep parsing.
917                 let _ = input.parse::<proc_macro2::TokenTree>();
918             }
919         }
920         Ok(args)
921     }
922 }
923 
924 struct StrArg<T> {
925     value: LitStr,
926     _p: std::marker::PhantomData<T>,
927 }
928 
929 impl<T: Parse> Parse for StrArg<T> {
parse(input: ParseStream<'_>) -> syn::Result<Self>930     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
931         let _ = input.parse::<T>()?;
932         let _ = input.parse::<Token![=]>()?;
933         let value = input.parse()?;
934         Ok(Self {
935             value,
936             _p: std::marker::PhantomData,
937         })
938     }
939 }
940 
941 struct Skips(HashSet<Ident>);
942 
943 impl Parse for Skips {
parse(input: ParseStream<'_>) -> syn::Result<Self>944     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
945         let _ = input.parse::<kw::skip>();
946         let content;
947         let _ = syn::parenthesized!(content in input);
948         let names: Punctuated<Ident, Token![,]> = content.parse_terminated(Ident::parse_any)?;
949         let mut skips = HashSet::new();
950         for name in names {
951             if skips.contains(&name) {
952                 return Err(syn::Error::new(
953                     name.span(),
954                     "tried to skip the same field twice",
955                 ));
956             } else {
957                 skips.insert(name);
958             }
959         }
960         Ok(Self(skips))
961     }
962 }
963 
964 #[derive(Debug)]
965 struct Fields(Punctuated<Field, Token![,]>);
966 
967 #[derive(Debug)]
968 struct Field {
969     name: Punctuated<Ident, Token![.]>,
970     value: Option<Expr>,
971     kind: FieldKind,
972 }
973 
974 #[derive(Debug, Eq, PartialEq)]
975 enum FieldKind {
976     Debug,
977     Display,
978     Value,
979 }
980 
981 impl Parse for Fields {
parse(input: ParseStream<'_>) -> syn::Result<Self>982     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
983         let _ = input.parse::<kw::fields>();
984         let content;
985         let _ = syn::parenthesized!(content in input);
986         let fields: Punctuated<_, Token![,]> = content.parse_terminated(Field::parse)?;
987         Ok(Self(fields))
988     }
989 }
990 
991 impl ToTokens for Fields {
to_tokens(&self, tokens: &mut TokenStream)992     fn to_tokens(&self, tokens: &mut TokenStream) {
993         self.0.to_tokens(tokens)
994     }
995 }
996 
997 impl Parse for Field {
parse(input: ParseStream<'_>) -> syn::Result<Self>998     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
999         let mut kind = FieldKind::Value;
1000         if input.peek(Token![%]) {
1001             input.parse::<Token![%]>()?;
1002             kind = FieldKind::Display;
1003         } else if input.peek(Token![?]) {
1004             input.parse::<Token![?]>()?;
1005             kind = FieldKind::Debug;
1006         };
1007         let name = Punctuated::parse_separated_nonempty_with(input, Ident::parse_any)?;
1008         let value = if input.peek(Token![=]) {
1009             input.parse::<Token![=]>()?;
1010             if input.peek(Token![%]) {
1011                 input.parse::<Token![%]>()?;
1012                 kind = FieldKind::Display;
1013             } else if input.peek(Token![?]) {
1014                 input.parse::<Token![?]>()?;
1015                 kind = FieldKind::Debug;
1016             };
1017             Some(input.parse()?)
1018         } else {
1019             None
1020         };
1021         Ok(Self { name, value, kind })
1022     }
1023 }
1024 
1025 impl ToTokens for Field {
to_tokens(&self, tokens: &mut TokenStream)1026     fn to_tokens(&self, tokens: &mut TokenStream) {
1027         if let Some(ref value) = self.value {
1028             let name = &self.name;
1029             let kind = &self.kind;
1030             tokens.extend(quote! {
1031                 #name = #kind#value
1032             })
1033         } else if self.kind == FieldKind::Value {
1034             // XXX(eliza): I don't like that fields without values produce
1035             // empty fields rather than local variable shorthand...but,
1036             // we've released a version where field names without values in
1037             // `instrument` produce empty field values, so changing it now
1038             // is a breaking change. agh.
1039             let name = &self.name;
1040             tokens.extend(quote!(#name = tracing::field::Empty))
1041         } else {
1042             self.kind.to_tokens(tokens);
1043             self.name.to_tokens(tokens);
1044         }
1045     }
1046 }
1047 
1048 impl ToTokens for FieldKind {
to_tokens(&self, tokens: &mut TokenStream)1049     fn to_tokens(&self, tokens: &mut TokenStream) {
1050         match self {
1051             FieldKind::Debug => tokens.extend(quote! { ? }),
1052             FieldKind::Display => tokens.extend(quote! { % }),
1053             _ => {}
1054         }
1055     }
1056 }
1057 
1058 #[derive(Debug)]
1059 enum Level {
1060     Str(LitStr),
1061     Int(LitInt),
1062     Path(Path),
1063 }
1064 
1065 impl Parse for Level {
parse(input: ParseStream<'_>) -> syn::Result<Self>1066     fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
1067         let _ = input.parse::<kw::level>()?;
1068         let _ = input.parse::<Token![=]>()?;
1069         let lookahead = input.lookahead1();
1070         if lookahead.peek(LitStr) {
1071             Ok(Self::Str(input.parse()?))
1072         } else if lookahead.peek(LitInt) {
1073             Ok(Self::Int(input.parse()?))
1074         } else if lookahead.peek(Ident) {
1075             Ok(Self::Path(input.parse()?))
1076         } else {
1077             Err(lookahead.error())
1078         }
1079     }
1080 }
1081 
1082 /// Indicates whether a field should be recorded as `Value` or `Debug`.
1083 enum RecordType {
1084     /// The field should be recorded using its `Value` implementation.
1085     Value,
1086     /// The field should be recorded using `tracing::field::debug()`.
1087     Debug,
1088 }
1089 
1090 impl RecordType {
1091     /// Array of primitive types which should be recorded as [RecordType::Value].
1092     const TYPES_FOR_VALUE: &'static [&'static str] = &[
1093         "bool",
1094         "str",
1095         "u8",
1096         "i8",
1097         "u16",
1098         "i16",
1099         "u32",
1100         "i32",
1101         "u64",
1102         "i64",
1103         "f32",
1104         "f64",
1105         "usize",
1106         "isize",
1107         "NonZeroU8",
1108         "NonZeroI8",
1109         "NonZeroU16",
1110         "NonZeroI16",
1111         "NonZeroU32",
1112         "NonZeroI32",
1113         "NonZeroU64",
1114         "NonZeroI64",
1115         "NonZeroUsize",
1116         "NonZeroIsize",
1117         "Wrapping",
1118     ];
1119 
1120     /// Parse `RecordType` from [syn::Type] by looking up
1121     /// the [RecordType::TYPES_FOR_VALUE] array.
parse_from_ty(ty: &syn::Type) -> Self1122     fn parse_from_ty(ty: &syn::Type) -> Self {
1123         match ty {
1124             syn::Type::Path(syn::TypePath { path, .. })
1125                 if path
1126                     .segments
1127                     .iter()
1128                     .last()
1129                     .map(|path_segment| {
1130                         let ident = path_segment.ident.to_string();
1131                         Self::TYPES_FOR_VALUE.iter().any(|&t| t == ident)
1132                     })
1133                     .unwrap_or(false) =>
1134             {
1135                 RecordType::Value
1136             }
1137             syn::Type::Reference(syn::TypeReference { elem, .. }) => {
1138                 RecordType::parse_from_ty(&*elem)
1139             }
1140             _ => RecordType::Debug,
1141         }
1142     }
1143 }
1144 
param_names(pat: Pat, record_type: RecordType) -> Box<dyn Iterator<Item = (Ident, RecordType)>>1145 fn param_names(pat: Pat, record_type: RecordType) -> Box<dyn Iterator<Item = (Ident, RecordType)>> {
1146     match pat {
1147         Pat::Ident(PatIdent { ident, .. }) => Box::new(iter::once((ident, record_type))),
1148         Pat::Reference(PatReference { pat, .. }) => param_names(*pat, record_type),
1149         // We can't get the concrete type of fields in the struct/tuple
1150         // patterns by using `syn`. e.g. `fn foo(Foo { x, y }: Foo) {}`.
1151         // Therefore, the struct/tuple patterns in the arguments will just
1152         // always be recorded as `RecordType::Debug`.
1153         Pat::Struct(PatStruct { fields, .. }) => Box::new(
1154             fields
1155                 .into_iter()
1156                 .flat_map(|FieldPat { pat, .. }| param_names(*pat, RecordType::Debug)),
1157         ),
1158         Pat::Tuple(PatTuple { elems, .. }) => Box::new(
1159             elems
1160                 .into_iter()
1161                 .flat_map(|p| param_names(p, RecordType::Debug)),
1162         ),
1163         Pat::TupleStruct(PatTupleStruct {
1164             pat: PatTuple { elems, .. },
1165             ..
1166         }) => Box::new(
1167             elems
1168                 .into_iter()
1169                 .flat_map(|p| param_names(p, RecordType::Debug)),
1170         ),
1171 
1172         // The above *should* cover all cases of irrefutable patterns,
1173         // but we purposefully don't do any funny business here
1174         // (such as panicking) because that would obscure rustc's
1175         // much more informative error message.
1176         _ => Box::new(iter::empty()),
1177     }
1178 }
1179 
1180 mod kw {
1181     syn::custom_keyword!(fields);
1182     syn::custom_keyword!(skip);
1183     syn::custom_keyword!(skip_all);
1184     syn::custom_keyword!(level);
1185     syn::custom_keyword!(target);
1186     syn::custom_keyword!(name);
1187     syn::custom_keyword!(err);
1188 }
1189 
1190 enum AsyncTraitKind<'a> {
1191     // old construction. Contains the function
1192     Function(&'a ItemFn),
1193     // new construction. Contains a reference to the async block
1194     Async(&'a ExprAsync),
1195 }
1196 
1197 struct AsyncTraitInfo<'a> {
1198     // statement that must be patched
1199     source_stmt: &'a Stmt,
1200     kind: AsyncTraitKind<'a>,
1201     self_type: Option<syn::TypePath>,
1202 }
1203 
1204 // Get the AST of the inner function we need to hook, if it was generated
1205 // by async-trait.
1206 // When we are given a function annotated by async-trait, that function
1207 // is only a placeholder that returns a pinned future containing the
1208 // user logic, and it is that pinned future that needs to be instrumented.
1209 // Were we to instrument its parent, we would only collect information
1210 // regarding the allocation of that future, and not its own span of execution.
1211 // Depending on the version of async-trait, we inspect the block of the function
1212 // to find if it matches the pattern
1213 // `async fn foo<...>(...) {...}; Box::pin(foo<...>(...))` (<=0.1.43), or if
1214 // it matches `Box::pin(async move { ... }) (>=0.1.44). We the return the
1215 // statement that must be instrumented, along with some other informations.
1216 // 'gen_body' will then be able to use that information to instrument the
1217 // proper function/future.
1218 // (this follows the approach suggested in
1219 // https://github.com/dtolnay/async-trait/issues/45#issuecomment-571245673)
get_async_trait_info(block: &Block, block_is_async: bool) -> Option<AsyncTraitInfo<'_>>1220 fn get_async_trait_info(block: &Block, block_is_async: bool) -> Option<AsyncTraitInfo<'_>> {
1221     // are we in an async context? If yes, this isn't a async_trait-like pattern
1222     if block_is_async {
1223         return None;
1224     }
1225 
1226     // list of async functions declared inside the block
1227     let inside_funs = block.stmts.iter().filter_map(|stmt| {
1228         if let Stmt::Item(Item::Fn(fun)) = &stmt {
1229             // If the function is async, this is a candidate
1230             if fun.sig.asyncness.is_some() {
1231                 return Some((stmt, fun));
1232             }
1233         }
1234         None
1235     });
1236 
1237     // last expression of the block (it determines the return value
1238     // of the block, so that if we are working on a function whose
1239     // `trait` or `impl` declaration is annotated by async_trait,
1240     // this is quite likely the point where the future is pinned)
1241     let (last_expr_stmt, last_expr) = block.stmts.iter().rev().find_map(|stmt| {
1242         if let Stmt::Expr(expr) = stmt {
1243             Some((stmt, expr))
1244         } else {
1245             None
1246         }
1247     })?;
1248 
1249     // is the last expression a function call?
1250     let (outside_func, outside_args) = match last_expr {
1251         Expr::Call(ExprCall { func, args, .. }) => (func, args),
1252         _ => return None,
1253     };
1254 
1255     // is it a call to `Box::pin()`?
1256     let path = match outside_func.as_ref() {
1257         Expr::Path(path) => &path.path,
1258         _ => return None,
1259     };
1260     if !path_to_string(path).ends_with("Box::pin") {
1261         return None;
1262     }
1263 
1264     // Does the call take an argument? If it doesn't,
1265     // it's not gonna compile anyway, but that's no reason
1266     // to (try to) perform an out of bounds access
1267     if outside_args.is_empty() {
1268         return None;
1269     }
1270 
1271     // Is the argument to Box::pin an async block that
1272     // captures its arguments?
1273     if let Expr::Async(async_expr) = &outside_args[0] {
1274         // check that the move 'keyword' is present
1275         async_expr.capture?;
1276 
1277         return Some(AsyncTraitInfo {
1278             source_stmt: last_expr_stmt,
1279             kind: AsyncTraitKind::Async(async_expr),
1280             self_type: None,
1281         });
1282     }
1283 
1284     // Is the argument to Box::pin a function call itself?
1285     let func = match &outside_args[0] {
1286         Expr::Call(ExprCall { func, .. }) => func,
1287         _ => return None,
1288     };
1289 
1290     // "stringify" the path of the function called
1291     let func_name = match **func {
1292         Expr::Path(ref func_path) => path_to_string(&func_path.path),
1293         _ => return None,
1294     };
1295 
1296     // Was that function defined inside of the current block?
1297     // If so, retrieve the statement where it was declared and the function itself
1298     let (stmt_func_declaration, func) = inside_funs
1299         .into_iter()
1300         .find(|(_, fun)| fun.sig.ident == func_name)?;
1301 
1302     // If "_self" is present as an argument, we store its type to be able to rewrite "Self" (the
1303     // parameter type) with the type of "_self"
1304     let mut self_type = None;
1305     for arg in &func.sig.inputs {
1306         if let FnArg::Typed(ty) = arg {
1307             if let Pat::Ident(PatIdent { ref ident, .. }) = *ty.pat {
1308                 if ident == "_self" {
1309                     let mut ty = *ty.ty.clone();
1310                     // extract the inner type if the argument is "&self" or "&mut self"
1311                     if let syn::Type::Reference(syn::TypeReference { elem, .. }) = ty {
1312                         ty = *elem;
1313                     }
1314 
1315                     if let syn::Type::Path(tp) = ty {
1316                         self_type = Some(tp);
1317                         break;
1318                     }
1319                 }
1320             }
1321         }
1322     }
1323 
1324     Some(AsyncTraitInfo {
1325         source_stmt: stmt_func_declaration,
1326         kind: AsyncTraitKind::Function(func),
1327         self_type,
1328     })
1329 }
1330 
1331 // Return a path as a String
path_to_string(path: &Path) -> String1332 fn path_to_string(path: &Path) -> String {
1333     use std::fmt::Write;
1334     // some heuristic to prevent too many allocations
1335     let mut res = String::with_capacity(path.segments.len() * 5);
1336     for i in 0..path.segments.len() {
1337         write!(&mut res, "{}", path.segments[i].ident)
1338             .expect("writing to a String should never fail");
1339         if i < path.segments.len() - 1 {
1340             res.push_str("::");
1341         }
1342     }
1343     res
1344 }
1345 
1346 /// A visitor struct to replace idents and types in some piece
1347 /// of code (e.g. the "self" and "Self" tokens in user-supplied
1348 /// fields expressions when the function is generated by an old
1349 /// version of async-trait).
1350 struct IdentAndTypesRenamer<'a> {
1351     types: Vec<(&'a str, TypePath)>,
1352     idents: Vec<(Ident, Ident)>,
1353 }
1354 
1355 impl<'a> syn::visit_mut::VisitMut for IdentAndTypesRenamer<'a> {
1356     // we deliberately compare strings because we want to ignore the spans
1357     // If we apply clippy's lint, the behavior changes
1358     #[allow(clippy::cmp_owned)]
visit_ident_mut(&mut self, id: &mut Ident)1359     fn visit_ident_mut(&mut self, id: &mut Ident) {
1360         for (old_ident, new_ident) in &self.idents {
1361             if id.to_string() == old_ident.to_string() {
1362                 *id = new_ident.clone();
1363             }
1364         }
1365     }
1366 
visit_type_mut(&mut self, ty: &mut syn::Type)1367     fn visit_type_mut(&mut self, ty: &mut syn::Type) {
1368         for (type_name, new_type) in &self.types {
1369             if let syn::Type::Path(TypePath { path, .. }) = ty {
1370                 if path_to_string(path) == *type_name {
1371                     *ty = syn::Type::Path(new_type.clone());
1372                 }
1373             }
1374         }
1375     }
1376 }
1377 
1378 // A visitor struct that replace an async block by its patched version
1379 struct AsyncTraitBlockReplacer<'a> {
1380     block: &'a Block,
1381     patched_block: Block,
1382 }
1383 
1384 impl<'a> syn::visit_mut::VisitMut for AsyncTraitBlockReplacer<'a> {
visit_block_mut(&mut self, i: &mut Block)1385     fn visit_block_mut(&mut self, i: &mut Block) {
1386         if i == self.block {
1387             *i = self.patched_block.clone();
1388         }
1389     }
1390 }
1391