easy_macros_all_syntax_cases/
lib.rs

1use proc_macro::TokenStream;
2
3mod all_syntax_cases;
4mod helpers;
5
6#[proc_macro]
7/// Generates exhaustive handler functions for traversing syn AST syntax trees.
8///
9/// This macro creates a complete set of recursive handler functions that traverse through
10/// all variants of syn's AST types (Item, Expr, Stmt, Pat, Type, etc.). It generates match
11/// arms for every syn type variant and automatically routes to user-defined handlers.
12///
13/// # Syntax
14///
15/// ```rust,ignore
16/// all_syntax_cases! {
17///     setup => {
18///         generated_fn_prefix: "prefix",
19///         additional_input_type: YourType,
20///         system_functions_test: false,  // Optional: default false
21///     }
22///     default_cases => {
23///         // Functions called for all matching types
24///         fn handler_name(param: &mut SynType, additional: AdditionalType);
25///         
26///         #[after_system]  // Optional: run after system traversal
27///         fn late_handler(param: &mut SynType, additional: AdditionalType);
28///     }
29///     special_cases => {
30///         // Functions called for specific syn variants
31///         fn special_handler(variant: &mut syn::ExprTry, additional: AdditionalType);
32///     }
33/// }
34/// ```
35///
36/// # Parameters
37///
38/// ## setup
39///
40/// - `generated_fn_prefix` - String prefix for all generated function names (e.g., `"handle"`
41///   generates `handle_item`, `handle_expr`, etc.)
42/// - `additional_input_type` - Type of additional context passed to all handlers. Can be any type
43///   (reference, value, mutable reference). This type is passed through the entire traversal.
44/// - `system_functions_test` - Optional boolean (default: `false`). When `true`, enables validation
45///   that all system-generated functions are actually invoked during macro expansion. This helps detect
46///   coverage gaps in the macro's traversal logic. Use this when developing or debugging the macro itself,
47///   not in production code.
48///
49/// ## default_cases
50///
51/// Functions that handle any type matching their parameter signature. Handlers are automatically called
52/// for matching fields, with smart unwrapping of `Box<T>`, `Vec<T>`, and `Punctuated<T, _>`. Note: `Option<T>`
53/// fields are traversed via system-generated functions rather than direct smart unwrapping.
54///
55/// **Collection handling**:
56/// - **2 parameters** (param + context): Iterates collections, calling handler per element
57/// - **3+ parameters**: Passes entire collections, enabling multi-field correlation from same node
58///
59/// Mark with `#[after_system]` to run after traversing child nodes (for post-processing).
60///
61/// ## special_cases
62///
63/// Functions that handle specific syn type variants (like `syn::ExprTry`, `syn::ItemMod`). These
64/// **completely override** default handlers for their variant—defaults won't run, and traversal stops
65/// unless you explicitly call system handlers (e.g., `{prefix}_expr_handle(&mut expr, context)`).
66///
67/// Like `default_cases`, special case handlers also benefit from smart unwrapping of `Box<T>`,
68/// `Vec<T>`, and `Punctuated<T, _>` when matching function parameters to struct fields.
69///
70/// # Generated Functions
71///
72/// The macro generates handler functions for all major syn types:
73/// - `{prefix}_item_handle` - Handles `syn::Item` variants
74/// - `{prefix}_expr_handle` - Handles `syn::Expr` variants
75/// - `{prefix}_stmt_handle` - Handles `syn::Stmt` variants
76/// - `{prefix}_pat_handle` - Handles `syn::Pat` variants
77/// - `{prefix}_type_handle` - Handles `syn::Type` variants
78/// - And many more for generics, blocks, signatures, fields, etc.
79///
80/// Each generated function contains exhaustive match arms for all variants of its type.
81///
82/// # Type Matching
83///
84/// The macro intelligently matches function parameters to struct fields:
85///
86/// - **Direct types**: `&mut syn::Expr` matches `expr: Expr`, `Box<Expr>`, `Option<Expr>`
87/// - **Collections** (2-param handlers): `&mut syn::Expr` matches `Vec<Expr>` or `Punctuated<Expr, T>` (iterates per element)
88/// - **Collections** (3+ param handlers): `&mut Vec<syn::Attribute>` matches as whole value (no iteration)
89///
90/// # Examples
91///
92/// ## Finding Function Calls (Special Cases)
93///
94/// ```rust,ignore
95/// use all_syntax_cases::all_syntax_cases;
96///
97/// #[derive(Default)]
98/// struct CallFinder { calls: Vec<String> }
99///
100/// all_syntax_cases! {
101///     setup => {
102///         generated_fn_prefix: "find",
103///         additional_input_type: &mut CallFinder,
104///     }
105///     default_cases => {}
106///     special_cases => {
107///         fn handle_call(call: &mut syn::ExprCall, finder: &mut CallFinder);
108///     }
109/// }
110///
111/// fn handle_call(call: &mut syn::ExprCall, finder: &mut CallFinder) {
112///     finder.calls.push(call.func.to_token_stream().to_string());
113///     // Note: Traversal stops here unless we call find_expr_handle manually
114/// }
115/// ```
116///
117/// ## Multi-Field Correlation (3+ Parameters)
118///
119/// ```rust,ignore
120/// all_syntax_cases! {
121///     setup => {
122///         generated_fn_prefix: "analyze",
123///         additional_input_type: &mut Analysis,
124///     }
125///     default_cases => {
126///         // Receives BOTH fields together from each node (called once per struct/enum)
127///         fn analyze_attrs_and_generics(
128///             attrs: &mut Vec<syn::Attribute>,  // Entire vector
129///             generics: &mut syn::Generics,
130///             analysis: &mut Analysis
131///         );
132///         
133///         // 2 params: iterates and calls once per attribute across all nodes
134///         fn analyze_attr(attr: &mut syn::Attribute, analysis: &mut Analysis);
135///     }
136///     special_cases => {}
137/// }
138/// ```
139///
140/// ## Post-Processing with `#[after_system]`
141///
142/// ```rust,ignore
143/// all_syntax_cases! {
144///     setup => {
145///         generated_fn_prefix: "transform",
146///         additional_input_type: &mut Context,
147///     }
148///     default_cases => {
149///         fn pre_process(expr: &mut syn::Expr, ctx: &mut Context);
150///         
151///         #[after_system]  // Runs after children of Expr processed
152///         fn post_process(expr: &mut syn::Expr, ctx: &mut Context);
153///     }
154///     special_cases => {}
155/// }
156/// ```
157///
158/// # Errors and Panics
159///
160/// Compile-time panics occur when:
161/// - Required `setup` parameters (`generated_fn_prefix`, `additional_input_type`) are missing
162/// - Handler functions never match any syntax node (signature doesn't match any fields)
163/// - `additional_input_type` appears multiple times in a signature (must be distinct from syn types)
164/// - `system_functions_test: true` enabled and internal functions not invoked (for macro debugging)
165///
166/// # Limitations
167///
168/// - **Incomplete coverage**: `TokenStream` fields (e.g., `syn::Macro::tokens`) are not traversed
169/// - **Maintenance lag**: Manual updates needed when syn adds new syntax (use `system_functions_test` to detect gaps)
170///
171/// See comparison with `syn::visit_mut` below for complete coverage alternative.
172///
173/// # How It Works
174///
175/// 1. Generates handler functions for all syn types with exhaustive match arms
176/// 2. For each variant: checks special cases first → if matched, calls only that handler and stops traversal
177/// 3. If no special case: calls all matching default handlers → recursively traverses nested nodes
178/// 4. Threads `additional_input` through all calls
179///
180/// # Use Cases
181///
182/// Syntax tree traversal • Code transformation • Pattern detection • Static analysis • Custom linting • Complex procedural macros
183///
184/// # Comparison with `syn::visit_mut`
185///
186/// Both traverse and mutate syn ASTs, but with different tradeoffs:
187///
188/// ## Advantages of `all_syntax_cases!`
189///
190/// - **Multi-field correlation**: Access multiple fields from same node in one handler (e.g., `attrs` + `generics` together)
191/// - **Default vs. special cases**: Default handlers run for all types; special cases override and stop traversal
192/// - **Automatic type matching**: Smart unwrapping of `Box<T>`, `Option<T>`, `Vec<T>`, `Punctuated<T, _>`
193/// - **Pre/post-processing**: Use `#[after_system]` to run handlers after child traversal
194///
195/// ## Advantages of `syn::visit_mut`
196///
197/// - **Always current**: Auto-updates with syn releases; no manual maintenance
198/// - **Established**: Well-documented, widely used, thoroughly tested
199/// - **Simpler for single fields**: Straightforward trait-based approach
200///
201/// ## When to Use Which
202///
203/// **Use `all_syntax_cases!`** for multi-field correlation, default/special case separation, or pre/post-processing.
204///
205/// **Use `syn::visit_mut`** for stability, deep nesting, or single-field-at-a-time patterns.
206///
207/// # See Also
208///
209/// - [`syn::visit_mut`](https://docs.rs/syn/latest/syn/visit_mut/index.html) - Alternative visitor pattern in syn
210/// - [`syn::fold`](https://docs.rs/syn/latest/syn/fold/index.html) - Transforming visitor pattern
211pub fn all_syntax_cases(item: TokenStream) -> TokenStream {
212    all_syntax_cases::all_syntax_cases(item)
213}
214#[proc_macro]
215#[doc(hidden)]
216pub fn all_syntax_cases_debug(item: TokenStream) -> TokenStream {
217    let result = all_syntax_cases::all_syntax_cases(item);
218    panic!("{}", result);
219}