mirror of
https://github.com/github/codeql.git
synced 2026-05-14 11:19:27 +02:00
Yeast: Fix three issues from second review round
1. Depth guard now only counts rule rewrites, not tree traversal. Deep ASTs (>100 levels) no longer trigger false "non-terminating cycle" errors. Only actual rule-rewrite chains are depth-limited. 2. Repeated matcher detects zero-width matches and breaks the loop. Patterns like ((_)?)* no longer infinite-loop — if the iterator does not advance after a successful match, the repetition stops. 3. Shorthand rule! syntax now propagates source_range to synthetic nodes via create_node_with_range, matching the full template path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -630,11 +630,12 @@ pub fn parse_rule_top(input: TokenStream) -> Result<TokenStream> {
|
||||
.unwrap_or_else(|| panic!("node kind '{}' not found", #output_kind_str));
|
||||
let mut __fields = std::collections::BTreeMap::new();
|
||||
#(#field_stmts)*
|
||||
let __id = #ctx_ident.ast.create_node(
|
||||
let __id = #ctx_ident.ast.create_node_with_range(
|
||||
__kind,
|
||||
yeast::NodeContent::DynamicString(String::new()),
|
||||
__fields,
|
||||
true,
|
||||
__source_range,
|
||||
);
|
||||
vec![__id]
|
||||
}
|
||||
|
||||
@@ -556,16 +556,16 @@ impl Rule {
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_RULE_DEPTH: usize = 100;
|
||||
const MAX_REWRITE_DEPTH: usize = 100;
|
||||
|
||||
fn apply_rules(rules: &Vec<Rule>, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope) -> Result<Vec<Id>, String> {
|
||||
apply_rules_inner(rules, ast, id, fresh, 0)
|
||||
}
|
||||
|
||||
fn apply_rules_inner(rules: &Vec<Rule>, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope, depth: usize) -> Result<Vec<Id>, String> {
|
||||
if depth > MAX_RULE_DEPTH {
|
||||
fn apply_rules_inner(rules: &Vec<Rule>, ast: &mut Ast, id: Id, fresh: &tree_builder::FreshScope, rewrite_depth: usize) -> Result<Vec<Id>, String> {
|
||||
if rewrite_depth > MAX_REWRITE_DEPTH {
|
||||
return Err(format!(
|
||||
"Desugaring exceeded maximum depth ({MAX_RULE_DEPTH}). \
|
||||
"Desugaring exceeded maximum rewrite depth ({MAX_REWRITE_DEPTH}). \
|
||||
This likely indicates a non-terminating rule cycle."
|
||||
));
|
||||
}
|
||||
@@ -574,7 +574,8 @@ fn apply_rules_inner(rules: &Vec<Rule>, ast: &mut Ast, id: Id, fresh: &tree_buil
|
||||
if let Some(result_node) = rule.try_rule(ast, id, fresh)? {
|
||||
let mut results = Vec::new();
|
||||
for node in result_node {
|
||||
results.extend(apply_rules_inner(rules, ast, node, fresh, depth + 1)?);
|
||||
// Increment depth only when re-processing rule output
|
||||
results.extend(apply_rules_inner(rules, ast, node, fresh, rewrite_depth + 1)?);
|
||||
}
|
||||
return Ok(results);
|
||||
}
|
||||
@@ -583,6 +584,7 @@ fn apply_rules_inner(rules: &Vec<Rule>, ast: &mut Ast, id: Id, fresh: &tree_buil
|
||||
let mut node = ast.nodes[id].clone();
|
||||
|
||||
// recursively descend into all the fields
|
||||
// Child traversal does not increment rewrite depth
|
||||
for vec in node.fields.values_mut() {
|
||||
let old = std::mem::take(vec);
|
||||
let mut new = Vec::new();
|
||||
|
||||
@@ -125,11 +125,18 @@ impl QueryListElem {
|
||||
loop {
|
||||
let matches_initial = matches.clone();
|
||||
let start = remaining_children.clone();
|
||||
let start_next = start.clone().next();
|
||||
if !match_children(children.iter(), ast, remaining_children, matches)? {
|
||||
*remaining_children = start;
|
||||
*matches = matches_initial;
|
||||
break;
|
||||
}
|
||||
// Guard against zero-width matches: if the iterator
|
||||
// didn't advance, break to avoid infinite looping.
|
||||
let current_next = remaining_children.clone().next();
|
||||
if start_next == current_next {
|
||||
break;
|
||||
}
|
||||
iters += 1;
|
||||
if *rep == Rep::ZeroOrOne {
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user