Reputation: 105
So I have defined the following procedural macro:
#[proc_macro_attribute]
pub fn hello(attr: TokenStream, item: TokenStream) -> TokenStream {
println!("attr: {}", attr);
println!("item: {}", item);
item
}
then I apply this proc macro to a non-inline module:
// In file some_mod.rs
#![hello]
fn foo() {}
fn bar() {}
The output of the compiler indicates that the item passed to the proc macro hello
is mod some_mod;
, without any items in the module. however I want to do some modifications to the content of the module some_mod
.
I have figured out that inline module works:
mod some_mod {
#![hello]
fn foo() { }
fo bar() { }
}
The item passed to my proc macro is mod some_mod { fn foo() { } fn bar() { } }
.
But I will use my proc macro in a complex module hierarchy, I don't want to put all those modules in a single file.
Is there any way to make my proc macro get the content of the non-inline module?
Upvotes: 4
Views: 1726
Reputation: 108
The problem you are describing is due to the fact that using procedural macros in position of inner attributes is currently unstable. There has been a tracking issue for this problem for about 1.5 years now and this comment explicitly mentions the problem you are currently facing where applying the macro to an inline module yields different results than applying it to a file-module.
To the best of my knowledge, there is currently no out-of-the-box solution for this issue.
Alternatively, since you are essentially only modifying the token stream of the file, you could try to hook your program via build.rs
into the compilation process (you can load any libraries you want for the build process) but this would involve manually sifting through all files and having to generate new files from the input token streams on the fly. Unfortunately, I can - currently - not think of any better option as long as you really need the macro to take the whole module as input.
Upvotes: 2