All files / utils/ast ChildStatementCollector.ts

100% Statements 25/25
100% Branches 18/18
100% Functions 3/3
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117                                                  5212x 5212x     5212x 151x 175x                 5212x 24x               5212x 56x               5212x 18x       5212x 41x             5212x 16x       5212x 25x     5212x                       255x 195x   60x                     41x 81x   41x 25x            
/**
 * ChildStatementCollector
 *
 * Collects child statements and blocks from control flow statements.
 * This centralizes recursion patterns to prevent missing nested statements.
 *
 * Issue #566: Extracted from CodeGenerator for improved testability.
 */
 
import * as Parser from "../../PARSE/2-Parse/grammar/CNextParser";
 
/**
 * Result of collecting child statements and blocks from a statement.
 */
interface IChildStatementResult {
  statements: Parser.StatementContext[];
  blocks: Parser.BlockContext[];
}
 
class ChildStatementCollector {
  /**
   * Collect all child statements and blocks from a control flow statement.
   * Handles if, while, for, do-while, switch, critical, and nested blocks.
   */
  static collectAll(stmt: Parser.StatementContext): IChildStatementResult {
    const statements: Parser.StatementContext[] = [];
    const blocks: Parser.BlockContext[] = [];
 
    // if statement: has statement() children (can be blocks or single statements)
    if (stmt.ifStatement()) {
      for (const childStmt of stmt.ifStatement()!.statement()) {
        ChildStatementCollector._classifyChildStatement(
          childStmt,
          statements,
          blocks,
        );
      }
    }
 
    // while statement: single statement() child
    if (stmt.whileStatement()) {
      ChildStatementCollector._classifyChildStatement(
        stmt.whileStatement()!.statement(),
        statements,
        blocks,
      );
    }
 
    // for statement: single statement() child
    if (stmt.forStatement()) {
      ChildStatementCollector._classifyChildStatement(
        stmt.forStatement()!.statement(),
        statements,
        blocks,
      );
    }
 
    // do-while statement: has block() directly
    if (stmt.doWhileStatement()) {
      blocks.push(stmt.doWhileStatement()!.block());
    }
 
    // switch statement: case blocks and optional default block
    if (stmt.switchStatement()) {
      ChildStatementCollector._collectSwitchChildren(
        stmt.switchStatement()!,
        blocks,
      );
    }
 
    // critical statement: has block() directly (ADR-050)
    if (stmt.criticalStatement()) {
      blocks.push(stmt.criticalStatement()!.block());
    }
 
    // Nested block statement
    if (stmt.block()) {
      blocks.push(stmt.block()!);
    }
 
    return { statements, blocks };
  }
 
  /**
   * Classify a child statement as block or single statement.
   * Blocks are pushed to the blocks array, statements to the statements array.
   */
  private static _classifyChildStatement(
    childStmt: Parser.StatementContext,
    statements: Parser.StatementContext[],
    blocks: Parser.BlockContext[],
  ): void {
    if (childStmt.block()) {
      blocks.push(childStmt.block()!);
    } else {
      statements.push(childStmt);
    }
  }
 
  /**
   * Collect blocks from switch statement cases and default.
   */
  private static _collectSwitchChildren(
    switchStmt: Parser.SwitchStatementContext,
    blocks: Parser.BlockContext[],
  ): void {
    for (const caseCtx of switchStmt.switchCase()) {
      blocks.push(caseCtx.block());
    }
    if (switchStmt.defaultCase()) {
      blocks.push(switchStmt.defaultCase()!.block());
    }
  }
}
 
export default ChildStatementCollector;