1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
 * Copyright (c) 2020 Ayush Kumar Mishra
 *
 * This source code is licensed under the MIT License found in
 * the LICENSE file in the root directory of this source tree.
 */
extern crate proc_macro;
use proc_macro::{TokenStream, TokenTree};

/// This attribute will enable a function to access the caller's source location.
#[proc_macro_attribute]
pub fn trace(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let mut prefix: TokenStream = "
    use backtrace::{Backtrace, BacktraceFrame};
    let (trace, curr_file, curr_line) = (Backtrace::new(), file!(), line!());
    let frames = trace.frames();
    let previous_symbol = frames
        .iter()
        .flat_map(BacktraceFrame::symbols)
        .skip_while(|s| {
            s.filename()
                .map(|p| !p.ends_with(curr_file))
                .unwrap_or(true)
                || s.lineno() != Some(curr_line)
        })
        .nth(1 as usize)
        .unwrap();

        println!(\"Called from {:?} at line {:?}\",
            previous_symbol.filename().unwrap(), previous_symbol.lineno().unwrap());
    "
    .parse()
    .unwrap();

    item.into_iter()
        .map(|tt| match tt {
            TokenTree::Group(ref g) if g.delimiter() == proc_macro::Delimiter::Brace => {
                prefix.extend(g.stream());

                TokenTree::Group(proc_macro::Group::new(
                    proc_macro::Delimiter::Brace,
                    prefix.clone(),
                ))
            }
            other => other,
        })
        .collect()
}