diff --git a/Cargo.toml b/Cargo.toml index d99bf18..7475689 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = { version = "2.0", features = ["full", "visit-mut"] } +syn = { version = "2.0.9", features = ["full", "visit-mut"] } [dev-dependencies] futures = "0.3" diff --git a/src/expand.rs b/src/expand.rs index 362ba78..0a1ef1c 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -2,6 +2,7 @@ use crate::bound::{has_bound, InferredBound, Supertraits}; use crate::lifetime::{AddLifetimeToImplTrait, CollectLifetimes}; use crate::parse::Item; use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf}; +use crate::verbatim::VerbatimFn; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, quote_spanned, ToTokens}; use std::collections::BTreeSet as Set; @@ -11,7 +12,7 @@ use syn::visit_mut::{self, VisitMut}; use syn::{ parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericArgument, GenericParam, Generics, Ident, ImplItem, Lifetime, LifetimeParam, Pat, PatIdent, PathArguments, Receiver, - ReturnType, Signature, Stmt, Token, TraitItem, Type, TypePath, WhereClause, + ReturnType, Signature, Token, TraitItem, Type, TypePath, WhereClause, }; impl ToTokens for Item { @@ -94,15 +95,27 @@ pub fn expand(input: &mut Item, is_local: bool) { associated_type_impl_traits: &associated_type_impl_traits, }; for inner in &mut input.items { - if let ImplItem::Fn(method) = inner { - let sig = &mut method.sig; - if sig.asyncness.is_some() { + match inner { + ImplItem::Fn(method) if method.sig.asyncness.is_some() => { + let sig = &mut method.sig; let block = &mut method.block; let has_self = has_self_in_sig(sig) || has_self_in_block(block); transform_block(context, sig, block); transform_sig(context, sig, has_self, false, is_local); method.attrs.push(lint_suppress_with_body()); } + ImplItem::Verbatim(tokens) => { + let mut method = match syn::parse2::(tokens.clone()) { + Ok(method) if method.sig.asyncness.is_some() => method, + _ => continue, + }; + let sig = &mut method.sig; + let has_self = has_self_in_sig(sig); + transform_sig(context, sig, has_self, false, is_local); + method.attrs.push(lint_suppress_with_body()); + *tokens = quote!(#method); + } + _ => {} } } } @@ -329,12 +342,6 @@ fn transform_sig( // ___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 mut self_span = None; let decls = sig .inputs diff --git a/src/lib.rs b/src/lib.rs index ec893f6..090a10c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -325,6 +325,7 @@ mod expand; mod lifetime; mod parse; mod receiver; +mod verbatim; use crate::args::Args; use crate::expand::expand; diff --git a/src/verbatim.rs b/src/verbatim.rs new file mode 100644 index 0000000..d064f6e --- /dev/null +++ b/src/verbatim.rs @@ -0,0 +1,34 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::parse::{Parse, ParseStream, Result}; +use syn::{Attribute, Signature, Token, Visibility}; + +pub struct VerbatimFn { + pub attrs: Vec, + pub vis: Visibility, + pub defaultness: Option, + pub sig: Signature, + pub semi_token: Token![;], +} + +impl Parse for VerbatimFn { + fn parse(input: ParseStream) -> Result { + Ok(VerbatimFn { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + defaultness: input.parse()?, + sig: input.parse()?, + semi_token: input.parse()?, + }) + } +} + +impl ToTokens for VerbatimFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.attrs); + self.vis.to_tokens(tokens); + self.defaultness.to_tokens(tokens); + self.sig.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } +}