Skip to content

fix(swift): extract method requirements declared in a protocol body - #3673

Open
rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/swift-protocol-method-requirements
Open

rajatnagda45 wants to merge 1 commit into
Graphify-Labs:v8from
rajatnagda45:fix/swift-protocol-method-requirements

Conversation

@rajatnagda45

Copy link
Copy Markdown
Contributor

Problem

tree-sitter-swift gives a protocol's body-less method requirement its own node type — protocol_function_declaration — rather than reusing the function_declaration used inside a class or struct. The Swift config's function_types only listed function_declaration, so those requirements were never recognised.

The result: a protocol like

protocol Drawable {
    func draw()
    func area() -> Double
}

became an empty node. The method contract — the whole point of a protocol, and the API surface every conforming type must implement — never entered the graph. Protocol-oriented Swift codebases lost their most important abstraction layer.

Fix

Add protocol_function_declaration to both function_types and function_boundary_types in _SWIFT_CONFIG. The generic engine already knows how to turn a function node inside a class body into a .method() node hung off the owner and to walk its signature for type references; it just needed to be told this node type counts.

Now:

  • requirements surface as .method() nodes under the protocol;
  • their signature type references (return / parameter types) are captured;
  • a protocol's draw and a conformer's draw stay distinct nodes, and the implements conformance edge is untouched.

Stored-property requirements are deliberately left alone — that matches how stored properties on a class are already handled (they emit a type reference, not a member node), so behaviour stays consistent across declaration kinds. This mirrors the sibling receiver-method / interface-member handling in the other extractors.

Test

New tests/test_swift_protocol_requirements.py — three cases, all failing before and passing after:

  • method requirements become .method() nodes under the protocol;
  • a requirement's return type still produces a references edge;
  • protocol requirement vs. conformer implementation stay two nodes, conformance edge intact.

All 67 Swift language tests pass.

tree-sitter-swift gives a protocol's body-less method requirement its own
node type, protocol_function_declaration, instead of reusing the
function_declaration used inside a class or struct. The Swift config's
function_types only listed function_declaration, so a protocol like

    protocol Drawable {
        func draw()
        func area() -> Double
    }

became an empty node - the method contract every conformer must implement
never entered the graph.

Add protocol_function_declaration to function_types and
function_boundary_types. Requirements now surface as .method() nodes hung
off the protocol, their signature type references (return/param types) are
captured, and they stay distinct from a conformer's implementation of the
same name. Stored property requirements are left alone, matching how
stored properties on a class are already handled.

Adds regression coverage for all three.

@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 protocol_function_declaration to the Swift config's function and function-boundary types so body-less method requirements inside a protocol { ... } are extracted as method nodes with their signature references, instead of being dropped and leaving the protocol an empty node. Conformer methods stay distinct nodes from the protocol requirements, and the implements heritage edge is unaffected. Covered by a new regression test.

No blocking issues surfaced.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 2044 functions depend on the 256 functions this change touches.

Health — this change adds coupling hotspots:

  • new: extract() — 649 callers, 45 callees
  • new: _rebuild_code() — 137 callers, 54 callees
  • new: extract_js() — 85 callers, 4 callees
  • new: extract_xaml() — 19 callers, 17 callees
  • new: dispatch_command() — 2 callers, 125 callees
  • new: _get_extractor() — 26 callers, 6 callees
  • new: run_pipeline() — 8 callers, 13 callees
  • new: collect_files() — 17 callers, 6 callees
  • …and 30 more — each is listed as a finding

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

Test selection

Test selection

118 of 287 test file(s) selected (41%) via static blast radius.

  • tests/test_astro_extraction.py — impact
  • tests/test_astro_import_ids.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_cpp_nested_and_cli.py — impact
  • 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_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_extract.py — impact
  • tests/test_extract_cache_location.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_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_catch_binding_shadow.py — impact
  • tests/test_indirect_call_external_import_shadow.py — impact
  • tests/test_indirect_call_for_of_binding_shadow.py — impact
  • tests/test_indirect_call_function_expression_shadow.py — impact
  • tests/test_indirect_call_nested_closure_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_inferred_confidence_rubric.py — impact
  • tests/test_inherited_field_receivers.py — impact
  • tests/test_issue_3405_python_resolution.py — impact
  • … and 68 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.

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

@rajatnagda45

Copy link
Copy Markdown
Contributor Author

Same empty-node symptom I hit on the Go side (#3672), but for Swift protocols — turns out protocol_function_declaration just wasn't in the config's function types, so the whole contract vanished. Tested against the existing swift suite, all green.

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