#![allow(nonstandard_style, unused_imports, clippy::complexity, clippy::style)]
//! Internal crate, do not use it directly.
extern crate proc_macro;
use ::core::{mem, ops::Not as _};
use ::proc_macro::TokenStream;
use ::proc_macro2::{
Span,
TokenStream as TokenStream2,
};
use ::quote::{
format_ident,
quote,
quote_spanned,
ToTokens,
};
use ::syn::{*,
parse::{Parse, Parser, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
visit_mut::VisitMut,
Result,
};
use self::{
append_captures_hack_to_impl_occurrences::append_captures_hack_to_impl_occurrences,
collect_lifetime_params::collect_lifetime_params,
manually_unsugar_async::manually_unsugar_async,
params::Params,
};
mod append_captures_hack_to_impl_occurrences;
mod collect_lifetime_params;
mod manually_unsugar_async;
mod params;
#[cfg(feature = "showme")]
mod showme;
/// feature = "proc-macros"
See [the crate docs](https://docs.rs/fix_hidden_lifetime_bug) for more info.
#[proc_macro_attribute] pub
fn fix_hidden_lifetime_bug (
attrs: TokenStream,
input: TokenStream,
) -> TokenStream
{
let Params {
krate,
showme,
} = parse_macro_input!(attrs);
let ref krate = krate.unwrap_or_else(|| parse_quote!(
::fix_hidden_lifetime_bug
));
match parse_macro_input!(input) {
| Item::Fn(ItemFn {
attrs, vis, sig, block,
}) => {
let fun = ImplItemMethod {
attrs, vis, sig, block: *block, defaultness: None,
};
fix_fn(krate, fun, None).map(ToTokens::into_token_stream)
},
| Item::Impl(impl_) => fix_impl(krate, impl_).map(ToTokens::into_token_stream),
| _ => Err(Error::new(
Span::call_site(),
"expected `fn`, or `impl` block",
)),
}
.map(|output| {
let _ = showme;
#[cfg(feature = "showme")] {
if showme.is_some() {
showme::pretty_print_tokenstream(&output);
eprintln!("{}", showme::BANNER);
}
}
output
})
.unwrap_or_else(|err| err.to_compile_error())
.into()
}
fn fix_fn (
krate: &'_ Path,
mut fun: ImplItemMethod,
outer_scope: Option<&'_ mut ItemImpl>,
) -> Result
{
let ref lifetimes = collect_lifetime_params(&mut fun.sig, outer_scope);
if fun.sig.asyncness.is_some() {
fun = manually_unsugar_async(krate, fun);
}
append_captures_hack_to_impl_occurrences(
krate,
lifetimes,
&mut fun.sig.output,
);
fun.attrs.push(parse_quote!(
#[allow(clippy::style, clippy::pedantic, clippy::complexity)]
));
Ok(fun)
}
fn fix_impl (
krate: &'_ Path,
mut impl_: ItemImpl,
) -> Result
{
if let Some((_, ref trait_, _)) = impl_.trait_ {
return Err(Error::new_spanned(
trait_,
"`#[fix_hidden_lifetime_bug]` does not support traits yet.",
));
}
let items = mem::take(&mut impl_.items);
impl_.items = items.into_iter().map(|it| Ok(match it {
| ImplItem::Method(mut fun) => {
let mut process_current = false;
fun.attrs.retain(|attr| (
attr.path.segments.last().unwrap().ident
!=
"fix_hidden_lifetime_bug"
|| {
process_current = true;
false
}
));
if process_current {
fun = fix_fn(krate, fun, Some(&mut impl_))?;
}
ImplItem::Method(fun)
},
| _ => it,
})).collect::>()?;
Ok(impl_.into_token_stream())
}
/* Uncomment to debug panics on parse_quote calls */
// macro_rules! __parse_quote__ {(
// $($code:tt)*
// ) => (
// (|| {
// fn type_of_some (_: Option)
// -> &'static str
// {
// ::core::any::type_name::()
// }
// let target_ty = None; if false { return target_ty.unwrap(); }
// let code = ::quote::quote!( $($code)* );
// eprintln!(
// "[{}:{}:{}:parse_quote!]\n - ty: `{ty}`\n - code: `{code}`",
// file!(), line!(), column!(),
// code = code,
// ty = type_of_some(target_ty),
// );
// ::syn::parse_quote!( #code )
// })()
// )} use __parse_quote__ as parse_quote;