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                                                              1091x 3x     1088x 1088x   278x 259x       19x         12x       1076x                               187x 1x       186x 177x     9x 9x 9x                                     121x 1x       120x 117x       3x 3x         2x     1x          
/**
 * 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 QualifiedCName from "./QualifiedCName";
 
/**
 * 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 === "namespace" ||
        sym.kind === "class" ||
        sym.kind === "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 separator-qualified names
    if (!QualifiedCName.isQualified(typeName)) {
      return false;
    }
 
    const parts = QualifiedCName.split(typeName);
    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 separator-qualified types
    if (!QualifiedCName.isQualified(typeName)) {
      return typeName;
    }
 
    // Check if this looks like a qualified type
    const parts = QualifiedCName.split(typeName);
    if (
      parts.length > 1 &&
      CppNamespaceUtils.isCppNamespace(parts[0], symbolTable)
    ) {
      // It's a C++ namespaced type - re-qualify for C++ namespace syntax
      return parts.join("::");
    }
 
    return typeName;
  }
}
 
export default CppNamespaceUtils;