Problem
The AST extractor (tree-sitter) processes files in isolation and does not perform cross-file type inference. This causes a large class of inter-file relationships — arguably the most architecturally important ones — to be absent from the graph.
Root Cause
Tree-sitter is a per-file parser. When analyzing FileA.swift, it can resolve types and method calls only for symbols defined within the same file. Any reference to a type defined in FileB.swift requires cross-file type inference, which tree-sitter does not do.
Concrete Examples (from a real iOS project)
Example 1: View → ViewModel (MVVM core relationship)
Code:
// SessionViewController.swift
class SessionViewController: UIViewController {
let viewModel = SessionViewModel() // ← constructor call to another file
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
viewModel.update() // ← method call to another file
}
}
// SessionViewModel.swift
class SessionViewModel: NSObject {
func update() { ... }
}
Graph result: Zero edges between SessionViewController and SessionViewModel. They sit in different communities (284 vs 34) with no connection.
Why:
viewModel.update() — var.method() syntax requires inferring viewModel's type (SessionViewModel), which is defined in another file. Tree-sitter cannot resolve this.
SessionViewModel() — constructor syntax TypeName() should theoretically be detectable, but property initializers do not generate calls edges the way method-body constructors do.
Example 2: Static method on cross-file class
Code:
// SettingViewController.swift (LaikeMineModule)
let alert = NLKAlertStandardViewController.alertView(
withTitle: "...",
isButtonHorizontalLayout: true,
highlightButtonTitle: "...",
...
)
// NLKAlertStandardViewController+Helper.m (LaikeUIKit)
@implementation NLKAlertStandardViewController (Helper)
- (id)alertViewWithTitle:... { ... }
Graph result: No calls edge from SettingViewController to NLKAlertStandardViewController.
Why: TypeName.staticMethod(...) requires resolving TypeName first, then looking up staticMethod on it. NLKAlertStandardViewController is defined in another pod (LaikeUIKit), tree-sitter cannot resolve.
Example 3: Singleton method chain
Code:
// LoginManager.swift
public func logout() {
NENetworkCenter.shared().cancelAllRequests() // not captured
AccountCenter.shared.clearUserStatus() // not captured
clearUserCookies() // captured (same file)
}
Graph result: Only clearUserCookies() is captured as a calls edge.
Why: clearUserCookies() uses prefix-less syntax → same-file method → detected. AccountCenter.shared.clearUserStatus() uses Type.method.method() chain → AccountCenter is defined in another file → not resolved.
What IS captured (for contrast)
| Call form |
Example |
Captured? |
Why |
func() |
clearUserCookies() |
Yes |
Same-file, no type resolution needed |
TypeName(args) |
ASAuthorizationController(...) |
Yes |
Constructor syntax is unambiguous |
var.method() same-file |
fortuneCard.configure(...) |
Yes |
Both caller and callee in same file |
var.method() cross-file |
viewModel.update() |
No |
var type in another file |
Type.method() cross-file |
NLKAlert.alertView(...) |
No |
Type defined in another file |
Singleton.shared.method() |
AccountCenter.shared.clearUserStatus() |
No |
Singleton type in another file |
Impact
This is a significant gap. The most architecturally meaningful edges — MVVM bindings, service dependencies, manager relationships — are predominantly cross-file. In the analyzed project, only 906 calls edges exist vs 3121 references edges, suggesting most cross-file method invocations are downgraded to type references or lost entirely.
Problem
The AST extractor (tree-sitter) processes files in isolation and does not perform cross-file type inference. This causes a large class of inter-file relationships — arguably the most architecturally important ones — to be absent from the graph.
Root Cause
Tree-sitter is a per-file parser. When analyzing
FileA.swift, it can resolve types and method calls only for symbols defined within the same file. Any reference to a type defined inFileB.swiftrequires cross-file type inference, which tree-sitter does not do.Concrete Examples (from a real iOS project)
Example 1: View → ViewModel (MVVM core relationship)
Code:
Graph result: Zero edges between
SessionViewControllerandSessionViewModel. They sit in different communities (284 vs 34) with no connection.Why:
viewModel.update()—var.method()syntax requires inferringviewModel's type (SessionViewModel), which is defined in another file. Tree-sitter cannot resolve this.SessionViewModel()— constructor syntaxTypeName()should theoretically be detectable, but property initializers do not generatecallsedges the way method-body constructors do.Example 2: Static method on cross-file class
Code:
Graph result: No
callsedge fromSettingViewControllertoNLKAlertStandardViewController.Why:
TypeName.staticMethod(...)requires resolvingTypeNamefirst, then looking upstaticMethodon it.NLKAlertStandardViewControlleris defined in another pod (LaikeUIKit), tree-sitter cannot resolve.Example 3: Singleton method chain
Code:
Graph result: Only
clearUserCookies()is captured as acallsedge.Why:
clearUserCookies()uses prefix-less syntax → same-file method → detected.AccountCenter.shared.clearUserStatus()usesType.method.method()chain →AccountCenteris defined in another file → not resolved.What IS captured (for contrast)
func()clearUserCookies()TypeName(args)ASAuthorizationController(...)var.method()same-filefortuneCard.configure(...)var.method()cross-fileviewModel.update()vartype in another fileType.method()cross-fileNLKAlert.alertView(...)Typedefined in another fileSingleton.shared.method()AccountCenter.shared.clearUserStatus()Singletontype in another fileImpact
This is a significant gap. The most architecturally meaningful edges — MVVM bindings, service dependencies, manager relationships — are predominantly cross-file. In the analyzed project, only 906
callsedges exist vs 3121referencesedges, suggesting most cross-file method invocations are downgraded to type references or lost entirely.