ek9_query_call_graph

Answers first: callerNames / calleeNames and callerSites / calleeSites ('file.ek9:LINE') - then the chain to the requested depth.

Category: Enquiry · Compare: Call Hierarchy (IntelliJ)

When to use it

Who calls a method or function, and what does it call, to a depth - one call with symbol:'Type.member', no file needed.

When not to use it

Details

direction: 'both' (default) | 'outgoing' (callees, what this depends on) | 'incoming' (callers, refactor-impact); depth 0-5 (default 1, capped at 5), with depth>1 recursing via a nested children[] per node — hop level is implicit in nesting. Response: the headline names and sites, the target's flat signature/complexity fields, then incomingCalls[]/outgoingCalls[]; each node carries caller or callee (display name), fullyQualifiedName, calledAt 'file.ek9:LINE' (the call expression; a caller calling more than once has its first here and the rest in alsoCalledAt[]), declaredAt 'file.ek9:LINE' (the callable's declaration), callKind (function-call | method-call), pure and context (the source line at the call site). The graph is built during PRE_IR_CHECKS — a workspace compiled to an earlier phase errors with the reached phase (the default ek9_compile phase suffices), and a line not on a method/function returns {callGraph:'not_found', message:...}.

Arguments

ArgumentTypeRequiredWhat it is
amongarray of stringNames to answer FOR: 'which of these ...' - the name lists shrink to these and amongUnmatched names the ones that are not in the answer. Bare names, 'mod::Type' or 'Type.member'; a MODULE name stands for every construct in it ('which in scale.m07 do not ...' = amongUnmatched).
depthintegerMaximum traversal depth (0-5, default 1)
directionstring: both | outgoing | incomingDirection: 'both' (default), 'outgoing', or 'incoming'
filestringThe EK9 source file - OPTIONAL when symbol is a construct name; required to anchor on a member or a use site.
lineinteger1-based line of the declaration or a reference - OMIT it and pass symbol:'<name>' to let the tool find the line (a model counting lines in a file miscounts); if you do count, use ek9_read_file(lineNumbers:true).
symbolstringA construct NAME alone ('Shape', 'sample.deps.core::Validator') - no file needed, the tool finds it workspace-wide; or, with file (+ line), the identifier you mean there.

It also takes the arguments every tool takes.

Recorded calls

Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 7 recorded are shown.

Program by symbol

Request

{
  "direction" : "outgoing",
  "symbol" : "Main"
}

Response

{
  "calleeNames" : [ "greet" ],
  "calleeSites" : [ "Hello.ek9:13" ],
  "callerNames" : [ ],
  "callerSites" : [ ],
  "depth" : 1,
  "direction" : "outgoing",
  "enclosingGenus" : "PROGRAM",
  "enclosingType" : "Main",
  "fullyQualifiedName" : "com.example.hello::Main",
  "meta" : {
    "serverMs" : "<timing>"
  },
  "method" : "Main",
  "outgoingCallCount" : 1,
  "outgoingCalls" : [ {
    "callKind" : "function-call",
    "calledAt" : "Hello.ek9:13",
    "callee" : "greet",
    "context" : "greet(\"World\")",
    "declaredAt" : "Hello.ek9:6",
    "fullyQualifiedName" : "com.example.hello::greet",
    "pure" : false
  } ],
...

Cut short here: 5 more lines. The whole recorded call.

Call graph shape

Request

{
  "file" : "Hello.ek9",
  "line" : 13
}

Response

{
  "calleeNames" : [ "greet" ],
  "calleeSites" : [ "Hello.ek9:13" ],
  "callerNames" : [ ],
  "callerSites" : [ ],
  "depth" : 1,
  "direction" : "both",
  "enclosingGenus" : "PROGRAM",
  "enclosingType" : "Main",
  "fullyQualifiedName" : "com.example.hello::Main",
  "incomingCallCount" : 0,
  "incomingCalls" : [ ],
  "meta" : {
    "serverMs" : "<timing>"
  },
  "method" : "Main",
  "outgoingCallCount" : 1,
  "outgoingCalls" : [ {
    "callKind" : "function-call",
    "calledAt" : "Hello.ek9:13",
    "callee" : "greet",
    "context" : "greet(\"World\")",
    "declaredAt" : "Hello.ek9:6",
    "fullyQualifiedName" : "com.example.hello::greet",
...

Cut short here: 7 more lines. The whole recorded call.

Overload named by parameterisation

Request

{
  "direction" : "incoming",
  "symbol" : "Stash.keep(List of Integer)"
}

Response

{
  "calleeNames" : [ ],
  "calleeSites" : [ ],
  "callerNames" : [ "Tally" ],
  "callerSites" : [ "Stash.ek9:32" ],
  "cognitiveComplexity" : 0,
  "complexity" : 1,
  "depth" : 1,
  "direction" : "incoming",
  "enclosingGenus" : "CLASS",
  "enclosingType" : "Stash",
  "fullyQualifiedName" : "com.example.stash::keep",
  "incomingCallCount" : 1,
  "incomingCalls" : [ {
    "callKind" : "method-call",
    "calledAt" : "Stash.ek9:32",
    "caller" : "Tally",
    "context" : "stash.keep(items)",
    "declaredAt" : "Stash.ek9:28",
    "fullyQualifiedName" : "com.example.stash::Tally",
    "pure" : false
  } ],
  "meta" : {
    "serverMs" : "<timing>"
...

Cut short here: 12 more lines. The whole recorded call.