Recover qualified Swift call edges (Type.method / Type.shared.method) that Graphify's AST pass drops, reconnecting cross-service call pathways in the knowledge graph.
Project description
graphify-swift-edges
Recover qualified Swift call edges that Graphify's tree-sitter pass records but never links — reconnecting cross-type call pathways in the knowledge graph.
The problem
Graphify builds a code knowledge graph with tree-sitter. For Swift it correctly records each
type's methods (Type --method--> .foo()), but it does not link qualified call sites back
to the callee's method node:
// Caller.swift
try PaymentStore.reconcile(id: row.id) // static, fully resolvable
let rows = PaymentStore.shared.fetch(query: q) // singleton, fully resolvable
These are fully-resolvable calls, yet in the resulting graph the callee type has zero incoming
calls edges. Types that talk to each other through static or singleton methods become
disconnected islands, so graphify path and graphify affected cannot trace the pathway
between them — even though the call is right there in the source.
What this tool does
It re-parses the source with the same tree-sitter grammar, then resolves qualified calls
deterministically against the graph's own symbol table and appends the missing calls edges:
- Build
{TypeLabel → typeNode}and{(typeNode, method) → methodNode}from the graph's existingmethodedges. - Walk every
call_expression; keepnavigation_expressioncallees of the formType.method(…)orType.shared.method(…)(PascalCase receiver). - Resolve receiver → type node, attribute the caller by enclosing-type AST ancestry
(not a line heuristic), and emit
caller --calls--> methodNode.
Precision guards (why it doesn't invent edges)
An edge is emitted only when all hold — otherwise the call is skipped, never guessed:
- the receiver label maps to exactly one type node (ambiguous labels are skipped);
- that type actually owns a method of that name;
- the receiver is type/singleton-qualified (unqualified
foo()is skipped — see Scope).
Validation — GRDB.swift (479 files)
A large, real-world, open-source Swift codebase (different authors, heavy use of extensions, generics, and protocols), checkout including its test suite:
| result | |
|---|---|
calls edges added |
70 |
path PlayerListModel → AppDatabase |
"No path found" → 2-hop call edge |
| precision (independent type-def check) | 69 / 70 (98.6%) |
Reproduce:
graphify . # build graphify-out/graph.json on GRDB
graphify-swift-edges graphify-out/graph.json . -o graphify-out/graph.json
graphify path "PlayerListModel" "AppDatabase" # now a real 2-hop call edge
Two honest findings this surfaced:
- Recall is codebase-dependent, and the guard is deliberately conservative. GRDB triggered
3,614 ambiguous-receiver skips because extension/generic-heavy types fragment into many
same-label nodes (
Database→ 15 nodes;TableRecord/FetchRequest→ 5 each) and the test suite defines many same-named fixtures (Player,Pet,Item). The tool skips all of these rather than guess — fewer edges, never wrong ones. Recovery scales with how many qualified calls have an unambiguous receiver, which varies a lot by codebase. - The single false positive is the documented residual mode.
Pet.setup()resolved even though GRDB definesstruct Petin several test files: the upstream graph had collapsed them into one node, so the ambiguity guard couldn't see the collision. 1-in-70, confined to duplicated test fixtures — exactly what the IndexStoreDB route (Scope) would eliminate.
Precision was measured independently of the parser, via type-definition uniqueness in the raw
source: a receiver whose name has exactly one class/struct/enum/actor/protocol definition cannot
be a same-name collision.
Usage
uv tool install graphify-swift-edges # or: pip install graphify-swift-edges
# after `graphify` has built graphify-out/graph.json:
graphify-swift-edges graphify-out/graph.json /path/to/swift/src -o graphify-out/graph.json
Then query the reconnected graph with graphify path (verified working):
graphify path "SomeCaller" "SomeCallee" --graph graphify-out/graph.json
# Shortest path (2 hops): SomeCaller --calls [RESOLVED_QUALIFIED]--> .method() <--method-- SomeCallee
affected caveat (measured): recovered edges point at method nodes. graphify affected
on the owning type returns nothing (it reverse-traverses calls but not method), and on a
method label it errors with No unique node match (labels like .fetch() are ambiguous
across types). So use path for cross-type tracing, not affected, until Graphify's affected
learns to hop method edges.
Scope (honest boundaries)
- Recovers: type-qualified (
Foo.bar()) and singleton-qualified (Foo.shared.bar()) calls. - Does NOT recover: instance-variable calls (
let s = Foo(); s.bar()) — these need real type inference. The correct general fix is a SourceKit / IndexStoreDB extractor that reads Swift's precise semantic index (protocol dispatch, generics, inferred types included). That is the documented sequel, not this tool. - The residual false-positive mode (a same-name type whose duplicate definitions the upstream graph collapsed into one node) is rare and, in testing, confined to duplicated test fixtures.
- Validated on one large open-source codebase; the resolution is language-general in principle (Kotlin, TS have the same qualified-call shape) but only Swift is implemented and measured here.
Tests
uv run --with pytest --with tree-sitter --with tree-sitter-swift python -m pytest
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file graphify_swift_edges-0.1.0.tar.gz.
File metadata
- Download URL: graphify_swift_edges-0.1.0.tar.gz
- Upload date:
- Size: 22.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5be5b925820dee0691234f0cee6afc076da49661d7011441088949f38d2b9666
|
|
| MD5 |
ce76a162fe8385b3f5656df949afd5d4
|
|
| BLAKE2b-256 |
1e69fd57e1cddab1cd23355a0311f341a2c0ed72f7ba92da9a59f17b7162e2aa
|
Provenance
The following attestation bundles were made for graphify_swift_edges-0.1.0.tar.gz:
Publisher:
publish.yml on novicetrader11-arch/graphify-swift-edges
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
graphify_swift_edges-0.1.0.tar.gz -
Subject digest:
5be5b925820dee0691234f0cee6afc076da49661d7011441088949f38d2b9666 - Sigstore transparency entry: 1751638039
- Sigstore integration time:
-
Permalink:
novicetrader11-arch/graphify-swift-edges@e1b66ad8fa2b8ec53e93ef05ba345c436163fffc -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/novicetrader11-arch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e1b66ad8fa2b8ec53e93ef05ba345c436163fffc -
Trigger Event:
release
-
Statement type:
File details
Details for the file graphify_swift_edges-0.1.0-py3-none-any.whl.
File metadata
- Download URL: graphify_swift_edges-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18bf85e0ba9d2bf3054b9c42e405261dfbf5210e8e6a4f1f876d5ab64ee0a06a
|
|
| MD5 |
dd5a66b35dd11a6c05a3b2967c3dd5b4
|
|
| BLAKE2b-256 |
027733a66a38ed64026b2a44e5e0e93bde1fd19175d94a501df95b6d793037f6
|
Provenance
The following attestation bundles were made for graphify_swift_edges-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on novicetrader11-arch/graphify-swift-edges
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
graphify_swift_edges-0.1.0-py3-none-any.whl -
Subject digest:
18bf85e0ba9d2bf3054b9c42e405261dfbf5210e8e6a4f1f876d5ab64ee0a06a - Sigstore transparency entry: 1751638162
- Sigstore integration time:
-
Permalink:
novicetrader11-arch/graphify-swift-edges@e1b66ad8fa2b8ec53e93ef05ba345c436163fffc -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/novicetrader11-arch
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e1b66ad8fa2b8ec53e93ef05ba345c436163fffc -
Trigger Event:
release
-
Statement type: