如何用syn遍历Rust文件中所有嵌套宏调用?
Traverse Nested Macro Calls in Rust Using Syn
The core issue with your current implementation is that syn::visit::visit_macro doesn’t traverse the token stream inside a macro call—you need to explicitly parse those tokens into an AST and visit that structure to uncover nested macros.
Step 1: Modify the Visitor to Parse Macro Tokens
Extend your custom Visitor to parse the token stream of each macro call and recursively visit the resulting AST. This will catch any nested macro calls within the arguments.
use syn::{visit::Visit, Macro, File, parse2}; use std::error::Error; struct MacroCallVisitor; impl Visit for MacroCallVisitor { fn visit_macro(&mut self, node: &Macro) { // Print the name of the current macro call let macro_name = node.path.segments.last().unwrap().ident.to_string(); println!("Macro call: {}", macro_name); // Parse the macro's token stream into a File (handles statements/expressions) match parse2::<File>(node.tokens.clone()) { Ok(file) => self.visit_file(&file), Err(e) => eprintln!("Warning: Could not parse tokens for macro '{}': {}", macro_name, e), } } }
Step 2: Run the Visitor on Your Rust File
Parse your target Rust file into a syn::File and execute the visitor to traverse all macro calls (including nested ones):
fn main() -> Result<(), Box<dyn Error>> { // Replace with your file content or read from disk let source_code = r#" fn main() { println!("Count: {}", format!("{}", add_one!(5))); let values = vec![1, mul_two!(2), 3]; outer_macro!(inner_macro!(nested_macro!())); } // Macro definitions (not calls, so they won't be printed) macro_rules! add_one { ($x:expr) => { $x + 1 } } macro_rules! mul_two { ($x:expr) => { $x * 2 } } macro_rules! inner_macro { ($x:expr) => { $x } } macro_rules! nested_macro { () => { 42 } } "#; let ast = syn::parse_file(source_code)?; let mut visitor = MacroCallVisitor; visitor.visit_file(&ast); Ok(()) }
Key Details
- Parsing Flexibility: Using
syn::Fileto parse macro tokens works for most cases because it handles both standalone expressions and sequences of statements, covering common macro argument patterns. - Error Handling: If a macro’s tokens can’t be parsed as valid Rust (common for macros with non-standard syntax), the code logs a warning but continues processing other macros.
- Definitions vs Calls: This implementation only prints macro calls (e.g.,
add_one!(5)), not macro definitions (e.g.,macro_rules! add_one { ... }), which aligns with your requirement to output macro calls.
Dependencies
Add syn with the full feature to your Cargo.toml to enable full syntax parsing:
[dependencies] syn = { version = "2.0", features = ["full"] }
内容的提问来源于stack exchange,提问作者Steve Lau
相关产品推荐
相关产品推荐

