Version
dev build from source at 4da8f877 (tag v0.10.8 lineage). 19 commits behind origin/main; none of those 19 touch the Swift front end or the call-resolution passes, and my own local commits do not either. Should reproduce on stock main.
Platform
macOS (Apple Silicon) — macOS 26.6.2, arm64
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
In a Swift project, calls into Foundation are bound to project-local members that merely share the last path component. The call graph then reports edges that do not exist.
Two of the three in the minimal repro below resolve onto stored properties — the graph contains a CALLS edge whose target is a :Variable node, which cannot be called at all.
This is not confined to a low-confidence tier. The minimal case produces all three at strategy=unique_name, confidence=0.75; in the real project the same failure also appears via suffix_match at 0.14, 0.21 and 0.55. So a confidence threshold alone would not catch it.
I expected these calls either to be left unresolved or to be marked as external, not bound to unrelated project symbols.
Same class as the already-recognised family, filed per-language the way this project already does: #476 Perl (closed, fixed), #606 PHP (open), #1276 Python (open), #1572 Python/TS cross-language via unique_name, #1355 same-named symbol binding. Swift is not yet reported.
Worth noting alongside #43 (Swift: CALLS edges not resolved), which is closed as completed. That fix is working — Swift now produces 12,017 CALLS edges in my real project. This report is the accuracy gap that arrived with them.
Related to my #1892 only in that both are Swift front-end gaps; the two are independent.
Reproduction
One Swift file. Three project types whose member names collide with Foundation members; three calls that are unambiguously Foundation's.
import Foundation
struct PickedFile {
let data: Data // a stored property, not callable
}
struct DateOnly {
static func string(from date: Date) -> String { "" }
}
struct Point {
let date: Date? // a stored property, not callable
}
final class Caller {
func fetch() async throws -> Data {
let url = URL(string: "https://example.com/x")!
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
func readSetting() -> String? {
return UserDefaults.standard.string(forKey: "someKey")
}
func tomorrow(from now: Date) -> Date? {
return Calendar.current.date(byAdding: .day, value: 1, to: now)
}
}
With a minimal Package.swift, git init, then index_repository mode=full.
MATCH (a)-[r:CALLS]->(b) RETURN r.callee, r.strategy, r.confidence, b.qualified_name, b.start_line:
| callee |
strategy |
confidence |
resolved to |
target line |
correct? |
URLSession.shared.data |
unique_name |
0.75 |
Main.data |
5 |
no — let data: Data |
UserDefaults.standard.string |
unique_name |
0.75 |
Main.DateOnly.string |
9 |
no — string(from:) is unrelated |
Calendar.current.date |
unique_name |
0.75 |
Main.date |
13 |
no — let date: Date? |
And the structural invariant that is violated — MATCH (a)-[r:CALLS]->(b:Variable):
callee resolved_to line parent
URLSession.shared.data Main.data 5 Main.PickedFile
Calendar.current.date Main.date 13 Main.Point
Rejecting any CALLS edge whose target node is not callable would catch two of the three here without touching the naming heuristics.
On a real project
A 462-file / 64k-line Swift app. Every call into a system framework, with each resolution checked against the source by hand:
| callee |
strategy |
conf |
resolved to |
correct? |
URLSession.shared.data |
suffix_match |
0.21 |
HomeboxUI.PickedFile.data |
no |
UserDefaults.standard.string ×3 |
unique_name |
0.75 |
AuthDTOs.HomeboxDateOnly.string(from:) |
no |
JSONEncoder().encode |
suffix_match |
0.14 |
MaintenanceDTOs.MaintenanceEntryCreate.encode(to:) |
no |
Calendar.current.date ×2 |
suffix_match |
0.55 |
StatisticsDTOs.date (a public let date: Date?) |
no |
Calendar.utcGregorian.startOfDayUTC |
unique_name |
0.75 |
AuthDTOs.Calendar.startOfDayUTC |
yes |
Seven of eight wrong. The eighth is genuinely correct — the project really does declare extension Calendar { static let utcGregorian; func startOfDayUTC(for:) }, so I am not counting it against the resolver.
Likely root: Swift has no import or LSP tier
Resolution strategies actually used, same binary, two projects indexed minutes apart:
| strategy |
Swift project (12,017 CALLS) |
Go + TS project (20,650 CALLS) |
import_map |
0 |
5,381 |
lsp_* (11 variants) |
0 |
2,478 |
unique_name |
5,300 |
4,933 |
suffix_match |
3,827 |
3,348 |
field_type_hint |
1,673 |
51 |
qualified_suffix |
723 |
3 |
same_module |
494 |
4,246 |
Swift uses 5 strategies; Go/TS uses 21. With no import map and no LSP tier, there is nothing that can say URLSession is external, so name matching is the only thing left. The Swift graph also carries no Package label at all, where the Go/TS project has 215 Package nodes with an external flag.
Scale, stated honestly
suffix_match confidence spread in the Swift project, all 22 distinct values: 1,151 edges at 0.55, the remaining 2,676 below 0.5 — 70% of suffix_match edges, 22% of all CALLS edges.
I am not claiming those 2,676 are all wrong. Sampling the 0.04 tier turned up vm.load → EntityListViewModel.load, which is plausibly correct despite the confidence. The demonstrable errors are the system-framework ones above. The confidence figures are here to show that a threshold is not the fix — the wrong edges sit at 0.75.
Project scale (if relevant)
Repro: 2 files. Real project: 462 Swift files / 64,101 lines, 3,766 Method nodes, 12,017 CALLS edges.
Version
devbuild from source at4da8f877(tagv0.10.8lineage). 19 commits behindorigin/main; none of those 19 touch the Swift front end or the call-resolution passes, and my own local commits do not either. Should reproduce on stockmain.Platform
macOS (Apple Silicon) — macOS 26.6.2, arm64
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
In a Swift project, calls into Foundation are bound to project-local members that merely share the last path component. The call graph then reports edges that do not exist.
Two of the three in the minimal repro below resolve onto stored properties — the graph contains a
CALLSedge whose target is a:Variablenode, which cannot be called at all.This is not confined to a low-confidence tier. The minimal case produces all three at
strategy=unique_name, confidence=0.75; in the real project the same failure also appears viasuffix_matchat 0.14, 0.21 and 0.55. So a confidence threshold alone would not catch it.I expected these calls either to be left unresolved or to be marked as external, not bound to unrelated project symbols.
Same class as the already-recognised family, filed per-language the way this project already does:
#476Perl (closed, fixed),#606PHP (open),#1276Python (open),#1572Python/TS cross-language viaunique_name,#1355same-named symbol binding. Swift is not yet reported.Worth noting alongside
#43(Swift: CALLS edges not resolved), which is closed as completed. That fix is working — Swift now produces 12,017CALLSedges in my real project. This report is the accuracy gap that arrived with them.Related to my
#1892only in that both are Swift front-end gaps; the two are independent.Reproduction
One Swift file. Three project types whose member names collide with Foundation members; three calls that are unambiguously Foundation's.
With a minimal
Package.swift,git init, thenindex_repository mode=full.MATCH (a)-[r:CALLS]->(b) RETURN r.callee, r.strategy, r.confidence, b.qualified_name, b.start_line:URLSession.shared.dataMain.datalet data: DataUserDefaults.standard.stringMain.DateOnly.stringstring(from:)is unrelatedCalendar.current.dateMain.datelet date: Date?And the structural invariant that is violated —
MATCH (a)-[r:CALLS]->(b:Variable):Rejecting any
CALLSedge whose target node is not callable would catch two of the three here without touching the naming heuristics.On a real project
A 462-file / 64k-line Swift app. Every call into a system framework, with each resolution checked against the source by hand:
URLSession.shared.dataHomeboxUI.PickedFile.dataUserDefaults.standard.string×3AuthDTOs.HomeboxDateOnly.string(from:)JSONEncoder().encodeMaintenanceDTOs.MaintenanceEntryCreate.encode(to:)Calendar.current.date×2StatisticsDTOs.date(apublic let date: Date?)Calendar.utcGregorian.startOfDayUTCAuthDTOs.Calendar.startOfDayUTCSeven of eight wrong. The eighth is genuinely correct — the project really does declare
extension Calendar { static let utcGregorian; func startOfDayUTC(for:) }, so I am not counting it against the resolver.Likely root: Swift has no import or LSP tier
Resolution strategies actually used, same binary, two projects indexed minutes apart:
import_maplsp_*(11 variants)unique_namesuffix_matchfield_type_hintqualified_suffixsame_moduleSwift uses 5 strategies; Go/TS uses 21. With no import map and no LSP tier, there is nothing that can say
URLSessionis external, so name matching is the only thing left. The Swift graph also carries noPackagelabel at all, where the Go/TS project has 215Packagenodes with anexternalflag.Scale, stated honestly
suffix_matchconfidence spread in the Swift project, all 22 distinct values: 1,151 edges at 0.55, the remaining 2,676 below 0.5 — 70% ofsuffix_matchedges, 22% of allCALLSedges.I am not claiming those 2,676 are all wrong. Sampling the 0.04 tier turned up
vm.load→EntityListViewModel.load, which is plausibly correct despite the confidence. The demonstrable errors are the system-framework ones above. The confidence figures are here to show that a threshold is not the fix — the wrong edges sit at 0.75.Project scale (if relevant)
Repro: 2 files. Real project: 462 Swift files / 64,101 lines, 3,766
Methodnodes, 12,017CALLSedges.