You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: credit instanceof ClassName checks as exports consumers
codegraph exports did not credit `instanceof ClassName` checks (or other
bare-reference, no-call-site usages) as consumers. CodegraphError showed
consumerCount:0 via `codegraph exports src/shared/errors.ts --json` despite
two real production usages (src/cli.ts, src/mcp/server.ts) that only ever
reference it via `err instanceof CodegraphError` — never `new
CodegraphError(...)`. Subclasses consumed via constructor calls were
correctly credited (ConfigError, consumerCount:23); only bare-reference
usages like instanceof were invisible to the consumer counter, so any
base/parent class whose primary cross-file use is instanceof narrowing
falsely presented as dead/unused.
Root cause: no edge at all was created for the right-hand operand of an
`instanceof` binary expression — the same "no edge for a bare-identifier
value reference" gap as #1771 (object-literal property values) and #1776
(Lua builtin reassignment), just at a different syntactic position.
Fix: both engines now extract a dynamic `calls` edge (dynamicKind/
dynamic_kind = 'value-ref') when instanceof's right operand is a bare
identifier, reusing the #1771/#1776 taxonomy entry rather than introducing
a new DynamicKind — ADR-002 explicitly anticipated this as "syntax-position-
agnostic" and invited a third extraction site to reuse it. Unlike the
function/method-only #1771/#1776 sites, the resolver-side kind filter for
value-ref now also accepts class-kind targets, since instanceof's operand is
always a class/constructor (never a plain data reference) — it still accepts
function-kind too, correctly covering the pre-ES6 "constructor function"
instanceof idiom (`x instanceof SomeFunction`).
Applied to both engines:
- WASM/TS: src/extractors/javascript.ts (collectInstanceofValueRefCall,
wired into the shared runCollectorWalk's binary_expression case),
src/domain/graph/builder/stages/build-edges.ts (resolveFallbackTargets
kind filter extended to accept 'class'), src/domain/graph/builder/
incremental.ts (mirrored filter for the incremental/watch-mode path).
- Native: crates/codegraph-core/src/extractors/javascript.rs
(handle_instanceof_value_ref, wired into match_js_node's binary_expression
arm — dispatches for JavaScript/TypeScript/Tsx alike), crates/
codegraph-core/src/domain/graph/builder/stages/build_edges.rs (matching
kind filter in process_file).
- src/types.ts / docs/architecture/decisions/002-dynamic-call-resolution.md:
documented instanceof as the third value-ref extraction site and the
class-kind target-set extension.
Verified against the exact repro on both engines: CodegraphError now shows
consumerCount:2 (src/cli.ts, createCallToolHandler in src/mcp/server.ts),
identical between native and WASM. codegraph roles --role dead does not (and
did not) flag the CodegraphError class itself — exported classes are never
classified dead by role, independent of this fix; the fix's measurable
effect is the consumer-count/fan-in correction. Total dead-symbol count
across the repo's own graph dropped from 816 to 810 as a side effect of
crediting other instanceof-only-referenced symbols codebase-wide.
Resolution-benchmark: no fixture exercises instanceof, so precision/recall
is byte-identical before and after (javascript 100/100, typescript
95.7/93.6, aggregate 63.8% recall) — confirmed empirically, not assumed.
Fixes#1784
docs check acknowledged — internal edge-emission/resolver bug fix, no new
commands, languages, or architecture to document.
Impact: 5 functions changed, 17 affected
Copy file name to clipboardExpand all lines: src/types.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -488,7 +488,7 @@ export type DynamicKind =
488
488
|'reflection'// .call/.apply/.bind / Reflect.* / callable-ref — resolved when target is in codebase; sink edge emitted if unresolved
489
489
|'eval'// eval() / new Function() — undecidable; always flagged
490
490
|'unresolved-dynamic'// any other detected dynamic pattern; flagged
491
-
|'value-ref';// bare identifier used as a value reference rather than a call site — object-literal property value (dispatch-table pattern, e.g. `{ resolve: someFn }`, #1771) or assignment to a Lua global/builtin identifier (e.g. `require = tracedRequire`, #1776)— resolved only against function/method-kind targets; unresolved (e.g. plain data references) are dropped silently, NOT flagged
491
+
|'value-ref';// bare identifier used as a value reference rather than a call site — object-literal property value (dispatch-table pattern, e.g. `{ resolve: someFn }`, #1771), assignment to a Lua global/builtin identifier (e.g. `require = tracedRequire`, #1776), or the right operand of an `instanceof` check (e.g. `err instanceof CodegraphError`, #1784) — resolved only against function/method/class-kind targets (class only relevant for the instanceof site); unresolved (e.g. plain data references) are dropped silently, NOT flagged
492
492
493
493
/** A function/method call detected by an extractor. */
0 commit comments