All files / utils CppNamespaceUtils.ts

96% Statements 24/25
95.65% Branches 22/23
100% Functions 3/3
96% Lines 24/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 118 119 120 121 122 123                                                              671x 3x     668x 668x   109x 96x       13x         12x       656x                               132x 1x       131x 118x     13x 13x 13x                                     67x 1x       66x 61x       5x 5x         2x     3x          
/**
 * C++ Namespace Detection Utilities
 *
 * Provides shared logic for detecting C++ namespaced types and converting
 * between underscore format (used in C headers) and :: format (used in C++).
 *
 * Issue #522: Consolidated from duplicate implementations in:
 * - CodeGenerator.ts (isCppScopeSymbol)
 * - generateStructHeader.ts (isCppNamespace, convertToCppNamespaceIfNeeded)
 */
 
import SymbolTable from "../transpiler/logic/symbols/SymbolTable";
import ESourceLanguage from "./types/ESourceLanguage";
import ESymbolKind from "./types/ESymbolKind";
 
/**
 * Static utility methods for C++ namespace operations
 */
class CppNamespaceUtils {
  /**
   * Check if a symbol name refers to a C++ scope-like symbol that requires :: syntax.
   * This includes C++ namespaces, classes, and enum classes (scoped enums).
   *
   * @param name - The symbol name to check (e.g., "SeaDash" or "Lib")
   * @param symbolTable - Optional symbol table for lookups
   * @returns true if the symbol is a C++ namespace, class, or enum
   */
  static isCppNamespace(
    name: string,
    symbolTable: SymbolTable | undefined,
  ): boolean {
    if (!symbolTable) {
      return false;
    }
 
    const symbols = symbolTable.getOverloads(name);
    for (const sym of symbols) {
      // Only consider C++ symbols
      if (sym.sourceLanguage !== ESourceLanguage.Cpp) {
        continue;
      }
 
      // C++ namespaces, classes, and enums (enum class) need :: syntax
      if (
        sym.kind === ESymbolKind.Namespace ||
        sym.kind === ESymbolKind.Class ||
        sym.kind === ESymbolKind.Enum
      ) {
        return true;
      }
    }
 
    return false;
  }
 
  /**
   * Check if a type name (potentially with underscores) is a C++ namespaced type.
   * This checks if the first part of an underscore-separated name is a C++ namespace.
   *
   * @param typeName - The type name to check (e.g., "SeaDash_Parse_ParseResult")
   * @param symbolTable - Optional symbol table for lookups
   * @returns true if this is a C++ namespaced type in underscore format
   */
  static isCppNamespaceType(
    typeName: string,
    symbolTable: SymbolTable | undefined,
  ): boolean {
    // Types already in :: format are clearly C++ namespaced
    if (typeName.includes("::")) {
      return true;
    }
 
    // Check underscore-separated names
    if (!typeName.includes("_")) {
      return false;
    }
 
    const parts = typeName.split("_");
    Eif (parts.length > 1) {
      return CppNamespaceUtils.isCppNamespace(parts[0], symbolTable);
    }
 
    return false;
  }
 
  /**
   * Convert underscore-separated type names to C++ namespace syntax
   * if the first part is a known C++ namespace.
   *
   * @param typeName - The type name to convert (e.g., "SeaDash_Parse_ParseResult")
   * @param symbolTable - Optional symbol table for lookups
   * @returns The converted type name (e.g., "SeaDash::Parse::ParseResult") or original if not C++ namespaced
   */
  static convertToCppNamespace(
    typeName: string,
    symbolTable: SymbolTable | undefined,
  ): string {
    // Already in :: format
    if (typeName.includes("::")) {
      return typeName;
    }
 
    // Only process types that contain underscores
    if (!typeName.includes("_")) {
      return typeName;
    }
 
    // Check if this looks like a qualified type
    const parts = typeName.split("_");
    if (
      parts.length > 1 &&
      CppNamespaceUtils.isCppNamespace(parts[0], symbolTable)
    ) {
      // It's a C++ namespaced type - convert _ to ::
      return parts.join("::");
    }
 
    return typeName;
  }
}
 
export default CppNamespaceUtils;