All files / transpiler/logic/symbols/c/collectors FunctionCollector.ts

89.47% Statements 17/19
78.57% Branches 11/14
100% Functions 5/5
100% Lines 16/16

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                                          34x                                 34x 34x                         10x 10x   10x 10x   10x     10x 10x       10x         10x       10x                                                             24x       24x         24x                              
/**
 * FunctionCollector - Collects function symbols from C parse trees.
 */
 
import type {
  DeclaratorContext,
  FunctionDefinitionContext,
} from "../../../parser/c/grammar/CParser";
import type ICFunctionSymbol from "../../../../types/symbols/c/ICFunctionSymbol";
import type ICParameterInfo from "../../../../types/symbols/c/ICParameterInfo";
import ESourceLanguage from "../../../../../utils/types/ESourceLanguage";
import DeclaratorUtils from "../utils/DeclaratorUtils";
import type IExtractedParameter from "../../shared/IExtractedParameter";
 
class FunctionCollector {
  /**
   * Map extracted parameters to ICParameterInfo array.
   */
  private static _mapParameters(
    extracted: IExtractedParameter[],
  ): ICParameterInfo[] {
    return extracted.map((p) => ({
      name: p.name,
      type: p.type,
      isConst: p.isConst,
      isArray: p.isArray,
    }));
  }
 
  /**
   * Resolve return type, appending '*' if declarator has a pointer.
   * Issue #895 Bug B / Issue #945: C grammar puts pointer before directDeclarator
   * (e.g., `widget_t *func()` has declarator.pointer() !== null)
   */
  private static _resolveReturnType(
    baseType: string,
    declarator: DeclaratorContext,
  ): string {
    const hasPointer = declarator.pointer() !== null;
    return hasPointer ? `${baseType}*` : baseType;
  }
 
  /**
   * Collect a function symbol from a function definition.
   *
   * @param funcDef The function definition context
   * @param sourceFile Source file path
   */
  static collectFromDefinition(
    funcDef: FunctionDefinitionContext,
    sourceFile: string,
  ): ICFunctionSymbol | null {
    const declarator = funcDef.declarator();
    Iif (!declarator) return null;
 
    const name = DeclaratorUtils.extractDeclaratorName(declarator);
    Iif (!name) return null;
 
    const line = funcDef.start?.line ?? 0;
 
    // Get return type from declaration specifiers
    const declSpecs = funcDef.declarationSpecifiers();
    const baseType = declSpecs
      ? DeclaratorUtils.extractTypeFromDeclSpecs(declSpecs)
      : "int";
 
    const returnType = FunctionCollector._resolveReturnType(
      baseType,
      declarator,
    );
 
    const parameters = FunctionCollector._mapParameters(
      DeclaratorUtils.extractFunctionParameters(declarator),
    );
 
    return {
      kind: "function",
      name,
      sourceFile,
      sourceLine: line,
      sourceLanguage: ESourceLanguage.C,
      isExported: true,
      type: returnType,
      parameters: parameters.length > 0 ? parameters : undefined,
      isDeclaration: false,
    };
  }
 
  /**
   * Collect a function symbol from a declaration (prototype).
   *
   * @param name Function name
   * @param baseType Return type
   * @param declarator The declarator context
   * @param sourceFile Source file path
   * @param line Source line number
   * @param isExtern Whether the function is extern
   */
  static collectFromDeclaration(
    name: string,
    baseType: string,
    declarator: DeclaratorContext,
    sourceFile: string,
    line: number,
    isExtern: boolean,
  ): ICFunctionSymbol {
    const parameters = FunctionCollector._mapParameters(
      DeclaratorUtils.extractFunctionParameters(declarator),
    );
 
    const returnType = FunctionCollector._resolveReturnType(
      baseType,
      declarator,
    );
 
    return {
      kind: "function",
      name,
      sourceFile,
      sourceLine: line,
      sourceLanguage: ESourceLanguage.C,
      isExported: !isExtern,
      type: returnType,
      parameters: parameters.length > 0 ? parameters : undefined,
      isDeclaration: true,
    };
  }
}
 
export default FunctionCollector;