Skip to content

v3.15.0

Latest

Choose a tag to compare

@carlos-alm carlos-alm released this 22 Jun 03:53
· 9 commits to main since this release
cb42049

Dynamic call detection ships across all 34 languages, plus richer codegraph stats output and a new ignoreAdditionalDirs config option. Seven phases of dynamic dispatch detection land in a single release: Reflect/decorator patterns in JS/TS, JVM dynamic dispatch with Kotlin callable-reference resolution, Python getattr/eval/functools.partial, Ruby send/public_send and PHP call_user_func, Go MethodByName and C/C++ dlsym/function-pointer detection, and C#/Swift/Elixir/Lua long-tail patterns. Every pattern is classified with a DynamicKind taxonomy (computed-literal, computed-key, reflection, eval, unresolved-dynamic) and visible via a new codegraph roles --dynamic flag; resolved calls remain in the normal call graph while unresolvable patterns emit zero-confidence sink edges that never pollute regular queries. A closed dispatch-table resolver (RES-2) handles ({a:fnA,b:fnB})[key]() via the existing PTS wildcard solver. codegraph stats now breaks down dead symbols by actionable sub-role (dead-leaf, dead-unresolved, dead-ffi, dead-entry, dead-callable), fixing a pre-existing double-counting bug in the dead total. A new ignoreAdditionalDirs config field lets projects append additional directories to the built-in IGNORE_DIRS without patching codegraph source.

Features

  • dynamic-calls: detect and flag dynamic call sites in JS/TS — DynamicKind taxonomy classifies every dynamic call at extraction time; sink edges flagged as dynamic_kind in a new DB column (migration v20); new codegraph roles --dynamic flag surfaces them; Rust native extractor fully mirrored (#1629)
  • dynamic-calls: Reflect.apply/construct/get and TypeScript @Foo decorator detection (Phase 1) — JS/TS-specific reflection idioms emit reflection-kind calls; both walk and query extractor paths updated; Rust mirrored (#1637)
  • dynamic-calls: JVM dynamic dispatch — Java Method.invoke/Class.forName/getMethod, Kotlin callable references (::fn), Scala/Groovy invoke patterns; Kotlin ::fn refs resolve at 100% recall (Phase 2) (#1646)
  • dynamic-calls: Python getattr/eval/exec/functools.partial detection; getattr(obj, 'method') resolves at 100% recall for top-level functions (Phase 3) (#1653)
  • dynamic-calls: Ruby send/public_send and PHP call_user_func/$fn() detection; literal symbol calls resolve at 100% recall (Phase 4) (#1654)
  • dynamic-calls: Go reflect.MethodByName and C/C++ function-pointer/dlsym detection; both resolve at 100% recall for literal names (Phase 5) (#1655)
  • dynamic-calls: C# GetMethod/Invoke, Swift NSSelectorFromString/performSelector, Elixir apply, Lua load/loadstring/bracket-index calls, ObjC performSelector, Dart Function.apply; Swift resolves at 100% recall; Rust extractor mirrored for all four languages (Phase 6) (#1657, #1670)
  • dynamic-calls: RES-2 — closed dispatch-table resolution — ({a:fnA,b:fnB})[key]() resolves to each table entry via the PTS wildcard solver; Rust native mirror included (#1677)
  • stats: separate dead-code categories in codegraph stats — per-sub-role breakdown with actionability labels (dead-leaf, dead-unresolved, dead-ffi, dead-entry, dead-callable); fixes pre-existing double-counting bug where the synthetic dead aggregate was summed alongside individual sub-role counts (#1648)
  • config: add ignoreAdditionalDirs to .codegraphrc.json — array of directory names merged with the built-in IGNORE_DIRS at file-collection time; included in BUILD_HASH_KEYS to trigger a full rebuild when changed; crates removed from the global IGNORE_DIRS default (add it to ignoreAdditionalDirs in your own .codegraphrc.json if needed) (#1666)

Bug Fixes

  • dataflow: P4 incremental re-stitch + P6 vertex extraction on native engine path — vertex rows extracted during bulk-insert pass; re-stitch fires on callee-only changes without a full rebuild; P6 parity fix for incremental vs full-build paths (#1635)
  • dataflow: make dataflow vertex write and inter-procedural stitch atomic — closes half-written state gap when the process is killed between vertex insert and stitch (#1658)
  • dataflow: purge dataflow rows keyed by call_edge_id before edge deletion — prevents FK constraint failures during incremental file purge that left stale nodes after file deletion (#1662)
  • dynamic-calls: RES-3 type-aware method name lookup for JVM getMethod patterns — Rust resolver now uses receiver type to construct qualified lookup for Groovy, Java, and Scala getMethod calls
  • native: Kotlin callable-ref prefers class method over top-level function; suppress spurious invoke sink edge that diverged from WASM (#1686)
  • native: CJS require bindings now produce receiver-edge parity with WASM — require()-destructured class types emit receiver call edges on the native path (#1671, #1678, #1679)
  • native: always run JS role re-classification on full builds to fix hasActiveFileSiblings parity — incremental-only re-classification left stale role assignments on fresh builds
  • wasm: preserve dyn=1 when deduplicating edges with same source/target/kind/confidence — bare @Log decorator was silently dropped when @Log() call-expression had already been processed first (#1688)
  • native: dispatch-table PTS resolution in JS extractor — ({a:fnA,b:fnB})[key]() now resolves on the native path, matching WASM output (#1690)
  • stats: exclude sink edges (dynamic call placeholders, confidence=0.0) from the call-confidence denominator; lift minimum confidence for resolved ts-native edges from 0.3 → 0.5 (#1641)
  • stats: suppress false-positive high-fan-in warnings for Rust ::new() constructors (#1643)
  • mcp: break 37-file circular dependency by extracting McpToolContext to mcp/types.ts — two consecutive architectural audits had flagged this cycle (#1638)
  • config: ignoreAdditionalDirs and ignoreDirs now respected in watch mode (#1666)
  • analysis: exclude gitignored NAPI-RS artifacts from native gap detection — prevents spurious WARN and unnecessary WASM backfill on every fresh --no-incremental build (#1647)
  • analysis: exclude NAPI-RS generated index.js from WASM engine analysis — eliminates false 359 cognitive-complexity reading for requireNative in codegraph triage (#1636)
  • types: use @types/better-sqlite3 types in getDatabase() and McpToolContext — removes last any usages in the DB layer (#1639)

Chores

  • docs: add ADRs for dynamic call resolution and interprocedural dataflow (#1675)
  • deps: bump better-sqlite3 from 12.10.0 to 12.11.1 (#1634)
  • deps: bump vitest from 4.1.8 to 4.1.9 (#1633)
  • deps: bump actions/checkout from 6 to 7 (#1630)