All files / transpiler/logic/analysis ModificationAnalyzer.ts

100% Statements 18/18
100% Branches 4/4
100% Functions 7/7
100% Lines 18/18

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                                                                    190x             190x                     64x 66x 66x   25x 2x       41x                             60x 61x   36x                       29x 29x                 174x                 171x                   3x               145x 145x          
/**
 * Modification Analyzer
 * Issue #593: Dedicated analyzer for C++ mode parameter modification tracking
 *
 * Accumulates function parameter modifications across multiple files for
 * cross-file const inference in C++ mode. This centralizes the accumulation
 * logic that was previously duplicated in Transpiler.
 *
 * Usage:
 * - Call accumulateResults() after analyzing each file
 * - Call getModifications()/getParamLists() to get accumulated state
 * - Call clear() between transpilation runs
 */
 
/**
 * Result type from CodeGenerator.analyzeModificationsOnly()
 */
interface IAnalysisResult {
  modifications: Map<string, Set<string>>;
  paramLists: Map<string, string[]>;
}
 
/**
 * Analyzer that tracks parameter modifications across files for C++ const inference.
 *
 * In C++ mode, we need to know which function parameters are modified so we can
 * generate correct const qualifiers. This analyzer accumulates that information
 * as files are processed, enabling cross-file transitive propagation.
 */
class ModificationAnalyzer {
  /**
   * Accumulated parameter modifications across all processed files.
   * Maps function name -> set of modified parameter names.
   */
  private readonly modifications: Map<string, Set<string>> = new Map();
 
  /**
   * Accumulated function parameter lists across all processed files.
   * Maps function name -> ordered list of parameter names.
   * Used for transitive propagation (mapping call argument indices to param names).
   */
  private readonly paramLists: Map<string, string[]> = new Map();
 
  /**
   * Accumulate modifications from analysis results.
   * Merges new modifications with existing ones (union of param sets).
   *
   * @param newModifications - Map of function name to modified param names
   */
  accumulateModifications(
    newModifications: ReadonlyMap<string, ReadonlySet<string>>,
  ): void {
    for (const [funcName, params] of newModifications) {
      const existing = this.modifications.get(funcName);
      if (existing) {
        // Merge: add all new params to existing set
        for (const param of params) {
          existing.add(param);
        }
      } else {
        // New function: create new set with copy of params
        this.modifications.set(funcName, new Set(params));
      }
    }
  }
 
  /**
   * Accumulate param lists from analysis results.
   * Uses first-wins semantics: once a function's param list is recorded,
   * subsequent attempts to set it are ignored.
   *
   * @param newParamLists - Map of function name to parameter name array
   */
  accumulateParamLists(
    newParamLists: ReadonlyMap<string, readonly string[]>,
  ): void {
    for (const [funcName, params] of newParamLists) {
      if (!this.paramLists.has(funcName)) {
        // Only set if not already present (first wins)
        this.paramLists.set(funcName, [...params]);
      }
    }
  }
 
  /**
   * Convenience method to accumulate both modifications and param lists.
   * This is the typical pattern when processing analysis results.
   *
   * @param results - Analysis results containing both modifications and param lists
   */
  accumulateResults(results: IAnalysisResult): void {
    this.accumulateModifications(results.modifications);
    this.accumulateParamLists(results.paramLists);
  }
 
  /**
   * Get readonly view of accumulated modifications.
   *
   * @returns Readonly map of function name to readonly set of modified params
   */
  getModifications(): ReadonlyMap<string, ReadonlySet<string>> {
    return this.modifications;
  }
 
  /**
   * Get readonly view of accumulated param lists.
   *
   * @returns Readonly map of function name to readonly param name array
   */
  getParamLists(): ReadonlyMap<string, readonly string[]> {
    return this.paramLists;
  }
 
  /**
   * Check if any modifications have been accumulated.
   * Useful for conditional logic in code generation.
   *
   * @returns true if there are any accumulated modifications
   */
  hasModifications(): boolean {
    return this.modifications.size > 0;
  }
 
  /**
   * Clear all accumulated state.
   * Call this between transpilation runs to reset the analyzer.
   */
  clear(): void {
    this.modifications.clear();
    this.paramLists.clear();
  }
}
 
export default ModificationAnalyzer;