Macro with Syn can't detect macro with full module tree path!

Hello,
it's just me and my annoying experiments with Macros :laughing:

I noticed something, when I use a macro with its full path, syn can't detect it.

here's a concrete example :

Macros code : ( in lib "ex: crateMyMacros")


// this is a dummy macro
#[proc_macro_attribute]
pub fn dummy_macro(
    _attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let input = parse_macro_input!(item as syn::Item);
    println!("Hello :D");
    let code = quote!(
          #input
    );

    TokenStream::from(code)
}

// this macro list all function attributes
#[proc_macro_attribute]
pub fn scan(
    _attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    println!("scan started !");
    let input = parse_macro_input!(item as syn::ItemFn);

    input.attrs.iter().for_each(|attr| {
        if let Some(ident) = attr.path().get_ident() {
            println!("ident = {}", ident);
        }
    });

    let code = quote!(
          #input
    );

    TokenStream::from(code)
}



Bin code (crateApp) :

    #[scan]
    #[dummy_macro]
    fn test() {
        println!("TEST");
    }

result :

scan started !
ident = dummy_macro
Hello :D

    #[scan]
    #[crateMyMacros::dummy_macro]
    fn test_with_strange_behavior() {
        println!("TEST");
    }

result :

scan started !
Hello :D

as you can see, when the macro name contains the full path #[crateMyMacros::dummy_macro], it is not detected !!

is this a syn bug? or is it one of the limitations of the Rust language ?

Thanks in advance for your feedback.

attr.path().get_ident() only parses single ident, so it's not suitable for the second case.

3 Likes

@vague thank you for your answer, I've noticed that many macros only use get_ident() to detect another macro,

so we can end up with cases where bugs occur due to confusion like this:
if dummy_macro comes from crate XXX or YYY, it will not be differentiated, even though the two are totally different.

I've analyzed a few crates, and they don't use any mechanism to check which crate the macro comes from!

for the case I've given, is there a way to get the full identifier? without going through to_token_stream() ?!

Exactly. AFAIK there is no way to distinguish them, since macros are only aware of tokens fed to them. If the absolute path is not written out, we don't know where the path comes from. But normally we assume the path is legitimate and secure.

2 Likes

The easiest way is to use parse_quote! to get a syn::Path and then just use == to compare the attribute path to your test path. Otherwise, Path.segments is an iterator of the PathSegments if you need more control.

1 Like

thank you all for your answers (@vague , @CAD97 ) :pray:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.