Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
2b6a00d
fix: scope codegraph batch complexity targets to file paths
carlos-alm Jul 5, 2026
b28051a
fix: exclude parameters and interface/type members from dead-role cla…
carlos-alm Jul 5, 2026
17fbcba
fix: credit import-type usages as exports consumers
carlos-alm Jul 5, 2026
26918bb
fix: prevent fn-impact/query crash when -f/--file is passed
carlos-alm Jul 5, 2026
be6432c
fix: correct exported-symbol detection for literal and object-literal…
carlos-alm Jul 5, 2026
4ead840
fix: exclude primitive type keywords from ast --kind string matching
carlos-alm Jul 5, 2026
f6326bf
fix: resolve call edges through renamed import specifiers
carlos-alm Jul 5, 2026
590f560
fix: couple file_hashes updates with edge regeneration in incremental…
carlos-alm Jul 5, 2026
d3ea4a4
fix: compare signature-change diffs using new-file line ranges
carlos-alm Jul 5, 2026
c306812
feat: add environment doctor check for stale native binary and missin…
carlos-alm Jul 5, 2026
8bb5893
fix: eliminate non-deterministic ordering in community detection
carlos-alm Jul 6, 2026
46037b1
fix: sync update-graph.sh hook extension allowlist with EXTENSIONS
carlos-alm Jul 6, 2026
6a84cf9
fix: recompute directory structure metrics for affected directories o…
carlos-alm Jul 6, 2026
8d936d1
refactor: register hardcoded execFileSync/execSync maxBuffer values i…
carlos-alm Jul 6, 2026
11c84be
fix: gate blast-radius check on newly introduced risk, not pre-existi…
carlos-alm Jul 6, 2026
963301a
fix: gate identifier-argument dynamic call edges on callback-acceptin…
carlos-alm Jul 6, 2026
3e8035d
fix: gate Array.from's callback arg by position, not just callee name
carlos-alm Jul 6, 2026
879635e
fix: scope reexportedSymbols to actually-named re-export specifiers
carlos-alm Jul 6, 2026
0fe9fc3
fix: stop CFG block/edge count from overriding AST-derived cyclomatic…
carlos-alm Jul 6, 2026
ccf3c19
fix: backfill edges.technique for incrementally-inserted calls edges
carlos-alm Jul 6, 2026
d5b1162
fix: wrap remote embedding JSON parse failure in EngineError
carlos-alm Jul 6, 2026
8971017
refactor: extract shared platform-default-path helper in config.ts
carlos-alm Jul 6, 2026
056c5e4
refactor: decompose loadConfig and related high-effort functions in c…
carlos-alm Jul 6, 2026
0738171
refactor: decompose findDbPath and openRepo in db/connection.ts (docs…
carlos-alm Jul 6, 2026
6f2423c
refactor: dedupe busy/locked error detection into isBusyOrLockedError
carlos-alm Jul 6, 2026
4c02378
fix: log statSync failures in findDbPath instead of silently swallowi…
carlos-alm Jul 6, 2026
0698e16
test: add direct unit coverage for closeDbPair/closeDbPairDeferred/cl…
carlos-alm Jul 6, 2026
4ac3b99
fix: correct blast-radius/fn-impact computation for line-shifted decl…
carlos-alm Jul 6, 2026
6767f09
feat: wire points-to solver max-iterations cap through DEFAULTS.analy…
carlos-alm Jul 6, 2026
5f6f30a
refactor: route console.log calls in domain/search through logger
carlos-alm Jul 6, 2026
b479318
refactor: reduce cyclomatic complexity of computeDeltaModularityDirected
carlos-alm Jul 6, 2026
c39ac40
refactor: unify impact-level rendering format between audit and fn-im…
carlos-alm Jul 6, 2026
067674f
refactor: dedupe computeSavings via pct helper and persist partial to…
carlos-alm Jul 6, 2026
f6807b4
fix: add main.rs driver to rust dynamic tracer fixture
carlos-alm Jul 6, 2026
1c07a54
fix: scope diff file-header detection to between-hunk positions
carlos-alm Jul 6, 2026
bf82aa2
fix: update titan-grind's dead-symbol script for current roles --json…
carlos-alm Jul 6, 2026
cd02d27
fix: thread configured busyTimeoutMs through remaining read-only quer…
carlos-alm Jul 6, 2026
980b5dc
fix: resolve computed string-literal keys in object-literal extractio…
carlos-alm Jul 6, 2026
4a873a3
fix: add same-class bare-call fallback to incremental rebuild path (d…
carlos-alm Jul 6, 2026
8f3348a
fix: unify Object.defineProperty accessor fallback kind-filtering bet…
carlos-alm Jul 6, 2026
acf804c
refactor: share chunked statement-cache primitive between builder and…
carlos-alm Jul 6, 2026
986c851
refactor: cache prepared statements in applyEdgeTechniquesAfterNative…
carlos-alm Jul 6, 2026
71e9174
fix: replace fixed-depth directory-proximity check with symmetric dis…
carlos-alm Jul 6, 2026
d2935cc
refactor: remove unreachable Partition delta-computation interface me…
carlos-alm Jul 6, 2026
6515186
fix: emit reference edges for function identifiers used as object-lit…
carlos-alm Jul 6, 2026
30c491a
refactor: unify call-ref and tests rendering format between audit and…
carlos-alm Jul 6, 2026
9db911b
fix: classify destructured bindings as constant, not function (docs c…
carlos-alm Jul 6, 2026
70559fc
refactor: adopt timeMedian in remaining benchmark timing loops
carlos-alm Jul 6, 2026
822e0eb
refactor: decompose runPerfBenchmarks in token-benchmark.ts
carlos-alm Jul 6, 2026
fcdfe7d
fix: attribute liveness to Lua functions assigned to global/builtin i…
carlos-alm Jul 6, 2026
ee6362c
refactor: extract shared sedi() helper for tracer scripts
carlos-alm Jul 6, 2026
d4e6212
fix: restore reflection dynamicKind for .call/.apply/.bind (docs chec…
carlos-alm Jul 6, 2026
aec5d2b
fix: restrict entry-role classification to function/method-kind symbo…
carlos-alm Jul 6, 2026
d250f8d
fix: credit destructured dynamic import() bindings as exports consumers
carlos-alm Jul 6, 2026
75978e2
fix: recognize Lua function nodes in complexity metrics computation (…
carlos-alm Jul 6, 2026
af17b6d
fix: scope global call-resolution fallback to same-language candidate…
carlos-alm Jul 6, 2026
dd447bc
fix: credit instanceof ClassName checks as exports consumers
carlos-alm Jul 6, 2026
9bb778a
fix: resolve merge conflicts with main (docs check acknowledged)
carlos-alm Jul 8, 2026
b0144ea
fix: correct self-contradictory value-ref filter docs (docs check ack…
carlos-alm Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -785,16 +785,22 @@ fn process_file<'a>(
let mut targets = resolve_call_targets(
ctx, call, fc.rel_path, imported_from, &fc.type_map, caller_name, imported_original_name,
);
// #1771: object-literal property-value references resolve against
// function/method-kind targets only — a bare identifier there is as
// likely to be a plain data reference (`{ name: SOME_CONSTANT }`) as
// a function reference, so drop any non-callable match rather than
// fabricating a "calls" edge to a constant/class/etc. Applied once
// here (after all resolve_call_targets tiers), mirroring the
// `dynamicKind === 'value-ref'` filter in resolveFallbackTargets
// (stages/build-edges.ts).
// #1771/#1784: value-ref references (object-literal property values,
// Lua builtin reassignment, `instanceof ClassName`) resolve against
// function/method/class-kind targets only. A bare identifier in one
// of these positions is as likely to be a plain data reference
// (`{ name: SOME_CONSTANT }`) as a real function/class, so drop any
// other-kind match rather than fabricating a "calls" edge to a
// constant. `class` was added because `instanceof`'s right operand
// is always a class/constructor (#1784). The filter is keyed on
// `dynamic_kind`, not on which site produced the call, so the #1771
// object-literal and #1776 Lua sites also gain class-kind
// resolution as a side effect — not because either idiom commonly
// names a class. Applied once here (after all resolve_call_targets
// tiers), mirroring the `dynamicKind === 'value-ref'` filter in
// resolveFallbackTargets (stages/build-edges.ts).
if call.dynamic_kind.as_deref() == Some("value-ref") {
targets.retain(|t| t.kind == "function" || t.kind == "method");
targets.retain(|t| t.kind == "function" || t.kind == "method" || t.kind == "class");
}
sort_targets_by_confidence(&mut targets, fc.rel_path, imported_from);
emit_call_edges(&targets, caller_id, is_dynamic, fc.rel_path, imported_from, &mut seen_edges, &mut pts_edge_map, edges);
Expand Down
106 changes: 106 additions & 0 deletions crates/codegraph-core/src/extractors/javascript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,8 @@ fn match_js_node(node: &Node, source: &[u8], symbols: &mut FileSymbols, _depth:
"shorthand_property_identifier" => {
handle_object_literal_shorthand_value_ref(node, source, &mut symbols.calls)
}
// #1784: `instanceof ClassName` checks, e.g. `err instanceof CodegraphError`.
"binary_expression" => handle_instanceof_value_ref(node, source, &mut symbols.calls),
_ => {}
}
}
Expand Down Expand Up @@ -2507,6 +2509,47 @@ fn handle_object_literal_shorthand_value_ref(node: &Node, source: &[u8], calls:
});
}

/// Collect a dynamic value-ref `Call` for the right-hand operand of an
/// `instanceof` binary expression when it's a bare identifier — e.g.
/// `err instanceof CodegraphError` (issue #1784). `instanceof` reads its
/// right operand as a value (a prototype-chain check), never calls it, so
/// this is the same "referenced as a value, not a call site" shape as the
/// object-literal (#1771) and Lua builtin-reassignment (#1776) sites —
/// reused rather than given its own `dynamic_kind` (see ADR-002).
///
/// Restricted to plain `identifier` right operands: `a instanceof B.C`
/// (`member_expression`) and `a instanceof (foo())` (parenthesized/call
/// expressions) are left unresolved rather than guessing — same
/// "restrict to the simplest syntactic shape" precedent as #1771.
///
/// Unlike the function/method-only value-ref sites, `instanceof`'s operand
/// is always a class/constructor — the resolver-side kind filter in
/// `build_edges.rs` accepts `class`-kind targets in addition to
/// function/method for this reason.
///
/// Mirrors `collectInstanceofValueRefCall` in `src/extractors/javascript.ts`.
fn handle_instanceof_value_ref(node: &Node, source: &[u8], calls: &mut Vec<Call>) {
let Some(operator_n) = node.child_by_field_name("operator") else { return };
if node_text(&operator_n, source) != "instanceof" {
return;
}
let Some(right_n) = node.child_by_field_name("right") else { return };
if right_n.kind() != "identifier" {
return;
}
let text = node_text(&right_n, source);
if JS_BUILTIN_GLOBALS.contains(&text) {
return;
}
calls.push(Call {
name: text.to_string(),
line: start_line(&right_n),
dynamic: Some(true),
dynamic_kind: Some("value-ref".to_string()),
..Default::default()
});
}

/// Extract definitions from destructured object bindings: `const { handleToken,
/// checkPermissions } = initAuth(...)` creates definitions for `handleToken`
/// and `checkPermissions`, kind `constant` — matching the convention for plain
Expand Down Expand Up @@ -4445,6 +4488,69 @@ mod tests {
assert!(s.calls.iter().all(|c| c.dynamic_kind.as_deref() != Some("value-ref")));
}

// ── #1784: instanceof value-ref extraction ──────────────────────────────

#[test]
fn extracts_value_ref_call_for_instanceof_class_name() {
let s = parse_js(
"function handle(err) { if (err instanceof CodegraphError) { report(err); } }",
);
let value_refs: Vec<_> = s
.calls
.iter()
.filter(|c| c.dynamic_kind.as_deref() == Some("value-ref"))
.collect();
assert!(value_refs.iter().any(|c| c.name == "CodegraphError"));
assert!(value_refs.iter().all(|c| c.dynamic == Some(true)));
}

#[test]
fn extracts_value_ref_call_for_instanceof_as_expression_value() {
let s = parse_js("const isConfig = (err) => err instanceof ConfigError;");
let value_refs: Vec<_> = s
.calls
.iter()
.filter(|c| c.dynamic_kind.as_deref() == Some("value-ref"))
.collect();
assert!(value_refs.iter().any(|c| c.name == "ConfigError"));
}

#[test]
fn no_value_ref_call_for_instanceof_member_expression_operand() {
let s = parse_js("const check = (a) => a instanceof ns.SomeClass;");
assert!(
s.calls
.iter()
.all(|c| !(c.dynamic_kind.as_deref() == Some("value-ref") && c.name == "SomeClass"))
);
}

#[test]
fn no_value_ref_call_for_instanceof_call_expression_operand() {
let s = parse_js("const check = (a) => a instanceof getClass();");
assert!(s.calls.iter().all(|c| c.dynamic_kind.as_deref() != Some("value-ref")));
}

#[test]
fn no_value_ref_call_for_instanceof_builtin_globals() {
let s = parse_js(
"function isBuiltin(x) { return x instanceof Error || x instanceof Array || x instanceof Map; }",
);
assert!(s.calls.iter().all(|c| c.dynamic_kind.as_deref() != Some("value-ref")));
}

#[test]
fn no_value_ref_call_for_in_operator() {
let s = parse_js("const has = (obj) => 'key' in obj;");
assert!(s.calls.iter().all(|c| c.dynamic_kind.as_deref() != Some("value-ref")));
}

#[test]
fn no_value_ref_call_for_other_binary_operators() {
let s = parse_js("const sum = (a, b) => a + b === Total;");
assert!(s.calls.iter().all(|c| c.dynamic_kind.as_deref() != Some("value-ref")));
}

#[test]
fn no_duplicate_call_for_call_expression_arg() {
let s = parse_js("router.use(checkPermissions(['admin']));");
Expand Down
42 changes: 28 additions & 14 deletions docs/architecture/decisions/002-dynamic-call-resolution.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,31 +79,45 @@ export type DynamicKind =
| 'unresolved-dynamic' // detected dynamic call we cannot resolve
| 'value-ref'; // bare identifier used as a value reference, not a call site —
// object-literal property value (dispatch tables, e.g.
// `{ resolve: someFn }`, #1771) or assignment to a Lua
// `{ resolve: someFn }`, #1771), assignment to a Lua
// global/builtin identifier (e.g. `require = tracedRequire`,
// #1776) — resolvable against function/method-kind targets
// only
// #1776), or the right operand of an `instanceof` check
// (e.g. `err instanceof CodegraphError`, #1784) —
// resolvable against function/method/class-kind targets;
// class was added for instanceof, but the filter is
// per-kind rather than per-site, so all three sites
// share the same allow-list
```

`dynamic?: boolean` is kept to avoid churning every `call.dynamic ? 1 : 0` site.

`value-ref` is Track A (resolvable) but deliberately **not** added to the flag-only
sink-edge set: when the identifier doesn't resolve to a function/method (e.g. a
sink-edge set: when the identifier doesn't resolve to a function/method/class (e.g. a
plain data reference like `{ name: SOME_CONSTANT }`), that's the common case, not
an undecidable dynamic call site — so it's silently dropped rather than flagged,
unlike `eval`/`computed-key`/`unresolved-dynamic`.

`value-ref` is deliberately syntax-position-agnostic: any bare identifier that
names a known function/method and appears somewhere other than a call site
qualifies, regardless of which language or grammar shape produced it.
Object-literal property values (#1771) and Lua assignment to a
global/builtin identifier (#1776, `require = tracedRequire` — a builtin name
isn't a locally-scoped variable that alias/points-to resolution could ever
observe, so this is the narrow, language-specific case where a plain
reference edge is the correct substitute for real alias tracking) are two
independent extraction sites feeding the same resolution/filtering logic
downstream; new languages/positions can add a third without touching
`build-edges.ts` / `incremental.ts` / `build_edges.rs` again.
names a known function/method/class and appears somewhere other than a call
site qualifies, regardless of which language or grammar shape produced it.
Object-literal property values (#1771), Lua assignment to a global/builtin
identifier (#1776, `require = tracedRequire` — a builtin name isn't a
locally-scoped variable that alias/points-to resolution could ever observe,
so this is the narrow, language-specific case where a plain reference edge
is the correct substitute for real alias tracking), and the right operand of
an `instanceof` check (#1784, `err instanceof CodegraphError` — `instanceof`
evaluates its right operand as a value, never calls it) are three independent
extraction sites feeding the same resolution/filtering logic downstream. The
`instanceof` site is the motivation for adding `class` to the allowed
target kinds, since its operand is always a class/constructor — but the
resolver-side filter is keyed on `dynamicKind`, not on which site produced
the call, so this is a per-kind allowed-target-kind set rather than a
per-site one: object-literal and Lua value-ref sites also gain class-kind
resolution as a side effect of this change, not because either idiom
commonly names a class. New languages/positions can add a fourth
without touching `build-edges.ts` / `incremental.ts` / `build_edges.rs`
again, beyond widening the allowed-target-kind set if the new site's operand
isn't a function/method/class.

### Sink edges reuse `kind='calls'`, not a new edge kind

Expand Down
11 changes: 7 additions & 4 deletions src/domain/graph/builder/incremental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -759,11 +759,14 @@ function buildCallEdges(
initialTargets,
);

// #1771: object-literal property-value references resolve against
// function/method-kind targets only — mirrors the same filter in
// resolveFallbackTargets (stages/build-edges.ts, full-build path).
// #1771/#1784: value-ref references resolve against function/method/
// class-kind targets only (class included for `instanceof ClassName`,
// #1784) — mirrors the same filter in resolveFallbackTargets
// (stages/build-edges.ts, full-build path).
if (call.dynamicKind === 'value-ref') {
targets = targets.filter((t) => t.kind === 'function' || t.kind === 'method');
targets = targets.filter(
(t) => t.kind === 'function' || t.kind === 'method' || t.kind === 'class',
);
}

edgesAdded += emitIncrementalCallEdges(
Expand Down
20 changes: 14 additions & 6 deletions src/domain/graph/builder/stages/build-edges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1372,11 +1372,17 @@ function resolveFallbackTargets(
if (qualified.length > 0) targets = qualified;
}

// #1771: object-literal property-value references (`{ resolve: someFn }`)
// resolve against function/method-kind targets only — a bare identifier
// there is as likely to be a plain data reference (`{ name: SOME_CONSTANT }`)
// as a function, so drop any non-callable match rather than fabricating a
// "calls" edge to a constant/class/etc. Applied once here, after every
// #1771/#1784: value-ref references (object-literal property values,
// Lua builtin reassignment, `instanceof ClassName`) resolve against
// function/method/class-kind targets only. A bare identifier in one of
// these positions is as likely to be a plain data reference
// (`{ name: SOME_CONSTANT }`) as a real function/class, so drop any
// other-kind match rather than fabricating a "calls" edge to a constant.
// `class` was added because `instanceof`'s right operand is always a
// class/constructor (#1784). The filter is keyed on `dynamicKind`, not on
// which site produced the call, so the #1771 object-literal and #1776 Lua
// sites also gain class-kind resolution as a side effect — not because
// either idiom commonly names a class. Applied once here, after every
// fallback tier above, so it covers whichever tier produced the match.
if (call.dynamicKind === 'value-ref') {
// `targets` is typed without `kind` when it flows straight through from
Expand All @@ -1386,7 +1392,9 @@ function resolveFallbackTargets(
// as its own step (not folded into the filter callback) so the type-gap
// workaround and the actual filtering decision stay visually distinct.
const typedTargets = targets as ReadonlyArray<{ id: number; file: string; kind?: string }>;
targets = typedTargets.filter((t) => t.kind === 'function' || t.kind === 'method');
targets = typedTargets.filter(
(t) => t.kind === 'function' || t.kind === 'method' || t.kind === 'class',
);
}

return { targets, importedFrom };
Expand Down
45 changes: 40 additions & 5 deletions src/extractors/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3185,6 +3185,37 @@ function collectObjectLiteralValueRefCall(pairNode: TreeSitterNode, calls: Call[
});
}

/**
* Collect a dynamic value-ref `Call` for the right-hand operand of an
* `instanceof` binary expression when it's a bare identifier — e.g.
* `err instanceof CodegraphError` (issue #1784). `instanceof` reads its
* right operand as a value (a prototype-chain check), never calls it, so
* this is the same "referenced as a value, not a call site" shape as the
* object-literal (#1771) and Lua builtin-reassignment (#1776) sites — reused
* rather than given its own DynamicKind (see ADR-002).
*
* Restricted to plain `identifier` right operands: `a instanceof B.C`
* (`member_expression`) and `a instanceof (foo())` (parenthesized/call
* expressions) are left unresolved rather than guessing — same
* "restrict to the simplest syntactic shape" precedent as #1771.
*
* Unlike the function/method-only value-ref sites, `instanceof`'s operand is
* always a class/constructor — the resolver-side kind filter
* (`resolveFallbackTargets` / `build_edges.rs`) accepts `class`-kind targets
* in addition to function/method for this reason.
*/
function collectInstanceofValueRefCall(binaryNode: TreeSitterNode, calls: Call[]): void {
if (binaryNode.childForFieldName('operator')?.text !== 'instanceof') return;
const rightNode = binaryNode.childForFieldName('right');
if (rightNode?.type !== 'identifier' || BUILTIN_GLOBALS.has(rightNode.text)) return;
calls.push({
name: rightNode.text,
line: nodeStartLine(rightNode),
dynamic: true,
dynamicKind: 'value-ref',
});
}

function extractReceiverName(objNode: TreeSitterNode | null): string | undefined {
if (!objNode) return undefined;
const t = objNode.type;
Expand Down Expand Up @@ -3745,11 +3776,11 @@ function collectThisCallAndBindings(
* `valueRefCalls` is REQUIRED (unlike `calls`) — both paths route
* object-literal value-ref extraction through this single field, since
* neither `walkJavaScriptNode` (walk path) nor the compiled query patterns
* (query path) visit `pair`/`shorthand_property_identifier` nodes on their
* own (#1771). Both callers pass their own `calls` array here; it's a
* separate field from the optional `calls` above purely so this collector
* isn't accidentally gated off by the walk path's "don't double-collect
* call_expression" omission.
* (query path) visit `pair`/`shorthand_property_identifier`/`binary_expression`
* nodes on their own (#1771, #1784). Both callers pass their own `calls`
* array here; it's a separate field from the optional `calls` above purely
* so this collector isn't accidentally gated off by the walk path's "don't
* double-collect call_expression" omission.
*/
interface CollectorWalkTargets {
definitions: Definition[];
Expand Down Expand Up @@ -3854,6 +3885,10 @@ function runCollectorWalk(rootNode: TreeSitterNode, targets: CollectorWalkTarget
});
}
break;
case 'binary_expression':
// #1784: `instanceof ClassName` checks, e.g. `err instanceof CodegraphError`.
collectInstanceofValueRefCall(node, targets.valueRefCalls);
break;
}
for (let i = 0; i < node.childCount; i++) {
walk(node.child(i)!, depth + 1, childInDynamicImport);
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ export type DynamicKind =
| 'reflection' // .call/.apply/.bind / Reflect.* / callable-ref — resolved when target is in codebase; sink edge emitted if unresolved
| 'eval' // eval() / new Function() — undecidable; always flagged
| 'unresolved-dynamic' // any other detected dynamic pattern; flagged
| '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
| '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 against function/method/class-kind targets; class was added for instanceof, but the filter is per-kind rather than per-site, so all three sites share the same allow-list; unresolved (e.g. plain data references) are dropped silently, NOT flagged

/** A function/method call detected by an extractor. */
export interface Call {
Expand Down
Loading
Loading