module Noir::KotlinCalleeExtractor

Overview

Tree-sitter-backed Kotlin 1-hop callee extractor. Parallels Noir::JavaCalleeExtractor for JVM analyzers — both Spring (Kotlin) and Ktor route through this module. Kotlin's call_expression wraps either a simple_identifier (bare call), a navigation_expression (a.b.c selector chain, optionally rooted on this/super), or an inner call_expression (the foo(...) { } trailing-lambda shape). 1-hop extraction reduces to:

  1. For Spring Kotlin: find the (class_name, method_name) function_declaration in the already-parsed root and walk its function_body.
  2. For Ktor: walk the verb DSL call's lambda statements node.
  3. For each call_expression, reconstruct a textual callee:
    • foo()foo
    • service.save(x)service.save
    • this.foo()this.foo
    • super.foo()super.foo
    • Foo.bar() (static) → Foo.bar
    • getFoo().bar() → "" (chained on a call — outer dropped as noise, inner getFoo still emitted via the recursive walk)

Cross-file definition resolution (e.g. userService.saveUserServiceImpl.save in another file) is intentionally out of scope for this first cut. Callee#path therefore points at the call site, matching the honest scope on every other analyzer.

Extended Modules

Defined in:

miniparsers/kotlin_callee_extractor.cr

Constant Summary

ROUTING_DSL_NAMES = Set {"get", "post", "put", "delete", "patch", "head", "options", "route", "routing", "authenticate", "rateLimit", "install", "intercept", "host", "port"}

Routing DSL verbs + scoping helpers. When skip_routing is on (Ktor handler body), a call_expression whose root name is in this set is treated as a NESTED ROUTE — we skip both emitting it and descending into its trailing lambda so the nested route's callees don't leak into the parent route's list.

Instance Method Summary

Instance Method Detail

def callees_in_lambda(body : LibTreeSitter::TSNode, source : String, file_path : String, skip_routing : Bool = true) : Array(Tuple(String, String, Int32)) #

Ktor / http4k entry: given a handler body node, return every 1-hop callee inside it. skip_routing controls whether Ktor's routing DSL (route { ... }, sibling verb calls, etc.) is treated as a NESTED ROUTE boundary — Ktor needs this on so a nested route's callees don't leak into the parent; http4k uses an entirely different routing idiom ("/x" bind GET to h) and turns the skip off so a real handler call named get isn't silently dropped.


[View source]
def callees_in_method(root : LibTreeSitter::TSNode, source : String, file_path : String, class_name : String, method_name : String) : Array(Tuple(String, String, Int32)) #

Spring Kotlin entry: find the (class_name, method_name) function_declaration in root and return every 1-hop call_expression callee inside its body as {name, file_path, file_line_1_based}. Empty array when the function can't be located or its body is missing.


[View source]