Repository navigation
Swift: computed properties emit no node — erases the entire SwiftUI view layer (var body is a computed property) #2181
Description
Version: graphify 0.9.25
Language: Swift (_SWIFT_CONFIG, extract.py:984)
Summary
_SWIFT_CONFIG treats only function_declaration / init_declaration / deinit_declaration / subscript_declaration as functions. A Swift computed property parses as property_declaration → computed_property, which appears in none of function_types, function_boundary_types, or body_fallback_child_types.
Consequence: a computed property gets no node, and its contents are never walked as a body. In SwiftUI, var body: some View { … } is a computed property — so for a SwiftUI codebase this silently erases the entire view layer.
The graph still looks healthy afterwards (types, funcs, and imports are all present), which is what makes this hard to notice: query and explain return confident, well-formed results that simply omit the UI, with no signal that anything is missing.
Reproduction
struct PlayerScrubber: View {
var body: some View {
VStack { Slider(value: .constant(0), in: 0...1) }
.contextMenu {
Button { mode.toggle() } label: { Label("Scrub Chapter", systemImage: "book") }
}
}
var toggled: Int { 1 }
func realFunction() -> Int { 2 }
}tree-sitter-swift parse (abridged):
class_declaration L1 struct PlayerScrubber: View {
class_body L1 {
property_declaration L2 var body: some View {
computed_property L2 { <-- not a recognised body type
property_declaration L9 var toggled: Int { 1 }
computed_property L9 { 1 } <-- same
function_declaration L10 func realFunction() -> Int { 2 }
function_body L10 { 2 } <-- recognised
Resulting graph: nodes for PlayerScrubber and .realFunction(). Nothing for body or toggled.
Observed on a real ~6.8k-node / 17k-edge SwiftUI project: a 108-line view file yields exactly two nodes — the file and the struct. Every Slider, .contextMenu, and Button inside body is invisible. In that same file a static func on a sibling enum extracts correctly, so the omission is specifically computed properties, not the file or the type.
Practical symptom that led me here: explain "<Type>" works well, but no query can answer "where is this control wired into the UI?" — because the answer lives inside body and body does not exist in the graph.
Why the obvious fix is wrong
Adding property_declaration to function_types would also match stored properties (var x = 5), which are not functions and have no body. On a medium codebase that mints thousands of junk nodes and leaves the graph worse than before.
Suggested fix
Emit a function-like node only when a property_declaration has a computed_property child, and treat that computed_property as the body/scope boundary.
That condition is on tree shape, so it doesn't fit the declarative LanguageConfig — but there's existing precedent for exactly this shape in _swift_extra_walk, which already special-cases Swift enum cases.
Worth handling in the same pass, since both also parse as computed_property:
willSet/didSetobservers on stored properties- explicit
get { } set { }accessor blocks
Impact
Any SwiftUI codebase, and any Swift codebase that puts logic in computed properties. Swift support is otherwise strong here — extension merging, receiver-typed member-call resolution, and module-aware imports all work well, which is why this one gap is easy to miss.
Related
Distinct from #2147, but they compound on SwiftUI projects. On the same corpus, View (degree 210), Foundation (264), SwiftUI (111) and RhapsodeKit (275) act as universal connectors, so path "A" "B" between two symbols in the same feature returned a five-hop route through View, an unrelated screen type, and Bool. #2147 covers why those hubs exist; this issue covers why the real intermediate nodes — the view bodies that would otherwise carry the connection — are missing. Fixing one without the other leaves SwiftUI traversal weak either way.
Happy to send a PR
If you can confirm the fix belongs in _swift_extra_walk rather than somewhere else, I'm glad to implement it. I have a 6.8k-node SwiftUI project currently exhibiting the bug, so I can report before/after node and edge counts on a real corpus rather than only a synthetic fixture — useful given this will shift node counts for every Swift repo and presumably move some snapshot tests.
Activity
fix(swift): extract computed & observed properties (#2181)
chore: bump to 0.9.28; changelog for #2211/#2213/#2210/#2212/#2215/#2221
safishamsi commentedon Jul 27, 2026
Fixed in v0.9.28 (#2220, thanks @ozdemirsarman). Swift computed and observed properties (var body: some View { ... }, get/set, willSet/didSet) now emit graph nodes, so SwiftUI views are no longer erased. https://github.com/Graphify-Labs/graphify/releases/tag/v0.9.28
drewmerc302 commentedon Jul 27, 2026
Confirmed fixed on the original corpus. Before/after numbers as offered, on the real ~7k-node SwiftUI project rather than a fixture.
Method: identical working tree and commit for both runs,
extract --code-only --no-cluster --forceso it's pure AST with no LLM or clustering in the loop. 455 code files, 409 Swift, ~56k Swift LOC.All 573 new nodes come from
.swiftfiles, and none are orphans — each gets an inboundmethodedge from its owning type, plus 569callsand 36referencesoutbound. So the body contents are being walked, not just the property node emitted. That was the part I was least sure would land.150 of the new nodes are
.body. The previous graph had zero.The file I used in the report is a clean example.
PlayerUI/PlayerScrubber.swiftwent 2 nodes → 3, and the new.bodynode has degree 8:That's the query I couldn't answer before — "where is this control wired into the UI" — now resolving to real project symbols instead of dead-ending.
17 other files were in the same ≤2-node state and are now populated. Biggest single gain was
Library/ItemDetailBody.swift, 19 → 45 nodes.Worth noting for anyone else measuring this: node counts shift by ~9% on Swift repos, so snapshot tests will move.
Also confirming #2147 (v0.9.27) from the same corpus, since the two compound as expected:
View,FoundationandSwiftUIare gone from the god-node ranking entirely. The top hubs are now all project types —RhapsodeKit(277),ActiveConnection(229),APIClient(198). Traversal between two symbols in the same feature no longer detours throughViewand an unrelated screen.Thanks @ozdemirsarman and @safishamsi — both fixes landed clean.
ozdemirsarman commentedon Jul 27, 2026
Thanks for taking the time to validate this so thoroughly on a real-world SwiftUI project and for sharing the before/after numbers. It’s great to see that the
.bodynodes are not only being emitted, but that their contents, calls, and references are now being traversed correctly.The improvements to the previously under-populated files and the god-node ranking are especially encouraging. The note about the ~9% node-count shift and its impact on snapshot tests is also very helpful.
Really appreciate the detailed verification, Andrew!
fix(swift): extract computed & observed properties (Graphify-Labs#2181)
chore: bump to 0.9.28; changelog for Graphify-Labs#2211/Graphify-Labs…
merge: backport upstream Swift extras (Graphify-Labs#2181 Graphify-La…