public override propertyAccessExpression()

in src/languages/go.ts [471:542]


  public override propertyAccessExpression(
    node: ts.PropertyAccessExpression,
    renderer: GoRenderer,
    submoduleReference?: SubmoduleReference,
  ): OTree {
    if (submoduleReference != null) {
      return new OTree([
        renderer
          .updateContext({ isExported: false, isPtr: false, wrapPtr: false })
          .convert(submoduleReference.lastNode),
      ]);
    }

    const expressionType = typeOfExpression(renderer.typeChecker, node.expression);
    const valueSymbol = renderer.typeChecker.getSymbolAtLocation(node.name);

    const isStaticMember = valueSymbol?.valueDeclaration != null && isStatic(valueSymbol.valueDeclaration);
    const isClassStaticPropertyAccess =
      isStaticMember &&
      expressionType?.symbol?.valueDeclaration != null &&
      valueSymbol.valueDeclaration != null &&
      ts.isClassDeclaration(expressionType.symbol.valueDeclaration) &&
      (ts.isPropertyDeclaration(valueSymbol.valueDeclaration) || ts.isAccessor(valueSymbol.valueDeclaration));
    const isClassStaticMethodAccess =
      isStaticMember &&
      !isClassStaticPropertyAccess &&
      valueSymbol.valueDeclaration != null &&
      ts.isMethodDeclaration(valueSymbol.valueDeclaration);

    // When the expression has an unknown type (unresolved symbol), has an upper-case first letter,
    // and doesn't end in a call expression (as hinted by the presence of parentheses), we assume
    // it's a type name... In such cases, what comes after can be considered a static member access.
    // Note that the expression might be further qualified, so we check using a regex that checks
    // for the last "." - delimited segment if there's dots in there...
    const expressionLooksLikeTypeReference =
      expressionType.symbol == null &&
      /(?:\.|^)[A-Z][^.)]*$/.exec(node.expression.getText(node.expression.getSourceFile())) != null;

    // Whether the node is an enum member reference.
    const isEnumMember =
      expressionType?.symbol?.valueDeclaration != null && ts.isEnumDeclaration(expressionType.symbol.valueDeclaration);

    const jsiiSymbol = lookupJsiiSymbolFromNode(renderer.typeChecker, node.name);
    const isExportedTypeName = jsiiSymbol != null && jsiiSymbol.symbolType !== 'module';

    const delimiter =
      isEnumMember || isClassStaticPropertyAccess || isClassStaticMethodAccess || expressionLooksLikeTypeReference
        ? '_'
        : '.';

    return new OTree([
      renderer.convert(node.expression),
      delimiter,
      renderer
        .updateContext({
          isExported:
            isClassStaticPropertyAccess ||
            isClassStaticMethodAccess ||
            expressionLooksLikeTypeReference ||
            isEnumMember ||
            isExportedTypeName,
        })
        .convert(node.name),
      ...(isClassStaticPropertyAccess
        ? ['()']
        : // If the parent's not a call-like expression, and it's an inferred static property access, we need to put call
        // parentheses at the end, as static properties are accessed via synthetic readers.
        expressionLooksLikeTypeReference && findUp(node, ts.isCallLikeExpression) == null
        ? ['()']
        : []),
    ]);
  }