Skip to content

fix(cpp): treat a member-function declaration as a method, not a field - #3963

Open
rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/cpp-member-function-declarations
Open

rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/cpp-member-function-declarations

Conversation

@rajatnagda45

Copy link
Copy Markdown
Contributor

Problem

Inside a class body a virtual double area() = 0; (pure virtual), a virtual void draw(); and a plain prototype int run(); all parse as a field_declaration whose declarator is a function_declarator. The field branch recognised that shape only to skip emitting a type reference — it still emitted a node for every declarator as a data member (a bare area label with a defines/field edge).

Consequences:

  • a pure-virtual interface class had no method nodes, only phantom fields;
  • a header-declared method and its out-of-line/overriding definition did not share one node (area field vs .area() method);
  • a call to such a method resolved to a field-shaped node.

Implementation

In the field-declaration branch, emit a function_declarator with the same shape a defined method uses — a .name() label, a method edge, and callable — so the declaration and its definition collapse to one method node (parity with the Java/TypeScript/Scala abstract-method contract). A genuine data member still gets its defines field edge.

Verification

  • tests/test_cpp_method_declarations.py (new): pure-virtual / declared-virtual / prototype members become method nodes; a data member stays a field; the decl/def merge keeps one node and a call through it resolves. All fail on v8, pass with the fix.
  • This corrects the label of every header-declared method, so a few existing cross-file assertions that expected the old bare bar/run field label now expect .bar()/.run() (test_cpp_objc_cross_file_calls, test_languages). The resolved call edges (source, target, confidence) are unchanged, and the decl/def merge still produces exactly one node carrying the definition site.
  • uv run pytest tests/ — full suite green (6175 passed, 15 skipped).
  • uv run ruff check . clean; uv run pyright adds zero new errors.

Inside a class body a `virtual double area() = 0;` (pure virtual), a
`virtual void draw();` and a plain prototype `int run();` parse as a
`field_declaration` whose declarator is a `function_declarator`. The field
branch recognised that shape only to skip emitting a type reference — it still
emitted a node for every declarator as a DATA MEMBER (a bare `area` label with
a `defines`/field edge).

So a pure-virtual interface class had no method nodes, only phantom fields; a
header-declared method and its out-of-line/overriding definition did not share
one node (`area` field vs `.area()` method); and a call to such a method
resolved to a field-shaped node.

Fix: in the field-declaration branch, emit a function_declarator with the same
shape a defined method uses — a `.name()` label, a `method` edge, and callable
— so the declaration and its definition collapse to one method node (parity
with the Java/TypeScript/Scala abstract-method contract). A genuine data member
still gets its `defines` field edge.

This corrects the label of every header-declared method, so a few existing
cross-file tests that asserted the old bare `bar`/`run` field label now assert
`.bar()`/`.run()`; the resolved call edges (source, target, confidence) are
unchanged, and the decl/def merge still produces exactly one node carrying the
definition site.

Added tests/test_cpp_method_declarations.py.
@github-actions

github-actions Bot commented Oct 1, 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.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.


Graphify review — findings

Fixes C++ member-function declarations so that prototypes, virtual f(); and pure-virtual virtual f() = 0; inside a class body (including pointer/reference-returning ones) are emitted as callable .name() nodes with a method edge instead of bare-named defines fields. Pure-virtual interfaces now get real method nodes, and a declaration shares one node with its out-of-line or in-class definition, so calls resolve to .bar() rather than a phantom bar field. Genuine data members still get their defines field edge, and existing cross-file call tests now expect the .name() labels.

Worth a look

  • C++ function-pointer data members are classified as methods — graphify/extractors/engine.py:5149 · Escalate · medium · 2 independent checks
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1128 functions depend on the 871 functions this change touches.

Health — this change adds coupling hotspots:

  • new: _extract_generic() — 18 callers, 29 callees
  • new: extract_js() — 87 callers, 4 callees
  • new: extract_xaml() — 19 callers, 17 callees
  • new: extract_objc() — 27 callers, 9 callees
  • new: extract_julia() — 19 callers, 7 callees
  • new: extract_cpp() — 31 callers, 3 callees
  • new: extract_vue() — 10 callers, 7 callees
  • new: walk() — 1 callers, 66 callees
  • …and 9 more — each is listed as a finding

Verification — 1128 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: 1082 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

27 of 313 test file(s) selected (9%) via static blast radius.

  • tests/test_astro_extraction.py — impact
  • tests/test_build.py — impact
  • tests/test_cjs_module_extension.py — impact
  • tests/test_cpp_method_declarations.py — impact, changed-test
  • tests/test_cpp_nested_and_cli.py — impact
  • tests/test_cpp_objc_cross_file_calls.py — impact, changed-test
  • tests/test_dotnet.py — impact
  • tests/test_extract.py — impact
  • tests/test_extract_php_closures.py — impact
  • tests/test_import_extension_resolution.py — impact
  • tests/test_indirect_call_block_scoped_shadow.py — impact
  • tests/test_indirect_dispatch.py — impact
  • tests/test_indirect_dispatch_assign_return.py — impact
  • tests/test_indirect_dispatch_getattr.py — impact
  • tests/test_js_exported_scalar_bindings.py — impact
  • tests/test_languages.py — impact, changed-test
  • tests/test_multilang.py — impact
  • tests/test_python_underscore_resolution.py — impact
  • tests/test_rationale.py — impact
  • tests/test_ruby_resolution.py — impact
  • tests/test_scala_self_type.py — impact
  • tests/test_swift_computed_properties.py — impact
  • tests/test_swift_protocol_requirements.py — impact
  • tests/test_trailing_newline_not_a_syntax_error.py — impact
  • tests/test_ts_new_expression_calls.py — impact
  • tests/test_typescript_module_extensions.py — impact
  • tests/test_vue_extraction.py — impact

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.

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

This branch has not been deployed

No deployments
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.

1 participant