All files / utils OpaqueTypeResolution.ts

100% Statements 11/11
100% Branches 8/8
100% Functions 2/2
100% Lines 11/11

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                                                          4323x 4229x   94x 94x 11x   83x                 3228x 3228x 16x               11x     3228x          
/**
 * Is a typedef truly opaque?
 *
 * A header may forward-declare `struct _widget_t`, typedef it, and only later
 * define the struct — in that header or in another one the program includes. So
 * "declared against a forward declaration" is not the answer; the answer is
 * whether a body ever arrived for the tag (#948, #958).
 *
 * The rule lives here because two callers need it and they cannot import each
 * other: `SymbolTable` answers it for a throwaway table during #985 phantom-body
 * recovery, and 1.4 Resolve authors it as a fact of the program. Sharing the
 * DECISION rather than the data is the point — two copies agreeing today would
 * be a latent divergence, and this one already had one: the guard below is
 * truthy, so an empty tag means "no tag", where a `!== undefined` spelling would
 * have treated it as a real one (#1511).
 */
class OpaqueTypeResolution {
  /**
   * @param typeName The typedef being asked about
   * @param opaqueTypedefs Typedefs declared against a forward-declared struct
   * @param typedefToTag Typedef name to the struct tag it aliases
   * @param structTagsWithBodies Tags that received a full definition
   */
  static isOpaque(
    typeName: string,
    opaqueTypedefs: ReadonlySet<string>,
    typedefToTag: ReadonlyMap<string, string>,
    structTagsWithBodies: ReadonlySet<string>,
  ): boolean {
    if (!opaqueTypedefs.has(typeName)) {
      return false;
    }
    const tag = typedefToTag.get(typeName);
    if (tag && structTagsWithBodies.has(tag)) {
      return false;
    }
    return true;
  }
 
  /** Every truly opaque typedef among those declared. */
  static resolveAll(
    opaqueTypedefs: ReadonlySet<string>,
    typedefToTag: ReadonlyMap<string, string>,
    structTagsWithBodies: ReadonlySet<string>,
  ): Set<string> {
    const opaque = new Set<string>();
    for (const typeName of opaqueTypedefs) {
      if (
        OpaqueTypeResolution.isOpaque(
          typeName,
          opaqueTypedefs,
          typedefToTag,
          structTagsWithBodies,
        )
      ) {
        opaque.add(typeName);
      }
    }
    return opaque;
  }
}
 
export default OpaqueTypeResolution;