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                                                              1351x 3x     1348x 1348x   441x 412x       29x         14x       1334x                               224x 1x       223x 214x     9x 9x 9x                                     4525x 3x       4522x 4432x       90x 90x         4x     86x          
/**
 * 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 "../PARSE/3-Declare/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;