use proc_macro::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
use syn::visit_mut::{self, VisitMut};
use syn::{Expr, ExprTry, ItemFn, parse_macro_input};
struct TryRewriter;
impl VisitMut for TryRewriter {
fn visit_expr_mut(&mut self, expr: &mut Expr) {
visit_mut::visit_expr_mut(self, expr);
if let Expr::Try(ExprTry { expr: inner, question_token, .. }) = expr {
let inner = (**inner).clone();
let q_span = question_token.span();
let caller = quote_spanned! { q_span =>
::std::panic::Location::caller()
};
let replacement: Expr = syn::parse_quote! {
match #inner {
::core::result::Result::Ok(__v) => __v,
::core::result::Result::Err(__e) => {
return ::core::result::Result::Err(
::traced_error::__macro::WrapErr(__e).__resolve(#caller)
);
}
}
};
*expr = replacement;
}
}
fn visit_item_fn_mut(&mut self, _: &mut ItemFn) {}
}
#[proc_macro_attribute]
pub fn traced(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut item_fn = parse_macro_input!(item as ItemFn);
TryRewriter.visit_block_mut(&mut item_fn.block);
let use_stmt: syn::Stmt = syn::parse_quote! {
#[allow(unused_imports)]
use ::traced_error::__macro::ResolveFallback as _;
};
item_fn.block.stmts.insert(0, use_stmt);
quote!(#item_fn).into()
}