Skip to content

Commit 566c7ac

Browse files
artus9033meta-codesync[bot]
authored andcommitted
fix: stabilize CXX API generator on MacOS, make parser indempotent for nested enums (#57536)
Summary: Fixes C++ API snapshot generation failures for nested enums and macOS/Linux output drift due to platform-dependent behavior, in the CXX API generator. ### Problems 1. Duplicate enums: Doxygen parses codegen `EventEmitters.h` twice (direct codegen input + again via `.mm` includes). The parser raised `RuntimeError: Identifier OnOrientationChangeOrientation already exists in scope ModalHostViewEventEmitter` on `ReactApple*` views. 2. Inconsistent behaviour on MacOS vs Linux: - for codegen component aliases (`ConcreteComponentDescriptor`, `ConcreteViewShadowNode`), macOS Doxygen emits hybrid XML definitions (`typedef Type Name = Type`) while Linux CI emits `using Name = Type`. The parser keyed off `definition.startswith("typedef")`, so identical source produced different `.api` output per platform. - `CASE_SENSE_NAMES = SYSTEM` follows the host OS default (case-insensitive on macOS, case-sensitive on Linux), causing inconsistent symbol resolution. ### Resolution - `.doxygen.config.template` files: set `CASE_SENSE_NAMES = YES` for deterministic name matching across macOS and Linux. - `snapshot.py`: `create_enum()` returns an existing enum scope instead of raising when the enum is already registered. - `builders.py`: `create_enum_scope()` to skip enums that already exist; `get_typedef_member()` to normalize Doxygen’s `typedef ... = ...` form to `using` so the output format is unified. ## Changelog: [INTERNAL] [FIXED] - Fix C++ API snapshot generation crash on duplicate codegen enums [INTERNAL] [FIXED] - Fix platform-dependent inconsistent CXX API generator output Pull Request resolved: #57536 Test Plan: - [x] `yarn cxx-api-build` completes on macOS (tested locally) - [x] `yarn cxx-api-validate` passes (tested locally on MacOS & on the Linux CI) - [x] `validate-cxx-api-snapshots` passes on Linux (tested on CI) Reviewed By: j-piasecki Differential Revision: D112793182 Pulled By: coado fbshipit-source-id: ada818451fb1207d965c1bed4fb5ce23ee2fe00f
1 parent f2a6db9 commit 566c7ac

5 files changed

Lines changed: 29 additions & 4 deletions

File tree

packages/react-native/.doxygen.config.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ INTERNAL_DOCS = NO
653653
# Possible values are: SYSTEM, NO and YES.
654654
# The default value is: SYSTEM.
655655

656-
CASE_SENSE_NAMES = SYSTEM
656+
CASE_SENSE_NAMES = YES
657657

658658
# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with
659659
# their full class and namespace scopes in the documentation. If set to YES, the

scripts/cxx-api/manual_test/.doxygen.config.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ INTERNAL_DOCS = NO
653653
# Possible values are: SYSTEM, NO and YES.
654654
# The default value is: SYSTEM.
655655

656-
CASE_SENSE_NAMES = SYSTEM
656+
CASE_SENSE_NAMES = YES
657657

658658
# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with
659659
# their full class and namespace scopes in the documentation. If set to YES, the

scripts/cxx-api/parser/builders.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
TypedefMember,
2929
VariableMember,
3030
)
31+
from .member.base import is_function_pointer_argstring
3132
from .scope import InterfaceScopeKind, ProtocolScopeKind, StructLikeScopeKind
3233
from .snapshot import Snapshot
3334
from .template import Template
@@ -460,7 +461,21 @@ def get_typedef_member(
460461

461462
typedef_keyword = "using"
462463
if typedef_definition.startswith("typedef"):
463-
typedef_keyword = "typedef"
464+
# Doxygen's "combining using relations" pass can emit hybrid definitions
465+
# like "typedef Type Name = Type" for using-declarations on macOS, while
466+
# Linux builds report "using Name = Type". Normalise the hybrid form for
467+
# codegen component aliases so snapshots are stable across platforms.
468+
if (
469+
"=" in typedef_definition
470+
and not is_function_pointer_argstring(typedef_argstring)
471+
and (
472+
"ConcreteComponentDescriptor" in typedef_definition
473+
or "ConcreteViewShadowNode" in typedef_definition
474+
)
475+
):
476+
typedef_keyword = "using"
477+
else:
478+
typedef_keyword = "typedef"
464479

465480
typedef = TypedefMember(
466481
typedef_name,
@@ -605,6 +620,14 @@ def create_enum_scope(snapshot: Snapshot, enum_def: compound.EnumdefType) -> Non
605620
"""
606621
Create an enum scope in the snapshot.
607622
"""
623+
path = parse_qualified_path(enum_def.qualifiedname)
624+
parent_scope = snapshot.ensure_scope(path[0:-1])
625+
enum_name = path[-1]
626+
if enum_name in parent_scope.inner_scopes:
627+
existing = parent_scope.inner_scopes[enum_name]
628+
if existing.kind.name == "enum":
629+
return
630+
608631
scope = snapshot.create_enum(enum_def.qualifiedname)
609632
scope.kind.type = resolve_linked_text_name(enum_def.get_type())[0]
610633
scope.location = enum_def.location.file

scripts/cxx-api/parser/snapshot.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ def create_enum(self, qualified_name: str) -> Scope[EnumScopeKind]:
184184
scope = current_scope.inner_scopes[enum_name]
185185
if scope.kind.name == "temporary":
186186
scope.kind = EnumScopeKind()
187+
elif scope.kind.name == "enum":
188+
return scope
187189
else:
188190
raise RuntimeError(
189191
f"Identifier {enum_name} already exists in scope {current_scope.name}"

scripts/cxx-api/tests/snapshots/.doxygen.config.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ INTERNAL_DOCS = NO
653653
# Possible values are: SYSTEM, NO and YES.
654654
# The default value is: SYSTEM.
655655

656-
CASE_SENSE_NAMES = SYSTEM
656+
CASE_SENSE_NAMES = YES
657657

658658
# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with
659659
# their full class and namespace scopes in the documentation. If set to YES, the

0 commit comments

Comments
 (0)