diff options
Diffstat (limited to 'vendor/tracing-attributes/src')
-rw-r--r-- | vendor/tracing-attributes/src/expand.rs | 118 | ||||
-rw-r--r-- | vendor/tracing-attributes/src/lib.rs | 60 |
2 files changed, 125 insertions, 53 deletions
diff --git a/vendor/tracing-attributes/src/expand.rs b/vendor/tracing-attributes/src/expand.rs index 81ee6ed90..7005b4423 100644 --- a/vendor/tracing-attributes/src/expand.rs +++ b/vendor/tracing-attributes/src/expand.rs @@ -2,15 +2,16 @@ use std::iter; use proc_macro2::TokenStream; use quote::{quote, quote_spanned, ToTokens}; +use syn::visit_mut::VisitMut; use syn::{ punctuated::Punctuated, spanned::Spanned, Block, Expr, ExprAsync, ExprCall, FieldPat, FnArg, Ident, Item, ItemFn, Pat, PatIdent, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType, - Path, Signature, Stmt, Token, TypePath, + Path, ReturnType, Signature, Stmt, Token, Type, TypePath, }; use crate::{ attr::{Field, Fields, FormatMode, InstrumentArgs}, - MaybeItemFnRef, + MaybeItemFn, MaybeItemFnRef, }; /// Given an existing function, generate an instrumented version of that function @@ -18,20 +19,21 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>( input: MaybeItemFnRef<'a, B>, args: InstrumentArgs, instrumented_function_name: &str, - self_type: Option<&syn::TypePath>, + self_type: Option<&TypePath>, ) -> proc_macro2::TokenStream { // these are needed ahead of time, as ItemFn contains the function body _and_ // isn't representable inside a quote!/quote_spanned! macro // (Syn's ToTokens isn't implemented for ItemFn) let MaybeItemFnRef { - attrs, + outer_attrs, + inner_attrs, vis, sig, block, } = input; let Signature { - output: return_type, + output, inputs: params, unsafety, asyncness, @@ -49,8 +51,35 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>( let warnings = args.warnings(); + let (return_type, return_span) = if let ReturnType::Type(_, return_type) = &output { + (erase_impl_trait(return_type), return_type.span()) + } else { + // Point at function name if we don't have an explicit return type + (syn::parse_quote! { () }, ident.span()) + }; + // Install a fake return statement as the first thing in the function + // body, so that we eagerly infer that the return type is what we + // declared in the async fn signature. + // The `#[allow(..)]` is given because the return statement is + // unreachable, but does affect inference, so it needs to be written + // exactly that way for it to do its magic. + let fake_return_edge = quote_spanned! {return_span=> + #[allow(unreachable_code, clippy::diverging_sub_expression, clippy::let_unit_value)] + if false { + let __tracing_attr_fake_return: #return_type = + unreachable!("this is just for type inference, and is unreachable code"); + return __tracing_attr_fake_return; + } + }; + let block = quote! { + { + #fake_return_edge + #block + } + }; + let body = gen_block( - block, + &block, params, asyncness.is_some(), args, @@ -59,10 +88,11 @@ pub(crate) fn gen_function<'a, B: ToTokens + 'a>( ); quote!( - #(#attrs) * - #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #return_type + #(#outer_attrs) * + #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #output #where_clause { + #(#inner_attrs) * #warnings #body } @@ -76,7 +106,7 @@ fn gen_block<B: ToTokens>( async_context: bool, mut args: InstrumentArgs, instrumented_function_name: &str, - self_type: Option<&syn::TypePath>, + self_type: Option<&TypePath>, ) -> proc_macro2::TokenStream { // generate the span's name let span_name = args @@ -393,11 +423,11 @@ impl RecordType { "Wrapping", ]; - /// Parse `RecordType` from [syn::Type] by looking up + /// Parse `RecordType` from [Type] by looking up /// the [RecordType::TYPES_FOR_VALUE] array. - fn parse_from_ty(ty: &syn::Type) -> Self { + fn parse_from_ty(ty: &Type) -> Self { match ty { - syn::Type::Path(syn::TypePath { path, .. }) + Type::Path(TypePath { path, .. }) if path .segments .iter() @@ -410,9 +440,7 @@ impl RecordType { { RecordType::Value } - syn::Type::Reference(syn::TypeReference { elem, .. }) => { - RecordType::parse_from_ty(&*elem) - } + Type::Reference(syn::TypeReference { elem, .. }) => RecordType::parse_from_ty(elem), _ => RecordType::Debug, } } @@ -471,7 +499,7 @@ pub(crate) struct AsyncInfo<'block> { // statement that must be patched source_stmt: &'block Stmt, kind: AsyncKind<'block>, - self_type: Option<syn::TypePath>, + self_type: Option<TypePath>, input: &'block ItemFn, } @@ -606,11 +634,11 @@ impl<'block> AsyncInfo<'block> { if ident == "_self" { let mut ty = *ty.ty.clone(); // extract the inner type if the argument is "&self" or "&mut self" - if let syn::Type::Reference(syn::TypeReference { elem, .. }) = ty { + if let Type::Reference(syn::TypeReference { elem, .. }) = ty { ty = *elem; } - if let syn::Type::Path(tp) = ty { + if let Type::Path(tp) = ty { self_type = Some(tp); break; } @@ -631,7 +659,7 @@ impl<'block> AsyncInfo<'block> { self, args: InstrumentArgs, instrumented_function_name: &str, - ) -> proc_macro::TokenStream { + ) -> Result<proc_macro::TokenStream, syn::Error> { // let's rewrite some statements! let mut out_stmts: Vec<TokenStream> = self .input @@ -652,12 +680,15 @@ impl<'block> AsyncInfo<'block> { // instrument the future by rewriting the corresponding statement out_stmts[iter] = match self.kind { // `Box::pin(immediately_invoked_async_fn())` - AsyncKind::Function(fun) => gen_function( - fun.into(), - args, - instrumented_function_name, - self.self_type.as_ref(), - ), + AsyncKind::Function(fun) => { + let fun = MaybeItemFn::from(fun.clone()); + gen_function( + fun.as_ref(), + args, + instrumented_function_name, + self.self_type.as_ref(), + ) + } // `async move { ... }`, optionally pinned AsyncKind::Async { async_expr, @@ -688,13 +719,13 @@ impl<'block> AsyncInfo<'block> { let vis = &self.input.vis; let sig = &self.input.sig; let attrs = &self.input.attrs; - quote!( + Ok(quote!( #(#attrs) * #vis #sig { #(#out_stmts) * } ) - .into() + .into()) } } @@ -722,7 +753,7 @@ struct IdentAndTypesRenamer<'a> { idents: Vec<(Ident, Ident)>, } -impl<'a> syn::visit_mut::VisitMut for IdentAndTypesRenamer<'a> { +impl<'a> VisitMut for IdentAndTypesRenamer<'a> { // we deliberately compare strings because we want to ignore the spans // If we apply clippy's lint, the behavior changes #[allow(clippy::cmp_owned)] @@ -734,11 +765,11 @@ impl<'a> syn::visit_mut::VisitMut for IdentAndTypesRenamer<'a> { } } - fn visit_type_mut(&mut self, ty: &mut syn::Type) { + fn visit_type_mut(&mut self, ty: &mut Type) { for (type_name, new_type) in &self.types { - if let syn::Type::Path(TypePath { path, .. }) = ty { + if let Type::Path(TypePath { path, .. }) = ty { if path_to_string(path) == *type_name { - *ty = syn::Type::Path(new_type.clone()); + *ty = Type::Path(new_type.clone()); } } } @@ -751,10 +782,33 @@ struct AsyncTraitBlockReplacer<'a> { patched_block: Block, } -impl<'a> syn::visit_mut::VisitMut for AsyncTraitBlockReplacer<'a> { +impl<'a> VisitMut for AsyncTraitBlockReplacer<'a> { fn visit_block_mut(&mut self, i: &mut Block) { if i == self.block { *i = self.patched_block.clone(); } } } + +// Replaces any `impl Trait` with `_` so it can be used as the type in +// a `let` statement's LHS. +struct ImplTraitEraser; + +impl VisitMut for ImplTraitEraser { + fn visit_type_mut(&mut self, t: &mut Type) { + if let Type::ImplTrait(..) = t { + *t = syn::TypeInfer { + underscore_token: Token![_](t.span()), + } + .into(); + } else { + syn::visit_mut::visit_type_mut(self, t); + } + } +} + +fn erase_impl_trait(ty: &Type) -> Type { + let mut ty = ty.clone(); + ImplTraitEraser.visit_type_mut(&mut ty); + ty +} diff --git a/vendor/tracing-attributes/src/lib.rs b/vendor/tracing-attributes/src/lib.rs index 49b3c794a..f5974e4e5 100644 --- a/vendor/tracing-attributes/src/lib.rs +++ b/vendor/tracing-attributes/src/lib.rs @@ -16,7 +16,7 @@ //! //! ```toml //! [dependencies] -//! tracing-attributes = "0.1.22" +//! tracing-attributes = "0.1.23" //! ``` //! //! The [`#[instrument]`][instrument] attribute can now be added to a function @@ -52,7 +52,7 @@ //! supported compiler version is not considered a semver breaking change as //! long as doing so complies with this policy. //! -#![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.22")] +#![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.23")] #![doc( html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png", issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/" @@ -86,7 +86,7 @@ extern crate proc_macro; use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse::{Parse, ParseStream}; -use syn::{Attribute, Block, ItemFn, Signature, Visibility}; +use syn::{Attribute, ItemFn, Signature, Visibility}; mod attr; mod expand; @@ -587,11 +587,13 @@ fn instrument_precise( // check for async_trait-like patterns in the block, and instrument // the future instead of the wrapper if let Some(async_like) = expand::AsyncInfo::from_fn(&input) { - return Ok(async_like.gen_async(args, instrumented_function_name.as_str())); + return async_like.gen_async(args, instrumented_function_name.as_str()); } + let input = MaybeItemFn::from(input); + Ok(expand::gen_function( - (&input).into(), + input.as_ref(), args, instrumented_function_name.as_str(), None, @@ -603,7 +605,8 @@ fn instrument_precise( /// which's block is just a `TokenStream` (it may contain invalid code). #[derive(Debug, Clone)] struct MaybeItemFn { - attrs: Vec<Attribute>, + outer_attrs: Vec<Attribute>, + inner_attrs: Vec<Attribute>, vis: Visibility, sig: Signature, block: TokenStream, @@ -612,7 +615,8 @@ struct MaybeItemFn { impl MaybeItemFn { fn as_ref(&self) -> MaybeItemFnRef<'_, TokenStream> { MaybeItemFnRef { - attrs: &self.attrs, + outer_attrs: &self.outer_attrs, + inner_attrs: &self.inner_attrs, vis: &self.vis, sig: &self.sig, block: &self.block, @@ -624,12 +628,14 @@ impl MaybeItemFn { /// (just like `ItemFn`, but skips parsing the body). impl Parse for MaybeItemFn { fn parse(input: ParseStream<'_>) -> syn::Result<Self> { - let attrs = input.call(syn::Attribute::parse_outer)?; + let outer_attrs = input.call(Attribute::parse_outer)?; let vis: Visibility = input.parse()?; let sig: Signature = input.parse()?; + let inner_attrs = input.call(Attribute::parse_inner)?; let block: TokenStream = input.parse()?; Ok(Self { - attrs, + outer_attrs, + inner_attrs, vis, sig, block, @@ -637,23 +643,35 @@ impl Parse for MaybeItemFn { } } +impl From<ItemFn> for MaybeItemFn { + fn from( + ItemFn { + attrs, + vis, + sig, + block, + }: ItemFn, + ) -> Self { + let (outer_attrs, inner_attrs) = attrs + .into_iter() + .partition(|attr| attr.style == syn::AttrStyle::Outer); + Self { + outer_attrs, + inner_attrs, + vis, + sig, + block: block.to_token_stream(), + } + } +} + /// A generic reference type for `MaybeItemFn`, /// that takes a generic block type `B` that implements `ToTokens` (eg. `TokenStream`, `Block`). #[derive(Debug, Clone)] struct MaybeItemFnRef<'a, B: ToTokens> { - attrs: &'a Vec<Attribute>, + outer_attrs: &'a Vec<Attribute>, + inner_attrs: &'a Vec<Attribute>, vis: &'a Visibility, sig: &'a Signature, block: &'a B, } - -impl<'a> From<&'a ItemFn> for MaybeItemFnRef<'a, Box<Block>> { - fn from(val: &'a ItemFn) -> Self { - MaybeItemFnRef { - attrs: &val.attrs, - vis: &val.vis, - sig: &val.sig, - block: &val.block, - } - } -} |