pub fn emulate_functionlike_macro_expansion<'a, F>(
    file: File,
    macro_paths_and_proc_macro_fns: &[(&'a str, F)]
) -> Result<(), Error>
where F: Fn(TokenStream) -> TokenStream,
Expand description

Searches the given Rust source code file for function-like macro calls and calls the functions that define how to expand them.

Each time it finds one, this function calls the corresponding procedural macro function, passing it the inner TokenStream just as if the macro were being expanded. The only effect is to verify that the macro doesn’t panic, as the expansion is not actually applied to the AST or the source code.

Note that this parser only handles Rust’s syntax, so it cannot resolve paths to see if they are equivalent to the given one. The paths used to reference the macro must be exactly equal to the one given in order to be expanded by this function. For example, if macro_path is "foo" and the file provided calls the macro using bar::foo!, this function will not know to expand it, and the macro’s code coverage will be underestimated.

Also, this function uses proc_macro2::TokenStream, not the standard proc_macro::TokenStream. The Rust compiler disallows using the proc_macro API for anything except defining a procedural macro (i.e. we can’t use it at runtime). You can convert between the two types using their into methods, as shown below.

§Returns

Ok on success, or an instance of Error indicating any error that occurred when trying to read or parse the file.

§Example


#[proc_macro]
fn remove(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
    // This stub just allows us to use `proc_macro2` instead of `proc_macro`.
    remove_internal(ts.into()).into()
}

fn remove_internal(_: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
    // This macro just eats its input and replaces it with nothing.
    proc_macro2::TokenStream::new()
}

#[test]
fn macro_code_coverage() {
    let file = std::fs::File::open("tests/tests.rs").unwrap();
    emulate_functionlike_macro_expansion(file, &[("remove", remove_internal)]).unwrap();
}