use crate::build_rs::BuildInfo;
use crate::gen::common;
use crate::spec::ProbeCallSpecification;
use crate::{TracersResult, TracingTarget};
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
pub(crate) fn generate_probe_call(
build_info: &BuildInfo,
call: ProbeCallSpecification,
) -> TracersResult<TokenStream> {
assert!(!build_info.implementation.is_dynamic());
match call {
ProbeCallSpecification::FireOnly(details) => {
match build_info.implementation.tracing_target() {
TracingTarget::Disabled => {
let call = details.call;
Ok(quote! {
if false {
#[allow(deprecated)]
#call
}
})
}
target @ TracingTarget::NoOp
| target @ TracingTarget::Stap
| target @ TracingTarget::Lttng => {
let mut mod_path = details.provider.clone();
let (provider, _) = mod_path
.segments
.pop()
.expect("provider path can't be empty")
.into_tuple();
let mod_name = syn::Ident::new(
&common::get_provider_impl_mod_name(&provider.ident),
provider.span(),
);
mod_path.segments.push(mod_name.into());
let probe = &details.probe;
let conditional_expression = match target {
TracingTarget::NoOp => {
quote! { false }
}
TracingTarget::Stap | TracingTarget::Lttng => {
let func_name = syn::Ident::new(
&format!("{}_enabled", &details.probe.ident),
details.probe.span(),
);
quote! { unsafe { #mod_path::#func_name() } }
}
_ => unreachable!(),
};
let args_with_var_names: Vec<_> = details
.args
.iter()
.enumerate()
.map(|(index, arg)| {
let span = arg.span();
let arg_name = syn::Ident::new(&format!("__tracer_arg{}", index), span);
(arg, arg_name)
})
.collect();
let wrapped_var_names = common::generate_tuple(
args_with_var_names.iter().map(|(_, arg_name)| arg_name),
);
let arg_names: Vec<_> =
args_with_var_names.iter().map(|(arg, _)| arg).collect();
let probe_parameters: Vec<_> = args_with_var_names
.iter()
.map(|(_, arg_name)| {
quote! { #arg_name.as_c_type() }
})
.collect();
let wrap_statement = if !details.args.is_empty() {
let wrap_func = syn::Ident::new(
&format!("__{}_wrap", details.probe.ident),
details.probe.span(),
);
quote! { let (#wrapped_var_names) = #mod_path::#wrap_func(#(#arg_names),*); }
} else {
quote! {}
};
let unsafe_block = if target == TracingTarget::NoOp {
quote! {}
} else {
quote! { unsafe }
};
let span = details.call.span();
Ok(quote_spanned! {span=>
{
use ::tracers::runtime::ProbeArgWrapper as _;
if #conditional_expression {
#wrap_statement
#unsafe_block { #mod_path::#probe(#(#probe_parameters),*); }
}
}
})
}
}
}
ProbeCallSpecification::FireWithCode { .. } => unimplemented!(),
}
}