All files / TRANSPILE/3-Render/headers ExternalTypeHeaderBuilder.ts

100% Statements 6/6
100% Branches 2/2
100% Functions 1/1
100% Lines 6/6

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                                                                                    308x           308x 190x 111x 110x         308x          
/**
 * ExternalTypeHeaderBuilder
 * Builds mapping from external type names to their C header include directives.
 *
 * Issue #589: Extracted from Transpiler.buildExternalTypeHeaders()
 * Issue #497: Enables header generation to include original C headers instead of
 * generating conflicting forward declarations for types like anonymous struct typedefs.
 * ADR-055 Phase 7: Uses TAnySymbol instead of ISymbol.
 */
 
/**
 * What this builder needs to know about a file.
 *
 * #1511: it used to take the whole `SymbolTable` and filter symbols by kind
 * here. The kinds that form a type are a property of the symbols, so that
 * filter is now authored in `Program` and this asks for the answer — which is
 * also why the parameter is this one method rather than `IProgram`: nothing
 * here needs the rest of the artifact, and the narrow shape keeps the unit
 * tests free of a whole program.
 */
interface ITypeSource {
  typesDeclaredIn(filePath: string): ReadonlySet<string>;
}
 
/**
 * Builds mapping from external type names to their C header include directives
 */
class ExternalTypeHeaderBuilder {
  /**
   * Build a map from external type names to their C header include directives.
   *
   * This enables header generation to include the original C headers instead of
   * generating conflicting forward declarations for types like anonymous struct typedefs.
   *
   * @param headerIncludeDirectives Map from header file paths to their include directives
   * @param typeSource Answers which type names a file declares (`Program`)
   * @returns Map from type names to include directives (e.g., "MyStruct" -> '#include "mystruct.h"')
   */
  static build(
    headerIncludeDirectives: ReadonlyMap<string, string>,
    typeSource: ITypeSource,
  ): Map<string, string> {
    const typeHeaders = new Map<string, string>();
 
    // Which header wins is decided HERE, by the order of the include
    // directives -- first one wins. That ordering is an include-resolution
    // fact, not a symbol fact, which is why it stayed behind when the rest
    // moved to `Program` (#1511).
    for (const [headerPath, directive] of headerIncludeDirectives) {
      for (const typeName of typeSource.typesDeclaredIn(headerPath)) {
        if (!typeHeaders.has(typeName)) {
          typeHeaders.set(typeName, directive);
        }
      }
    }
 
    return typeHeaders;
  }
}
 
export default ExternalTypeHeaderBuilder;