| 5663 | } |
| 5664 | |
| 5665 | static void wd_push(wd_stack_t *s, TSNode node, const char *enclosing_qn) { |
| 5666 | if (s->top >= s->cap) { |
| 5667 | int ncap = s->cap ? s->cap * 2 : 256; |
| 5668 | if (ncap > wd_stack_max()) { |
| 5669 | if (!s->warned) { |
| 5670 | char lim[24]; |
| 5671 | snprintf(lim, sizeof(lim), "%d", wd_stack_max()); |
| 5672 | cbm_log_warn("extract.walk_defs_capped", "limit", lim, "path", |
| 5673 | s->path ? s->path : ""); |
| 5674 | s->warned = true; |
| 5675 | } |
| 5676 | return; // bounded: stop growing (warned, not silent) |
| 5677 | } |
| 5678 | walk_defs_frame_t *nd = safe_realloc(s->data, (size_t)ncap * sizeof(walk_defs_frame_t)); |
| 5679 | if (!nd) { |
| 5680 | /* OOM — safe_realloc already freed the old buffer. Bail cleanly: drop |
| 5681 | * pending frames so the walk_defs loop drains and exits without a NULL |
| 5682 | * deref; extraction keeps whatever was already emitted. */ |
| 5683 | s->data = NULL; |
| 5684 | s->cap = 0; |
| 5685 | s->top = 0; |
| 5686 | return; |
| 5687 | } |
| 5688 | s->data = nd; |
| 5689 | s->cap = ncap; |
| 5690 | } |
| 5691 | s->data[s->top++] = (walk_defs_frame_t){node, enclosing_qn}; |
| 5692 | } |
| 5693 | |
| 5694 | /* Push all children of `node` in REVERSE order (so they pop in source order) |
| 5695 | * using a LINEAR traversal. Index-based ts_node_child(i) is O(i) per call in |
no test coverage detected