All files / transpiler/logic/analysis runAnalyzers.ts

100% Statements 35/35
100% Branches 18/18
100% Functions 5/5
100% Lines 34/34

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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159                                                                                                                  1173x 1173x 10x             1173x                               151x 151x 8x     151x 151x 1x       150x 150x     1x       149x 149x 139x     149x             2x       147x 147x             1x       146x 146x 1x       145x 145x 2x       143x 143x 1x       142x 142x     1x     142x        
/**
 * Run all semantic analyzers on a parsed C-Next program
 *
 * Extracted from transpiler.ts for reuse in the unified pipeline.
 * All 8 analyzers run in sequence, each returning errors that block compilation.
 */
 
import { CommonTokenStream } from "antlr4ng";
import { ProgramContext } from "../parser/grammar/CNextParser";
import ParameterNamingAnalyzer from "./ParameterNamingAnalyzer";
import StructFieldAnalyzer from "./StructFieldAnalyzer";
import InitializationAnalyzer from "./InitializationAnalyzer";
import FunctionCallAnalyzer from "./FunctionCallAnalyzer";
import NullCheckAnalyzer from "./NullCheckAnalyzer";
import DivisionByZeroAnalyzer from "./DivisionByZeroAnalyzer";
import FloatModuloAnalyzer from "./FloatModuloAnalyzer";
import CommentExtractor from "./CommentExtractor";
import ITranspileError from "../../../lib/types/ITranspileError";
import SymbolTable from "../symbols/SymbolTable";
 
/**
 * Options for running analyzers
 */
interface IAnalyzerOptions {
  /**
   * External struct field information from C/C++ headers
   * Maps struct name -> Set of field names
   */
  externalStructFields?: Map<string, Set<string>>;
 
  /**
   * Symbol table containing external function definitions from C/C++ headers
   * Used by FunctionCallAnalyzer to recognize external functions
   */
  symbolTable?: SymbolTable;
}
 
/**
 * Generic analyzer error with common fields
 */
interface IAnalyzerError {
  line: number;
  column: number;
  message: string;
  code?: string;
  rule?: string;
}
 
/**
 * Convert analyzer errors to ITranspileError format and add to accumulator.
 * Returns true if any errors were added (for early return logic).
 */
function collectErrors(
  analyzerErrors: IAnalyzerError[],
  target: ITranspileError[],
  formatMessage?: (err: IAnalyzerError) => string,
): boolean {
  const formatter = formatMessage ?? ((e) => e.message);
  for (const err of analyzerErrors) {
    target.push({
      line: err.line,
      column: err.column,
      message: formatter(err),
      severity: "error",
    });
  }
  return analyzerErrors.length > 0;
}
 
/**
 * Run all semantic analyzers on a parsed program
 *
 * @param tree - The parsed program AST
 * @param tokenStream - Token stream for comment validation
 * @param options - Optional configuration including external struct info
 * @returns Array of errors (empty if all pass)
 */
function runAnalyzers(
  tree: ProgramContext,
  tokenStream: CommonTokenStream,
  options?: IAnalyzerOptions,
): ITranspileError[] {
  const errors: ITranspileError[] = [];
  const formatWithCode = (e: IAnalyzerError) =>
    `error[${e.code}]: ${e.message}`;
 
  // 1. Parameter naming validation (Issue #227: reserved naming patterns)
  const paramNamingAnalyzer = new ParameterNamingAnalyzer();
  if (collectErrors(paramNamingAnalyzer.analyze(tree), errors)) {
    return errors;
  }
 
  // 2. Struct field validation (reserved field names like 'length')
  const structFieldAnalyzer = new StructFieldAnalyzer();
  if (
    collectErrors(structFieldAnalyzer.analyze(tree), errors, formatWithCode)
  ) {
    return errors;
  }
 
  // 3. Initialization analysis (Rust-style use-before-init detection)
  const initAnalyzer = new InitializationAnalyzer();
  if (options?.externalStructFields) {
    initAnalyzer.registerExternalStructFields(options.externalStructFields);
  }
  // Issue #503: Pass symbol table so C++ classes with default constructors are recognized
  if (
    collectErrors(
      initAnalyzer.analyze(tree, options?.symbolTable),
      errors,
      formatWithCode,
    )
  ) {
    return errors;
  }
 
  // 4. Call analysis (ADR-030: define-before-use)
  const funcAnalyzer = new FunctionCallAnalyzer();
  if (
    collectErrors(
      funcAnalyzer.analyze(tree, options?.symbolTable),
      errors,
      formatWithCode,
    )
  ) {
    return errors;
  }
 
  // 5. NULL check analysis (ADR-047: C library interop)
  const nullAnalyzer = new NullCheckAnalyzer();
  if (collectErrors(nullAnalyzer.analyze(tree), errors, formatWithCode)) {
    return errors;
  }
 
  // 6. Division by zero analysis (ADR-051: compile-time detection)
  const divZeroAnalyzer = new DivisionByZeroAnalyzer();
  if (collectErrors(divZeroAnalyzer.analyze(tree), errors, formatWithCode)) {
    return errors;
  }
 
  // 7. Float modulo analysis (catch % with f32/f64 early)
  const floatModAnalyzer = new FloatModuloAnalyzer();
  if (collectErrors(floatModAnalyzer.analyze(tree), errors, formatWithCode)) {
    return errors;
  }
 
  // 8. Comment validation (MISRA C:2012 Rules 3.1, 3.2) - ADR-043
  const commentExtractor = new CommentExtractor(tokenStream);
  collectErrors(
    commentExtractor.validate(),
    errors,
    (e) => `error[MISRA-${e.rule}]: ${e.message}`,
  );
 
  return errors;
}
 
export default runAnalyzers;