Skip to content

fix(cpp): extract union specifiers as class-like type nodes - #4052

Closed
rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/cpp-union-specifier
Closed

rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/cpp-union-specifier

Conversation

@rajatnagda45

Copy link
Copy Markdown
Contributor

Closes #4051

Problem

A named C++ union is dropped from the graph entirely — the type and all its members vanish:

union Value { int i; float f; };
struct Point { int x; };

Point and its members are in the graph; Value / i / f are not.

Cause

union_specifier was missing from _CPP_CONFIG.class_types. class_specifier, struct_specifier, and enum_specifier are all there, so a union was the only class-like container that fell through and was dropped.

Fix

Add union_specifier to class_types. It shares struct_specifier's name/body fields (type_identifier + field_declaration_list), so the existing generic container handling gives it a type node, a contains edge from its file, and a data member per field — exactly like a struct. An anonymous union has no type_identifier and is skipped by the existing name guard, like an anonymous enum.

Tests

Added test_cpp_union_specifier_is_extracted: a named union becomes a type node with defines edges to its members, and a typedef union { ... } Anon mints no nameless node. Fails on current v8, passes with the fix. Full suite: 6345 passed, 15 skipped. ruff clean; pyright on extract.py unchanged (119 errors before and after, 0 added).

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown

Thanks for the pull request, @rajatnagda45. A maintainer will review it soon.

Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions.

A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

Adds union_specifier to the C++ class_types, so a named union { ... } now becomes a type node with its data members (file contains the union, the union defines each field) instead of vanishing entirely. Anonymous unions such as typedef union { ... } Anon have no type name and are still skipped, matching anonymous enums.

No blocking issues surfaced.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 2349 functions depend on the 289 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract() — 753 callers, 50 callees
  • new: _rebuild_code() — 149 callers, 56 callees
  • new: extract_js() — 87 callers, 4 callees
  • new: extract_xaml() — 19 callers, 17 callees
  • new: main() — 99 callers, 3 callees
  • new: dispatch_command() — 2 callers, 127 callees
  • new: _get_extractor() — 27 callers, 6 callees
  • new: collect_files() — 19 callers, 6 callees
  • …and 35 more — each is listed as a finding

Verification — 2349 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 2164 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

142 of 326 test file(s) selected (44%) via static blast radius.

  • tests/test_astro_extraction.py — impact
  • tests/test_astro_import_ids.py — impact
  • tests/test_blade_extractor.py — impact
  • tests/test_build.py — impact
  • tests/test_builtin_global_type_refs.py — impact
  • tests/test_case_sensitive_resolution.py — impact
  • tests/test_cjs_module_extension.py — impact
  • tests/test_cobol_extractor.py — impact
  • tests/test_cpp_method_declarations.py — impact
  • tests/test_cpp_nested_and_cli.py — impact, changed-test
  • tests/test_cpp_objc_cross_file_calls.py — impact
  • tests/test_cross_extension_reexport_self_cycle.py — impact
  • tests/test_cross_language_call_resolution.py — impact
  • tests/test_cross_repo_external_call_guards.py — impact
  • tests/test_cross_repo_member_calls.py — impact
  • tests/test_csharp_call_site_generic_args.py — impact
  • tests/test_csharp_enum_members.py — impact
  • tests/test_csharp_field_generic_args.py — impact
  • tests/test_csharp_generic_callsites.py — impact
  • tests/test_csharp_interface_dispatch.py — impact
  • tests/test_csharp_member_calls.py — impact
  • tests/test_csharp_member_nodes.py — impact
  • tests/test_csharp_object_creation.py — impact
  • tests/test_csharp_partial_classes.py — impact
  • tests/test_csharp_tuple_type_refs.py — impact
  • tests/test_csharp_type_resolution.py — impact
  • tests/test_definition_file_portability.py — impact
  • tests/test_detect.py — impact
  • tests/test_dotnet.py — impact
  • tests/test_duplicate_annotation_edges.py — impact
  • tests/test_elixir_import_resolution.py — impact
  • tests/test_elixir_unqualified_call_scope.py — impact
  • tests/test_erlang_extractor.py — impact
  • tests/test_extract.py — impact
  • tests/test_extract_cache_location.py — impact
  • tests/test_extract_php_closures.py — impact
  • tests/test_file_label_disambiguation.py — impact
  • tests/test_file_node_id_spec.py — impact
  • tests/test_forwarding_review_findings.py — impact
  • tests/test_go_builtin_call_targets.py — impact
  • tests/test_go_import_repoint.py — impact
  • tests/test_go_interface_methods.py — impact
  • tests/test_go_qualified_resolution.py — impact
  • tests/test_import_extension_resolution.py — impact
  • tests/test_import_self_loops.py — impact
  • tests/test_imported_export_forwarding.py — impact
  • tests/test_incremental.py — impact
  • tests/test_indirect_call_arrow_single_param_shadow.py — impact
  • tests/test_indirect_call_block_scoped_shadow.py — impact
  • tests/test_indirect_call_catch_binding_shadow.py — impact
  • … and 92 more

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

· 43 more finding(s) on lines outside this diff (see the check run).

@safishamsi

Copy link
Copy Markdown
Member

Shipped in v0.9.76 (live on PyPI as graphifyy==0.9.76). Landed on v8 via an authorship-preserving cherry-pick, so your original commit authorship is kept. Thanks @rajatnagda45 for C++ union specifiers 🙏

Closing as shipped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cpp: a named union is dropped from the graph entirely

2 participants