Upgrade rust/crates/async-trait to 0.1.48

Test: make
Change-Id: I898f35cd086b1bd9952eba11d5d59d31f78a5d16
diff --git a/src/expand.rs b/src/expand.rs
index fb83df1..e78c6c4 100644
--- a/src/expand.rs
+++ b/src/expand.rs
@@ -1,19 +1,23 @@
-use crate::lifetime::{has_async_lifetime, CollectLifetimes};
+use crate::lifetime::CollectLifetimes;
 use crate::parse::Item;
-use crate::receiver::{
-    has_self_in_block, has_self_in_sig, has_self_in_where_predicate, ReplaceReceiver,
-};
-use proc_macro2::{Span, TokenStream};
+use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf};
+use proc_macro2::TokenStream;
 use quote::{format_ident, quote, quote_spanned, ToTokens};
-use std::mem;
+use std::collections::BTreeSet as Set;
 use syn::punctuated::Punctuated;
-use syn::visit_mut::VisitMut;
+use syn::visit_mut::{self, VisitMut};
 use syn::{
-    parse_quote, Block, FnArg, GenericParam, Generics, Ident, ImplItem, Lifetime, Pat, PatIdent,
-    Path, Receiver, ReturnType, Signature, Stmt, Token, TraitItem, Type, TypeParam, TypeParamBound,
-    WhereClause,
+    parse_quote, Attribute, Block, FnArg, GenericParam, Generics, Ident, ImplItem, Lifetime, Pat,
+    PatIdent, Receiver, ReturnType, Signature, Stmt, Token, TraitItem, Type, TypeParamBound,
+    TypePath, WhereClause,
 };
 
+macro_rules! parse_quote_spanned {
+    ($span:expr=> $($t:tt)*) => {
+        syn::parse2(quote_spanned!($span=> $($t)*)).unwrap()
+    };
+}
+
 impl ToTokens for Item {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         match self {
@@ -26,14 +30,12 @@
 #[derive(Clone, Copy)]
 enum Context<'a> {
     Trait {
-        name: &'a Ident,
         generics: &'a Generics,
         supertraits: &'a Supertraits,
     },
     Impl {
         impl_generics: &'a Generics,
-        receiver: &'a Type,
-        as_trait: &'a Path,
+        associated_type_impl_traits: &'a Set<Ident>,
     },
 }
 
@@ -59,7 +61,6 @@
     match input {
         Item::Trait(input) => {
             let context = Context::Trait {
-                name: &input.ident,
                 generics: &input.generics,
                 supertraits: &input.supertraits,
             };
@@ -69,32 +70,40 @@
                     if sig.asyncness.is_some() {
                         let block = &mut method.default;
                         let mut has_self = has_self_in_sig(sig);
+                        method.attrs.push(parse_quote!(#[must_use]));
                         if let Some(block) = block {
                             has_self |= has_self_in_block(block);
-                            transform_block(context, sig, block, has_self, is_local);
-                            method
-                                .attrs
-                                .push(parse_quote!(#[allow(clippy::used_underscore_binding)]));
+                            transform_block(context, sig, block);
+                            method.attrs.push(lint_suppress_with_body());
+                        } else {
+                            method.attrs.push(lint_suppress_without_body());
                         }
                         let has_default = method.default.is_some();
                         transform_sig(context, sig, has_self, has_default, is_local);
-                        method.attrs.push(parse_quote!(#[must_use]));
                     }
                 }
             }
         }
         Item::Impl(input) => {
-            let mut lifetimes = CollectLifetimes::new("'impl");
+            let mut lifetimes = CollectLifetimes::new("'impl", input.impl_token.span);
             lifetimes.visit_type_mut(&mut *input.self_ty);
             lifetimes.visit_path_mut(&mut input.trait_.as_mut().unwrap().1);
             let params = &input.generics.params;
             let elided = lifetimes.elided;
             input.generics.params = parse_quote!(#(#elided,)* #params);
 
+            let mut associated_type_impl_traits = Set::new();
+            for inner in &input.items {
+                if let ImplItem::Type(assoc) = inner {
+                    if let Type::ImplTrait(_) = assoc.ty {
+                        associated_type_impl_traits.insert(assoc.ident.clone());
+                    }
+                }
+            }
+
             let context = Context::Impl {
                 impl_generics: &input.generics,
-                receiver: &input.self_ty,
-                as_trait: &input.trait_.as_ref().unwrap().1,
+                associated_type_impl_traits: &associated_type_impl_traits,
             };
             for inner in &mut input.items {
                 if let ImplItem::Method(method) = inner {
@@ -102,11 +111,9 @@
                     if sig.asyncness.is_some() {
                         let block = &mut method.block;
                         let has_self = has_self_in_sig(sig) || has_self_in_block(block);
-                        transform_block(context, sig, block, has_self, is_local);
+                        transform_block(context, sig, block);
                         transform_sig(context, sig, has_self, false, is_local);
-                        method
-                            .attrs
-                            .push(parse_quote!(#[allow(clippy::used_underscore_binding)]));
+                        method.attrs.push(lint_suppress_with_body());
                     }
                 }
             }
@@ -114,6 +121,26 @@
     }
 }
 
+fn lint_suppress_with_body() -> Attribute {
+    parse_quote! {
+        #[allow(
+            clippy::let_unit_value,
+            clippy::type_complexity,
+            clippy::type_repetition_in_bounds,
+            clippy::used_underscore_binding
+        )]
+    }
+}
+
+fn lint_suppress_without_body() -> Attribute {
+    parse_quote! {
+        #[allow(
+            clippy::type_complexity,
+            clippy::type_repetition_in_bounds
+        )]
+    }
+}
+
 // Input:
 //     async fn f<T>(&self, x: &T) -> Ret;
 //
@@ -141,7 +168,13 @@
         ReturnType::Type(_, ret) => quote!(#ret),
     };
 
-    let mut lifetimes = CollectLifetimes::new("'life");
+    let default_span = sig
+        .ident
+        .span()
+        .join(sig.paren_token.span)
+        .unwrap_or_else(|| sig.ident.span());
+
+    let mut lifetimes = CollectLifetimes::new("'life", default_span);
     for arg in sig.inputs.iter_mut() {
         match arg {
             FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg),
@@ -149,13 +182,6 @@
         }
     }
 
-    let where_clause = sig
-        .generics
-        .where_clause
-        .get_or_insert_with(|| WhereClause {
-            where_token: Default::default(),
-            predicates: Punctuated::new(),
-        });
     for param in sig
         .generics
         .params
@@ -165,33 +191,48 @@
         match param {
             GenericParam::Type(param) => {
                 let param = &param.ident;
-                where_clause
+                let span = param.span();
+                where_clause_or_default(&mut sig.generics.where_clause)
                     .predicates
-                    .push(parse_quote!(#param: 'async_trait));
+                    .push(parse_quote_spanned!(span=> #param: 'async_trait));
             }
             GenericParam::Lifetime(param) => {
                 let param = &param.lifetime;
-                where_clause
+                let span = param.span();
+                where_clause_or_default(&mut sig.generics.where_clause)
                     .predicates
-                    .push(parse_quote!(#param: 'async_trait));
+                    .push(parse_quote_spanned!(span=> #param: 'async_trait));
             }
             GenericParam::Const(_) => {}
         }
     }
+
+    if sig.generics.lt_token.is_none() {
+        sig.generics.lt_token = Some(Token![<](sig.ident.span()));
+    }
+    if sig.generics.gt_token.is_none() {
+        sig.generics.gt_token = Some(Token![>](sig.paren_token.span));
+    }
+
     for elided in lifetimes.elided {
         sig.generics.params.push(parse_quote!(#elided));
-        where_clause
+        where_clause_or_default(&mut sig.generics.where_clause)
             .predicates
-            .push(parse_quote!(#elided: 'async_trait));
+            .push(parse_quote_spanned!(elided.span()=> #elided: 'async_trait));
     }
-    sig.generics.params.push(parse_quote!('async_trait));
+
+    sig.generics
+        .params
+        .push(parse_quote_spanned!(default_span=> 'async_trait));
+
     if has_self {
-        let bound: Ident = match sig.inputs.iter().next() {
+        let bound_span = sig.ident.span();
+        let bound = match sig.inputs.iter().next() {
             Some(FnArg::Receiver(Receiver {
                 reference: Some(_),
                 mutability: None,
                 ..
-            })) => parse_quote!(Sync),
+            })) => Ident::new("Sync", bound_span),
             Some(FnArg::Typed(arg))
                 if match (arg.pat.as_ref(), arg.ty.as_ref()) {
                     (Pat::Ident(pat), Type::Reference(ty)) => {
@@ -200,18 +241,21 @@
                     _ => false,
                 } =>
             {
-                parse_quote!(Sync)
+                Ident::new("Sync", bound_span)
             }
-            _ => parse_quote!(Send),
+            _ => Ident::new("Send", bound_span),
         };
+
         let assume_bound = match context {
             Context::Trait { supertraits, .. } => !has_default || has_bound(supertraits, &bound),
             Context::Impl { .. } => true,
         };
+
+        let where_clause = where_clause_or_default(&mut sig.generics.where_clause);
         where_clause.predicates.push(if assume_bound || is_local {
-            parse_quote!(Self: 'async_trait)
+            parse_quote_spanned!(bound_span=> Self: 'async_trait)
         } else {
-            parse_quote!(Self: ::core::marker::#bound + 'async_trait)
+            parse_quote_spanned!(bound_span=> Self: ::core::marker::#bound + 'async_trait)
         });
     }
 
@@ -226,20 +270,21 @@
                     ident.by_ref = None;
                     ident.mutability = None;
                 } else {
-                    let positional = positional_arg(i);
-                    *arg.pat = parse_quote!(#positional);
+                    let positional = positional_arg(i, &arg.pat);
+                    let m = mut_pat(&mut arg.pat);
+                    arg.pat = parse_quote!(#m #positional);
                 }
             }
         }
     }
 
+    let ret_span = sig.ident.span();
     let bounds = if is_local {
-        quote!('async_trait)
+        quote_spanned!(ret_span=> 'async_trait)
     } else {
-        quote!(::core::marker::Send + 'async_trait)
+        quote_spanned!(ret_span=> ::core::marker::Send + 'async_trait)
     };
-
-    sig.output = parse_quote! {
+    sig.output = parse_quote_spanned! {ret_span=>
         -> ::core::pin::Pin<Box<
             dyn ::core::future::Future<Output = #ret> + #bounds
         >>
@@ -247,247 +292,105 @@
 }
 
 // Input:
-//     async fn f<T>(&self, x: &T) -> Ret {
-//         self + x
+//     async fn f<T>(&self, x: &T, (a, b): (A, B)) -> Ret {
+//         self + x + a + b
 //     }
 //
 // Output:
-//     async fn f<T, AsyncTrait>(_self: &AsyncTrait, x: &T) -> Ret {
-//         _self + x
-//     }
-//     Box::pin(async_trait_method::<T, Self>(self, x))
-fn transform_block(
-    context: Context,
-    sig: &mut Signature,
-    block: &mut Block,
-    has_self: bool,
-    is_local: bool,
-) {
+//     Box::pin(async move {
+//         let ___ret: Ret = {
+//             let __self = self;
+//             let x = x;
+//             let (a, b) = __arg1;
+//
+//             __self + x + a + b
+//         };
+//
+//         ___ret
+//     })
+fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) {
     if let Some(Stmt::Item(syn::Item::Verbatim(item))) = block.stmts.first() {
         if block.stmts.len() == 1 && item.to_string() == ";" {
             return;
         }
     }
 
-    let inner = format_ident!("__{}", sig.ident);
-    let args = sig.inputs.iter().enumerate().map(|(i, arg)| match arg {
-        FnArg::Receiver(Receiver { self_token, .. }) => quote!(#self_token),
-        FnArg::Typed(arg) => {
-            if let Pat::Ident(PatIdent { ident, .. }) = &*arg.pat {
-                quote!(#ident)
-            } else {
-                positional_arg(i).into_token_stream()
+    let mut self_span = None;
+    let decls = sig
+        .inputs
+        .iter()
+        .enumerate()
+        .map(|(i, arg)| match arg {
+            FnArg::Receiver(Receiver {
+                self_token,
+                mutability,
+                ..
+            }) => {
+                let ident = Ident::new("__self", self_token.span);
+                self_span = Some(self_token.span);
+                quote!(let #mutability #ident = #self_token;)
             }
-        }
-    });
-
-    let mut standalone = sig.clone();
-    standalone.ident = inner.clone();
-
-    let generics = match context {
-        Context::Trait { generics, .. } => generics,
-        Context::Impl { impl_generics, .. } => impl_generics,
-    };
-
-    let mut outer_generics = generics.clone();
-    for p in &mut outer_generics.params {
-        match p {
-            GenericParam::Type(t) => t.default = None,
-            GenericParam::Const(c) => c.default = None,
-            GenericParam::Lifetime(_) => {}
-        }
-    }
-    if !has_self {
-        if let Some(mut where_clause) = outer_generics.where_clause {
-            where_clause.predicates = where_clause
-                .predicates
-                .into_iter()
-                .filter_map(|mut pred| {
-                    if has_self_in_where_predicate(&mut pred) {
-                        None
+            FnArg::Typed(arg) => {
+                if let Pat::Ident(PatIdent {
+                    ident, mutability, ..
+                }) = &*arg.pat
+                {
+                    if ident == "self" {
+                        self_span = Some(ident.span());
+                        let prefixed = Ident::new("__self", ident.span());
+                        quote!(let #mutability #prefixed = #ident;)
                     } else {
-                        Some(pred)
+                        quote!(let #mutability #ident = #ident;)
                     }
-                })
-                .collect();
-            outer_generics.where_clause = Some(where_clause);
-        }
-    }
-
-    let fn_generics = mem::replace(&mut standalone.generics, outer_generics);
-    standalone.generics.params.extend(fn_generics.params);
-    if let Some(where_clause) = fn_generics.where_clause {
-        standalone
-            .generics
-            .make_where_clause()
-            .predicates
-            .extend(where_clause.predicates);
-    }
-
-    if has_async_lifetime(&mut standalone, block) {
-        standalone.generics.params.push(parse_quote!('async_trait));
-    }
-
-    let mut types = standalone
-        .generics
-        .type_params()
-        .map(|param| param.ident.clone())
+                } else {
+                    let pat = &arg.pat;
+                    let ident = positional_arg(i, pat);
+                    quote!(let #pat = #ident;)
+                }
+            }
+        })
         .collect::<Vec<_>>();
 
-    let mut self_bound = None::<TypeParamBound>;
-    match standalone.inputs.iter_mut().next() {
-        Some(
-            arg @ FnArg::Receiver(Receiver {
-                reference: Some(_), ..
-            }),
-        ) => {
-            let (lifetime, mutability, self_token) = match arg {
-                FnArg::Receiver(Receiver {
-                    reference: Some((_, lifetime)),
-                    mutability,
-                    self_token,
-                    ..
-                }) => (lifetime, mutability, self_token),
-                _ => unreachable!(),
-            };
-            let under_self = Ident::new("_self", self_token.span);
-            match context {
-                Context::Trait { .. } => {
-                    self_bound = Some(match mutability {
-                        Some(_) => parse_quote!(::core::marker::Send),
-                        None => parse_quote!(::core::marker::Sync),
-                    });
-                    *arg = parse_quote! {
-                        #under_self: &#lifetime #mutability AsyncTrait
-                    };
+    if let Some(span) = self_span {
+        let mut replace_self = ReplaceSelf(span);
+        replace_self.visit_block_mut(block);
+    }
+
+    let stmts = &block.stmts;
+    let let_ret = match &mut sig.output {
+        ReturnType::Default => quote_spanned! {block.brace_token.span=>
+            #(#decls)*
+            let _: () = { #(#stmts)* };
+        },
+        ReturnType::Type(_, ret) => {
+            if contains_associated_type_impl_trait(context, ret) {
+                if decls.is_empty() {
+                    quote!(#(#stmts)*)
+                } else {
+                    quote!(#(#decls)* { #(#stmts)* })
                 }
-                Context::Impl { receiver, .. } => {
-                    let mut ty = quote!(#receiver);
-                    if let Type::TraitObject(trait_object) = receiver {
-                        if trait_object.dyn_token.is_none() {
-                            ty = quote!(dyn #ty);
-                        }
-                        if trait_object.bounds.len() > 1 {
-                            ty = quote!((#ty));
-                        }
+            } else {
+                quote_spanned! {block.brace_token.span=>
+                    if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> {
+                        return __ret;
                     }
-                    *arg = parse_quote! {
-                        #under_self: &#lifetime #mutability #ty
-                    };
+                    #(#decls)*
+                    let __ret: #ret = { #(#stmts)* };
+                    #[allow(unreachable_code)]
+                    __ret
                 }
             }
         }
-        Some(arg @ FnArg::Receiver(_)) => {
-            let (self_token, mutability) = match arg {
-                FnArg::Receiver(Receiver {
-                    self_token,
-                    mutability,
-                    ..
-                }) => (self_token, mutability),
-                _ => unreachable!(),
-            };
-            let under_self = Ident::new("_self", self_token.span);
-            match context {
-                Context::Trait { .. } => {
-                    self_bound = Some(parse_quote!(::core::marker::Send));
-                    *arg = parse_quote! {
-                        #mutability #under_self: AsyncTrait
-                    };
-                }
-                Context::Impl { receiver, .. } => {
-                    *arg = parse_quote! {
-                        #mutability #under_self: #receiver
-                    };
-                }
-            }
-        }
-        Some(FnArg::Typed(arg)) => {
-            if let Pat::Ident(arg) = &mut *arg.pat {
-                if arg.ident == "self" {
-                    arg.ident = Ident::new("_self", arg.ident.span());
-                }
-            }
-        }
-        _ => {}
-    }
-
-    if let Context::Trait { name, generics, .. } = context {
-        if has_self {
-            let (_, generics, _) = generics.split_for_impl();
-            let mut self_param: TypeParam = parse_quote!(AsyncTrait: ?Sized + #name #generics);
-            if !is_local {
-                self_param.bounds.extend(self_bound);
-            }
-            let count = standalone
-                .generics
-                .params
-                .iter()
-                .take_while(|param| {
-                    if let GenericParam::Const(_) = param {
-                        false
-                    } else {
-                        true
-                    }
-                })
-                .count();
-            standalone
-                .generics
-                .params
-                .insert(count, GenericParam::Type(self_param));
-            types.push(Ident::new("Self", Span::call_site()));
-        }
-    }
-
-    if let Some(where_clause) = &mut standalone.generics.where_clause {
-        // Work around an input bound like `where Self::Output: Send` expanding
-        // to `where <AsyncTrait>::Output: Send` which is illegal syntax because
-        // `where<T>` is reserved for future use... :(
-        where_clause.predicates.insert(0, parse_quote!((): Sized));
-    }
-
-    let mut replace = match context {
-        Context::Trait { .. } => ReplaceReceiver::with(parse_quote!(AsyncTrait)),
-        Context::Impl {
-            receiver, as_trait, ..
-        } => ReplaceReceiver::with_as_trait(receiver.clone(), as_trait.clone()),
     };
-    replace.visit_signature_mut(&mut standalone);
-    replace.visit_block_mut(block);
-
-    let mut generics = types;
-    let consts = standalone
-        .generics
-        .const_params()
-        .map(|param| param.ident.clone());
-    generics.extend(consts);
-
-    let allow_non_snake_case = if sig.ident != sig.ident.to_string().to_lowercase() {
-        Some(quote!(non_snake_case,))
-    } else {
-        None
-    };
-
-    let brace = block.brace_token;
-    let box_pin = quote_spanned!(brace.span=> {
-        #[allow(
-            #allow_non_snake_case
-            unused_parens, // https://github.com/dtolnay/async-trait/issues/118
-            clippy::missing_docs_in_private_items,
-            clippy::needless_lifetimes,
-            clippy::ptr_arg,
-            clippy::trivially_copy_pass_by_ref,
-            clippy::type_repetition_in_bounds,
-            clippy::used_underscore_binding,
-        )]
-        #standalone #block
-        Box::pin(#inner::<#(#generics),*>(#(#args),*))
-    });
-    *block = parse_quote!(#box_pin);
-    block.brace_token = brace;
+    let box_pin = quote_spanned!(block.brace_token.span=>
+        Box::pin(async move { #let_ret })
+    );
+    block.stmts = parse_quote!(#box_pin);
 }
 
-fn positional_arg(i: usize) -> Ident {
-    format_ident!("__arg{}", i)
+fn positional_arg(i: usize, pat: &Pat) -> Ident {
+    use syn::spanned::Spanned;
+    format_ident!("__arg{}", i, span = pat.span())
 }
 
 fn has_bound(supertraits: &Supertraits, marker: &Ident) -> bool {
@@ -500,3 +403,45 @@
     }
     false
 }
+
+fn contains_associated_type_impl_trait(context: Context, ret: &mut Type) -> bool {
+    struct AssociatedTypeImplTraits<'a> {
+        set: &'a Set<Ident>,
+        contains: bool,
+    }
+
+    impl<'a> VisitMut for AssociatedTypeImplTraits<'a> {
+        fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
+            if ty.qself.is_none()
+                && ty.path.segments.len() == 2
+                && ty.path.segments[0].ident == "Self"
+                && self.set.contains(&ty.path.segments[1].ident)
+            {
+                self.contains = true;
+            }
+            visit_mut::visit_type_path_mut(self, ty);
+        }
+    }
+
+    match context {
+        Context::Trait { .. } => false,
+        Context::Impl {
+            associated_type_impl_traits,
+            ..
+        } => {
+            let mut visit = AssociatedTypeImplTraits {
+                set: associated_type_impl_traits,
+                contains: false,
+            };
+            visit.visit_type_mut(ret);
+            visit.contains
+        }
+    }
+}
+
+fn where_clause_or_default(clause: &mut Option<WhereClause>) -> &mut WhereClause {
+    clause.get_or_insert_with(|| WhereClause {
+        where_token: Default::default(),
+        predicates: Punctuated::new(),
+    })
+}
diff --git a/src/lib.rs b/src/lib.rs
index 929af4f..100bee6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -303,7 +303,16 @@
 //! let object = &value as &dyn ObjectSafe;
 //! ```
 
-#![allow(clippy::match_like_matches_macro)] // matches! requires Rust 1.42
+#![allow(
+    clippy::default_trait_access,
+    clippy::doc_markdown,
+    clippy::if_not_else,
+    clippy::items_after_statements,
+    clippy::module_name_repetitions,
+    clippy::shadow_unrelated,
+    clippy::similar_names,
+    clippy::too_many_lines
+)]
 
 extern crate proc_macro;
 
@@ -312,7 +321,6 @@
 mod lifetime;
 mod parse;
 mod receiver;
-mod respan;
 
 use crate::args::Args;
 use crate::expand::expand;
diff --git a/src/lifetime.rs b/src/lifetime.rs
index 9d2066b..ff25d32 100644
--- a/src/lifetime.rs
+++ b/src/lifetime.rs
@@ -1,59 +1,43 @@
 use proc_macro2::Span;
 use syn::visit_mut::{self, VisitMut};
-use syn::{Block, GenericArgument, Item, Lifetime, Receiver, Signature, TypeReference};
-
-pub fn has_async_lifetime(sig: &mut Signature, block: &mut Block) -> bool {
-    let mut visitor = HasAsyncLifetime(false);
-    visitor.visit_signature_mut(sig);
-    visitor.visit_block_mut(block);
-    visitor.0
-}
-
-struct HasAsyncLifetime(bool);
-
-impl VisitMut for HasAsyncLifetime {
-    fn visit_lifetime_mut(&mut self, life: &mut Lifetime) {
-        self.0 |= life.to_string() == "'async_trait";
-    }
-
-    fn visit_item_mut(&mut self, _: &mut Item) {
-        // Do not recurse into nested items.
-    }
-}
+use syn::{GenericArgument, Lifetime, Receiver, TypeReference};
 
 pub struct CollectLifetimes {
     pub elided: Vec<Lifetime>,
     pub explicit: Vec<Lifetime>,
     pub name: &'static str,
+    pub default_span: Span,
 }
 
 impl CollectLifetimes {
-    pub fn new(name: &'static str) -> Self {
+    pub fn new(name: &'static str, default_span: Span) -> Self {
         CollectLifetimes {
             elided: Vec::new(),
             explicit: Vec::new(),
             name,
+            default_span,
         }
     }
 
     fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) {
         match lifetime {
-            None => *lifetime = Some(self.next_lifetime()),
+            None => *lifetime = Some(self.next_lifetime(None)),
             Some(lifetime) => self.visit_lifetime(lifetime),
         }
     }
 
     fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
         if lifetime.ident == "_" {
-            *lifetime = self.next_lifetime();
+            *lifetime = self.next_lifetime(lifetime.span());
         } else {
             self.explicit.push(lifetime.clone());
         }
     }
 
-    fn next_lifetime(&mut self) -> Lifetime {
+    fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime {
         let name = format!("{}{}", self.name, self.elided.len());
-        let life = Lifetime::new(&name, Span::call_site());
+        let span = span.into().unwrap_or(self.default_span);
+        let life = Lifetime::new(&name, span);
         self.elided.push(life.clone());
         life
     }
diff --git a/src/receiver.rs b/src/receiver.rs
index 4273359..64ab65e 100644
--- a/src/receiver.rs
+++ b/src/receiver.rs
@@ -1,14 +1,9 @@
-use crate::respan::respan;
-use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree};
-use quote::{quote, quote_spanned};
+use proc_macro2::{Group, Span, TokenStream, TokenTree};
 use std::iter::FromIterator;
-use std::mem;
-use syn::punctuated::Punctuated;
 use syn::visit_mut::{self, VisitMut};
 use syn::{
-    parse_quote, Block, Error, ExprPath, ExprStruct, Ident, Item, Macro, PatPath, PatStruct,
-    PatTupleStruct, Path, PathArguments, QSelf, Receiver, Signature, Token, Type, TypePath,
-    WherePredicate,
+    Block, ExprPath, Ident, Item, Macro, Pat, PatIdent, PatPath, Receiver, Signature, Token,
+    TypePath,
 };
 
 pub fn has_self_in_sig(sig: &mut Signature) -> bool {
@@ -17,12 +12,6 @@
     visitor.0
 }
 
-pub fn has_self_in_where_predicate(where_predicate: &mut WherePredicate) -> bool {
-    let mut visitor = HasSelf(false);
-    visitor.visit_where_predicate_mut(where_predicate);
-    visitor.0
-}
-
 pub fn has_self_in_block(block: &mut Block) -> bool {
     let mut visitor = HasSelf(false);
     visitor.visit_block_mut(block);
@@ -37,6 +26,32 @@
     })
 }
 
+pub fn mut_pat(pat: &mut Pat) -> Option<Token![mut]> {
+    let mut visitor = HasMutPat(None);
+    visitor.visit_pat_mut(pat);
+    visitor.0
+}
+
+fn contains_fn(tokens: TokenStream) -> bool {
+    tokens.into_iter().any(|tt| match tt {
+        TokenTree::Ident(ident) => ident == "fn",
+        TokenTree::Group(group) => contains_fn(group.stream()),
+        _ => false,
+    })
+}
+
+struct HasMutPat(Option<Token![mut]>);
+
+impl VisitMut for HasMutPat {
+    fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) {
+        if let Some(m) = i.mutability {
+            self.0 = Some(m);
+        } else {
+            visit_mut::visit_pat_ident_mut(self, i);
+        }
+    }
+}
+
 struct HasSelf(bool);
 
 impl VisitMut for HasSelf {
@@ -70,225 +85,67 @@
     }
 }
 
-pub struct ReplaceReceiver {
-    pub with: Type,
-    pub as_trait: Option<Path>,
-}
+pub struct ReplaceSelf(pub Span);
 
-impl ReplaceReceiver {
-    pub fn with(ty: Type) -> Self {
-        ReplaceReceiver {
-            with: ty,
-            as_trait: None,
-        }
-    }
-
-    pub fn with_as_trait(ty: Type, as_trait: Path) -> Self {
-        ReplaceReceiver {
-            with: ty,
-            as_trait: Some(as_trait),
-        }
-    }
-
-    fn self_ty(&self, span: Span) -> Type {
-        respan(&self.with, span)
-    }
-
-    fn self_to_qself_type(&self, qself: &mut Option<QSelf>, path: &mut Path) {
-        let include_as_trait = true;
-        self.self_to_qself(qself, path, include_as_trait);
-    }
-
-    fn self_to_qself_expr(&self, qself: &mut Option<QSelf>, path: &mut Path) {
-        let include_as_trait = false;
-        self.self_to_qself(qself, path, include_as_trait);
-    }
-
-    fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path, include_as_trait: bool) {
-        if path.leading_colon.is_some() {
-            return;
-        }
-
-        let first = &path.segments[0];
-        if first.ident != "Self" || !first.arguments.is_empty() {
-            return;
-        }
-
-        if path.segments.len() == 1 {
-            self.self_to_expr_path(path);
-            return;
-        }
-
-        let span = first.ident.span();
-        *qself = Some(QSelf {
-            lt_token: Token![<](span),
-            ty: Box::new(self.self_ty(span)),
-            position: 0,
-            as_token: None,
-            gt_token: Token![>](span),
-        });
-
-        if include_as_trait && self.as_trait.is_some() {
-            let as_trait = self.as_trait.as_ref().unwrap().clone();
-            path.leading_colon = as_trait.leading_colon;
-            qself.as_mut().unwrap().position = as_trait.segments.len();
-
-            let segments = mem::replace(&mut path.segments, as_trait.segments);
-            path.segments.push_punct(Default::default());
-            path.segments.extend(segments.into_pairs().skip(1));
-        } else {
-            path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
-
-            let segments = mem::replace(&mut path.segments, Punctuated::new());
-            path.segments = segments.into_pairs().skip(1).collect();
-        }
-    }
-
-    fn self_to_expr_path(&self, path: &mut Path) {
-        if path.leading_colon.is_some() {
-            return;
-        }
-
-        let first = &path.segments[0];
-        if first.ident != "Self" || !first.arguments.is_empty() {
-            return;
-        }
-
-        if let Type::Path(self_ty) = self.self_ty(first.ident.span()) {
-            let variant = mem::replace(path, self_ty.path);
-            for segment in &mut path.segments {
-                if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
-                    if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
-                        bracketed.colon2_token = Some(Default::default());
-                    }
-                }
-            }
-            if variant.segments.len() > 1 {
-                path.segments.push_punct(Default::default());
-                path.segments.extend(variant.segments.into_pairs().skip(1));
-            }
-        } else {
-            let span = path.segments[0].ident.span();
-            let msg = "Self type of this impl is unsupported in expression position";
-            let error = Error::new(span, msg).to_compile_error();
-            *path = parse_quote!(::core::marker::PhantomData::<#error>);
-        }
-    }
-
-    fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool {
-        let mut out = Vec::new();
-        let mut modified = false;
-        let mut iter = tokens.clone().into_iter().peekable();
-        while let Some(tt) = iter.next() {
-            match tt {
-                TokenTree::Ident(mut ident) => {
-                    modified |= prepend_underscore_to_self(&mut ident);
-                    if ident == "Self" {
-                        modified = true;
-                        if self.as_trait.is_none() {
-                            let ident = Ident::new("AsyncTrait", ident.span());
-                            out.push(TokenTree::Ident(ident));
-                        } else {
-                            let self_ty = self.self_ty(ident.span());
-                            match iter.peek() {
-                                Some(TokenTree::Punct(p))
-                                    if p.as_char() == ':' && p.spacing() == Spacing::Joint =>
-                                {
-                                    let next = iter.next().unwrap();
-                                    match iter.peek() {
-                                        Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
-                                            let span = ident.span();
-                                            out.extend(quote_spanned!(span=> <#self_ty>));
-                                        }
-                                        _ => out.extend(quote!(#self_ty)),
-                                    }
-                                    out.push(next);
-                                }
-                                _ => out.extend(quote!(#self_ty)),
-                            }
-                        }
-                    } else {
-                        out.push(TokenTree::Ident(ident));
-                    }
-                }
-                TokenTree::Group(group) => {
-                    let mut content = group.stream();
-                    modified |= self.visit_token_stream(&mut content);
-                    let mut new = Group::new(group.delimiter(), content);
-                    new.set_span(group.span());
-                    out.push(TokenTree::Group(new));
-                }
-                other => out.push(other),
-            }
-        }
+impl ReplaceSelf {
+    #[cfg_attr(not(self_span_hack), allow(clippy::unused_self))]
+    fn prepend_underscore_to_self(&self, ident: &mut Ident) -> bool {
+        let modified = ident == "self";
         if modified {
-            *tokens = TokenStream::from_iter(out);
+            *ident = Ident::new("__self", ident.span());
+            #[cfg(self_span_hack)]
+            ident.set_span(self.0);
         }
         modified
     }
+
+    fn visit_token_stream(&mut self, tokens: &mut TokenStream) -> bool {
+        let mut out = Vec::new();
+        let mut modified = false;
+        visit_token_stream_impl(self, tokens.clone(), &mut modified, &mut out);
+        if modified {
+            *tokens = TokenStream::from_iter(out);
+        }
+        return modified;
+
+        fn visit_token_stream_impl(
+            visitor: &mut ReplaceSelf,
+            tokens: TokenStream,
+            modified: &mut bool,
+            out: &mut Vec<TokenTree>,
+        ) {
+            for tt in tokens {
+                match tt {
+                    TokenTree::Ident(mut ident) => {
+                        *modified |= visitor.prepend_underscore_to_self(&mut ident);
+                        out.push(TokenTree::Ident(ident));
+                    }
+                    TokenTree::Group(group) => {
+                        let mut content = group.stream();
+                        *modified |= visitor.visit_token_stream(&mut content);
+                        let mut new = Group::new(group.delimiter(), content);
+                        new.set_span(group.span());
+                        out.push(TokenTree::Group(new));
+                    }
+                    other => out.push(other),
+                }
+            }
+        }
+    }
 }
 
-impl VisitMut for ReplaceReceiver {
-    // `Self` -> `Receiver`
-    fn visit_type_mut(&mut self, ty: &mut Type) {
-        if let Type::Path(node) = ty {
-            if node.qself.is_none() && node.path.is_ident("Self") {
-                *ty = self.self_ty(node.path.segments[0].ident.span());
-            } else {
-                self.visit_type_path_mut(node);
-            }
-        } else {
-            visit_mut::visit_type_mut(self, ty);
-        }
-    }
-
-    // `Self::Assoc` -> `<Receiver>::Assoc`
-    fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
-        if ty.qself.is_none() {
-            self.self_to_qself_type(&mut ty.qself, &mut ty.path);
-        }
-        visit_mut::visit_type_path_mut(self, ty);
-    }
-
-    // `Self::method` -> `<Receiver>::method`
-    fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
-        if expr.qself.is_none() {
-            prepend_underscore_to_self(&mut expr.path.segments[0].ident);
-            self.self_to_qself_expr(&mut expr.qself, &mut expr.path);
-        }
-        visit_mut::visit_expr_path_mut(self, expr);
-    }
-
-    fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) {
-        self.self_to_expr_path(&mut expr.path);
-        visit_mut::visit_expr_struct_mut(self, expr);
-    }
-
-    fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
-        if pat.qself.is_none() {
-            self.self_to_qself_expr(&mut pat.qself, &mut pat.path);
-        }
-        visit_mut::visit_pat_path_mut(self, pat);
-    }
-
-    fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
-        self.self_to_expr_path(&mut pat.path);
-        visit_mut::visit_pat_struct_mut(self, pat);
-    }
-
-    fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) {
-        self.self_to_expr_path(&mut pat.path);
-        visit_mut::visit_pat_tuple_struct_mut(self, pat);
+impl VisitMut for ReplaceSelf {
+    fn visit_ident_mut(&mut self, i: &mut Ident) {
+        self.prepend_underscore_to_self(i);
     }
 
     fn visit_item_mut(&mut self, i: &mut Item) {
-        match i {
-            // Visit `macro_rules!` because locally defined macros can refer to `self`.
-            Item::Macro(i) if i.mac.path.is_ident("macro_rules") => {
+        // Visit `macro_rules!` because locally defined macros can refer to
+        // `self`. Otherwise, do not recurse into nested items.
+        if let Item::Macro(i) = i {
+            if i.mac.path.is_ident("macro_rules") {
                 self.visit_macro_mut(&mut i.mac)
             }
-            // Otherwise, do not recurse into nested items.
-            _ => {}
         }
     }
 
@@ -303,19 +160,3 @@
         }
     }
 }
-
-fn contains_fn(tokens: TokenStream) -> bool {
-    tokens.into_iter().any(|tt| match tt {
-        TokenTree::Ident(ident) => ident == "fn",
-        TokenTree::Group(group) => contains_fn(group.stream()),
-        _ => false,
-    })
-}
-
-fn prepend_underscore_to_self(ident: &mut Ident) -> bool {
-    let modified = ident == "self";
-    if modified {
-        *ident = Ident::new("_self", ident.span());
-    }
-    modified
-}
diff --git a/src/respan.rs b/src/respan.rs
deleted file mode 100644
index 38f6612..0000000
--- a/src/respan.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use proc_macro2::{Span, TokenStream};
-use quote::ToTokens;
-use syn::parse::Parse;
-
-pub(crate) fn respan<T>(node: &T, span: Span) -> T
-where
-    T: ToTokens + Parse,
-{
-    let tokens = node.to_token_stream();
-    let respanned = respan_tokens(tokens, span);
-    syn::parse2(respanned).unwrap()
-}
-
-fn respan_tokens(tokens: TokenStream, span: Span) -> TokenStream {
-    tokens
-        .into_iter()
-        .map(|mut token| {
-            token.set_span(span);
-            token
-        })
-        .collect()
-}