1use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, ItemFn, ReturnType, Type};
6
7#[proc_macro_attribute]
13pub fn skipper(attr: TokenStream, item: TokenStream) -> TokenStream {
14 if !attr.is_empty() {
15 return syn::Error::new(
16 proc_macro2::Span::call_site(),
17 "#[skipper] takes no arguments",
18 )
19 .to_compile_error()
20 .into();
21 }
22 let mut f = parse_macro_input!(item as ItemFn);
23 let ret = match &f.sig.output {
24 ReturnType::Default => quote!(return;),
25 ReturnType::Type(_, ty) if is_result(ty) => quote!(return ::core::result::Result::Ok(());),
26 ReturnType::Type(_, ty) => {
27 return syn::Error::new_spanned(
28 ty,
29 "#[skipper] supports tests returning () or Result<(), E>",
30 )
31 .to_compile_error()
32 .into()
33 }
34 };
35 let name = f.sig.ident.to_string();
36 let check: syn::Stmt = syn::parse_quote! {
37 if ::get_skipper::__should_skip(::core::file!(), ::core::module_path!(), #name) {
38 #ret
39 }
40 };
41 f.block.stmts.insert(0, check);
42 quote!(#f).into()
43}
44
45fn is_result(ty: &Type) -> bool {
46 matches!(ty, Type::Path(p) if p.path.segments.last().is_some_and(|s| s.ident == "Result"))
47}