Environment
- graphify 0.9.7 (PyPI
graphifyy), macOS, Python 3.10
- Extraction invoked directly via
graphify.extract.extract(files, parallel=False) (same result through the CLI pipeline)
Summary
Calls to members of a Kotlin object (singleton) resolve to calls edges only when caller and callee are in the same file. The identical pattern across two files produces zero edges — not even a references edge from the caller's class to the object.
This is the Kotlin sibling of the Swift navigation-expression work that landed in 0.9.5 (#1604) and looks adjacent to #1696 (Java receivers) and #1682 (PHP member calls).
Reproducer (3 files)
MessageHelper.kt
package demo
object MessageHelper {
fun isRoomClosed(roomId: String): Boolean {
return roomId.isEmpty()
}
}
RoomPage.kt
package demo
class RoomPage {
fun refresh(roomId: String) {
if (MessageHelper.isRoomClosed(roomId)) {
return
}
}
}
SameFile.kt (control — same pattern, single file)
package demo
object LocalHelper {
fun isReady(): Boolean = true
}
class LocalPage {
fun open() {
if (LocalHelper.isReady()) {
return
}
}
}
Current behavior (0.9.7)
Same-file control resolves correctly:
samefile_localpage_open --calls--> samefile_localhelper_isready [EXTRACTED]
Cross-file case emits nothing. roompage_roompage_refresh has only:
roompage_roompage --method--> roompage_roompage_refresh [EXTRACTED]
roompage_roompage_refresh --references--> roompage_kt_string [EXTRACTED]
No calls edge to messagehelper_messagehelper_isroomclosed, and no references edge to MessageHelper at all.
Expected
roompage_roompage_refresh --calls--> messagehelper_messagehelper_isroomclosed [EXTRACTED or INFERRED]
The receiver here is a navigation-qualified object name — statically unambiguous, no type inference needed, so this should be the easiest cross-file case for Kotlin.
Real-world impact
Found while indexing a large production Android monorepo (~5,900 Kotlin/Java files). A messaging utility object whose method is called from 3 different files (verified by grep and by a Hybrid-LSP-based tool, which both report all 3 callers) shows zero incoming calls edges in the graph, so "who calls X" silently returns an empty answer instead of failing loudly. Kotlin object + top-level utility functions are the dominant utility pattern in Android codebases, so this gap affects a large share of caller-lookup queries.
Environment
graphifyy), macOS, Python 3.10graphify.extract.extract(files, parallel=False)(same result through the CLI pipeline)Summary
Calls to members of a Kotlin
object(singleton) resolve tocallsedges only when caller and callee are in the same file. The identical pattern across two files produces zero edges — not even areferencesedge from the caller's class to theobject.This is the Kotlin sibling of the Swift navigation-expression work that landed in 0.9.5 (#1604) and looks adjacent to #1696 (Java receivers) and #1682 (PHP member calls).
Reproducer (3 files)
MessageHelper.ktRoomPage.ktSameFile.kt(control — same pattern, single file)Current behavior (0.9.7)
Same-file control resolves correctly:
Cross-file case emits nothing.
roompage_roompage_refreshhas only:No
callsedge tomessagehelper_messagehelper_isroomclosed, and noreferencesedge toMessageHelperat all.Expected
The receiver here is a navigation-qualified
objectname — statically unambiguous, no type inference needed, so this should be the easiest cross-file case for Kotlin.Real-world impact
Found while indexing a large production Android monorepo (~5,900 Kotlin/Java files). A messaging utility
objectwhose method is called from 3 different files (verified by grep and by a Hybrid-LSP-based tool, which both report all 3 callers) shows zero incomingcallsedges in the graph, so "who calls X" silently returns an empty answer instead of failing loudly. Kotlinobject+ top-level utility functions are the dominant utility pattern in Android codebases, so this gap affects a large share of caller-lookup queries.