Main entry point for AST scanning
(ast: &AstNode, file_path: &str, content: &str, ruleset: &RuleSet)
| 4 | |
| 5 | // Main entry point for AST scanning |
| 6 | pub fn scan_ast(ast: &AstNode, file_path: &str, content: &str, ruleset: &RuleSet) -> Vec<Issue> { |
| 7 | // Pre-filter applicable rules ONCE per file — not per AST node. |
| 8 | // This is critical for performance: file_content_exclude runs a regex against |
| 9 | // the full file content. Calling it inside walk_ast meant it ran O(nodes × rules) |
| 10 | // times — 5M+ times for large files. Pre-filtering reduces this to O(rules) = ~100. |
| 11 | let ast_rules: Vec<&Rule> = ruleset.rules.iter() |
| 12 | .filter(|r| r.ast_match.is_some()) |
| 13 | .filter(|r| !r.is_excluded(file_path, content, &ruleset.defaults)) |
| 14 | .collect(); |
| 15 | |
| 16 | if ast_rules.is_empty() { return Vec::new(); } |
| 17 | |
| 18 | let mut issues = Vec::new(); |
| 19 | walk_ast(ast, file_path, content, &ast_rules, &mut issues); |
| 20 | issues |
| 21 | } |
| 22 | |
| 23 | // Recursively walks the AST, checking each node against pre-filtered rules. |
| 24 | // Rules are already filtered for this file — no exclusion checks needed here. |
no test coverage detected