@optave/codegraph 3.12.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -35
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +2 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +1 -0
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +6 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +272 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/triage.js +1 -1
- package/dist/cli/commands/triage.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/shared/options.d.ts +2 -1
- package/dist/cli/shared/options.d.ts.map +1 -1
- package/dist/cli/shared/options.js +11 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/cli/types.d.ts +2 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/db/migrations.js +1 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/graph/builder/call-resolver.d.ts +12 -8
- package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
- package/dist/domain/graph/builder/call-resolver.js +93 -38
- package/dist/domain/graph/builder/call-resolver.js.map +1 -1
- package/dist/domain/graph/builder/cha.d.ts +9 -1
- package/dist/domain/graph/builder/cha.d.ts.map +1 -1
- package/dist/domain/graph/builder/cha.js +17 -2
- package/dist/domain/graph/builder/cha.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +8 -0
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +22 -3
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +1 -1
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +37 -2
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts +0 -2
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +88 -318
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +4 -0
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.js +341 -82
- package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/parser.d.ts +4 -5
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +46 -15
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +10 -2
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
- package/dist/domain/wasm-worker-pool.js +2 -0
- package/dist/domain/wasm-worker-pool.js.map +1 -1
- package/dist/domain/wasm-worker-protocol.d.ts +1 -0
- package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
- package/dist/extractors/cpp.d.ts.map +1 -1
- package/dist/extractors/cpp.js +42 -1
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/cuda.d.ts.map +1 -1
- package/dist/extractors/cuda.js +42 -1
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/helpers.d.ts +11 -0
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +40 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +8 -7
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.js +137 -6
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/features/structure-query.d.ts +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +6 -6
- package/dist/features/structure-query.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/config.d.ts +77 -4
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +395 -21
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +27 -0
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +59 -1
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/presentation/structure.d.ts +1 -1
- package/dist/presentation/structure.d.ts.map +1 -1
- package/dist/presentation/structure.js +2 -2
- package/dist/presentation/structure.js.map +1 -1
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +7 -8
- package/src/cli/commands/audit.ts +2 -1
- package/src/cli/commands/batch.ts +1 -0
- package/src/cli/commands/build.ts +6 -1
- package/src/cli/commands/config.ts +353 -0
- package/src/cli/commands/triage.ts +1 -1
- package/src/cli/index.ts +10 -0
- package/src/cli/shared/options.ts +11 -1
- package/src/cli/types.ts +2 -0
- package/src/db/migrations.ts +1 -1
- package/src/domain/graph/builder/call-resolver.ts +99 -41
- package/src/domain/graph/builder/cha.ts +18 -1
- package/src/domain/graph/builder/helpers.ts +24 -4
- package/src/domain/graph/builder/incremental.ts +1 -0
- package/src/domain/graph/builder/pipeline.ts +49 -2
- package/src/domain/graph/builder/stages/build-edges.ts +130 -399
- package/src/domain/graph/builder/stages/detect-changes.ts +1 -1
- package/src/domain/graph/builder/stages/finalize.ts +4 -0
- package/src/domain/graph/builder/stages/native-orchestrator.ts +396 -92
- package/src/domain/graph/builder/stages/resolve-imports.ts +1 -1
- package/src/domain/parser.ts +45 -14
- package/src/domain/wasm-worker-entry.ts +10 -2
- package/src/domain/wasm-worker-pool.ts +1 -0
- package/src/domain/wasm-worker-protocol.ts +1 -0
- package/src/extractors/cpp.ts +44 -1
- package/src/extractors/cuda.ts +44 -1
- package/src/extractors/helpers.ts +43 -0
- package/src/extractors/java.ts +8 -7
- package/src/extractors/javascript.ts +127 -6
- package/src/features/structure-query.ts +7 -7
- package/src/index.ts +5 -1
- package/src/infrastructure/config.ts +481 -22
- package/src/infrastructure/registry.ts +82 -1
- package/src/presentation/structure.ts +3 -3
- package/src/types.ts +41 -0
- package/grammars/tree-sitter-erlang.wasm +0 -0
|
@@ -16,10 +16,8 @@ import { buildPointsToMap, resolveViaPointsTo } from '../../resolver/points-to.j
|
|
|
16
16
|
import { enrichTypeMapWithTsc } from '../../resolver/ts-resolver.js';
|
|
17
17
|
import { findCaller, isModuleScopedLanguage, resolveCallTargets, resolveReceiverEdge, } from '../call-resolver.js';
|
|
18
18
|
import { buildChaContext, resolveChaTargets, resolveThisDispatch } from '../cha.js';
|
|
19
|
-
import { BUILTIN_RECEIVERS, batchInsertEdges, runChaPostPass } from '../helpers.js';
|
|
19
|
+
import { BUILTIN_RECEIVERS, batchInsertEdges, CHA_DISPATCH_PENALTY, CHA_TYPED_DISPATCH_CONFIDENCE, runChaPostPass, } from '../helpers.js';
|
|
20
20
|
import { getResolved, isBarrelFile, resolveBarrelExportCached } from './resolve-imports.js';
|
|
21
|
-
/** Phase 8.5: confidence penalty applied to CHA-dispatch edges. */
|
|
22
|
-
export const CHA_DISPATCH_PENALTY = 0.1;
|
|
23
21
|
// ── Node lookup setup ───────────────────────────────────────────────────
|
|
24
22
|
function makeGetNodeIdStmt(db) {
|
|
25
23
|
return {
|
|
@@ -337,17 +335,35 @@ function buildCallEdgesNative(ctx, getNodeIdStmt, allEdgeRows, allNodes, native)
|
|
|
337
335
|
nativeFiles.push({
|
|
338
336
|
file: relPath,
|
|
339
337
|
fileNodeId: fileNodeRow.id,
|
|
340
|
-
definitions: symbols.definitions.map((d) =>
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
338
|
+
definitions: symbols.definitions.map((d) => {
|
|
339
|
+
const params = d.children?.filter((c) => c.kind === 'parameter').map((c) => c.name);
|
|
340
|
+
return {
|
|
341
|
+
name: d.name,
|
|
342
|
+
kind: d.kind,
|
|
343
|
+
line: d.line,
|
|
344
|
+
endLine: d.endLine ?? null,
|
|
345
|
+
params: params?.length ? params : undefined,
|
|
346
|
+
};
|
|
347
|
+
}),
|
|
346
348
|
calls: symbols.calls,
|
|
347
349
|
importedNames,
|
|
348
350
|
classes: symbols.classes,
|
|
349
351
|
typeMap,
|
|
350
352
|
fnRefBindings: symbols.fnRefBindings?.length ? symbols.fnRefBindings : undefined,
|
|
353
|
+
paramBindings: symbols.paramBindings?.length ? symbols.paramBindings : undefined,
|
|
354
|
+
thisCallBindings: symbols.thisCallBindings?.length ? symbols.thisCallBindings : undefined,
|
|
355
|
+
arrayElemBindings: symbols.arrayElemBindings?.length ? symbols.arrayElemBindings : undefined,
|
|
356
|
+
spreadArgBindings: symbols.spreadArgBindings?.length ? symbols.spreadArgBindings : undefined,
|
|
357
|
+
forOfBindings: symbols.forOfBindings?.length ? symbols.forOfBindings : undefined,
|
|
358
|
+
arrayCallbackBindings: symbols.arrayCallbackBindings?.length
|
|
359
|
+
? symbols.arrayCallbackBindings
|
|
360
|
+
: undefined,
|
|
361
|
+
objectRestParamBindings: symbols.objectRestParamBindings?.length
|
|
362
|
+
? symbols.objectRestParamBindings
|
|
363
|
+
: undefined,
|
|
364
|
+
objectPropBindings: symbols.objectPropBindings?.length
|
|
365
|
+
? symbols.objectPropBindings
|
|
366
|
+
: undefined,
|
|
351
367
|
});
|
|
352
368
|
}
|
|
353
369
|
const nativeEdges = native.buildCallEdges(nativeFiles, allNodes, [
|
|
@@ -364,282 +380,6 @@ function buildCallEdgesNative(ctx, getNodeIdStmt, allEdgeRows, allNodes, native)
|
|
|
364
380
|
]);
|
|
365
381
|
}
|
|
366
382
|
}
|
|
367
|
-
/**
|
|
368
|
-
* Phase 8.3c pts post-pass for the native call-edge path.
|
|
369
|
-
*
|
|
370
|
-
* The native Rust engine builds call edges without knowledge of paramBindings,
|
|
371
|
-
* so `fn()` calls inside higher-order functions are not resolved to their
|
|
372
|
-
* concrete targets. This JS post-pass runs after the native edge pass and adds
|
|
373
|
-
* only the parameter-flow pts edges that the native engine missed.
|
|
374
|
-
*
|
|
375
|
-
* To avoid duplicating edges already emitted by the native engine, the current
|
|
376
|
-
* allEdgeRows snapshot is used to seed a seenByPair set before processing each
|
|
377
|
-
* file.
|
|
378
|
-
*/
|
|
379
|
-
function buildParamFlowPtsPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup) {
|
|
380
|
-
// Only process files that actually have paramBindings (avoid useless work).
|
|
381
|
-
const filesWithParams = [...ctx.fileSymbols].filter(([, symbols]) => symbols.paramBindings && symbols.paramBindings.length > 0);
|
|
382
|
-
if (filesWithParams.length === 0)
|
|
383
|
-
return;
|
|
384
|
-
// Seed seenByPair from the existing rows so we don't duplicate native edges.
|
|
385
|
-
// This is O(|allEdgeRows|) once per post-pass, which is acceptable.
|
|
386
|
-
const seenByPair = new Set();
|
|
387
|
-
for (const [srcId, tgtId] of allEdgeRows) {
|
|
388
|
-
seenByPair.add(`${srcId}|${tgtId}`);
|
|
389
|
-
}
|
|
390
|
-
const { barrelOnlyFiles, rootDir } = ctx;
|
|
391
|
-
const lookup = sharedLookup ?? makeContextLookup(ctx, getNodeIdStmt);
|
|
392
|
-
for (const [relPath, symbols] of filesWithParams) {
|
|
393
|
-
if (barrelOnlyFiles.has(relPath))
|
|
394
|
-
continue;
|
|
395
|
-
const fileNodeRow = getNodeIdStmt.get(relPath, 'file', relPath, 0);
|
|
396
|
-
if (!fileNodeRow)
|
|
397
|
-
continue;
|
|
398
|
-
const importedNames = buildImportedNamesMap(ctx, relPath, symbols, rootDir);
|
|
399
|
-
const typeMap = symbols.typeMap || new Map();
|
|
400
|
-
const ptsMap = buildPointsToMapForFile(symbols, importedNames);
|
|
401
|
-
if (!ptsMap)
|
|
402
|
-
continue;
|
|
403
|
-
for (const call of symbols.calls) {
|
|
404
|
-
if (call.receiver || call.dynamic)
|
|
405
|
-
continue; // pts post-pass handles only param-flow (non-dynamic)
|
|
406
|
-
const caller = findCaller(lookup, call, symbols.definitions, relPath, fileNodeRow);
|
|
407
|
-
const scopedKey = caller.callerName != null ? `${caller.callerName}::${call.name}` : null;
|
|
408
|
-
if (!scopedKey || !ptsMap.has(scopedKey))
|
|
409
|
-
continue;
|
|
410
|
-
// Only resolve calls that had no direct targets (same guard as buildFileCallEdges).
|
|
411
|
-
const { targets } = resolveCallTargets(lookup, call, relPath, importedNames, typeMap);
|
|
412
|
-
if (targets.length > 0)
|
|
413
|
-
continue;
|
|
414
|
-
for (const alias of resolveViaPointsTo(scopedKey, ptsMap)) {
|
|
415
|
-
const { targets: aliasTargets, importedFrom: aliasFrom } = resolveCallTargets(lookup, { name: alias }, relPath, importedNames, typeMap);
|
|
416
|
-
for (const t of aliasTargets) {
|
|
417
|
-
const edgeKey = `${caller.id}|${t.id}`;
|
|
418
|
-
if (t.id !== caller.id && !seenByPair.has(edgeKey)) {
|
|
419
|
-
const conf = computeConfidence(relPath, t.file, aliasFrom ?? null) - PROPAGATION_HOP_PENALTY;
|
|
420
|
-
if (conf > 0) {
|
|
421
|
-
seenByPair.add(edgeKey);
|
|
422
|
-
allEdgeRows.push([caller.id, t.id, 'calls', conf, 0, 'points-to']);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* bind/alias pts post-pass for the native call-edge path.
|
|
432
|
-
*
|
|
433
|
-
* The native Rust engine has no knowledge of JS-layer fnRefBindings (e.g.
|
|
434
|
-
* `const f = fn.bind(ctx)`), so calls to bind-created aliases are not resolved
|
|
435
|
-
* to their original function on the native path. This JS post-pass runs after
|
|
436
|
-
* the native edge pass and adds only the fnRefBindings-seeded pts edges that the
|
|
437
|
-
* native engine missed.
|
|
438
|
-
*
|
|
439
|
-
* Uses the same seenByPair dedup guard as buildParamFlowPtsPostPass to avoid
|
|
440
|
-
* duplicating edges already emitted by the native engine.
|
|
441
|
-
*/
|
|
442
|
-
function buildFnRefBindingsPtsPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup) {
|
|
443
|
-
// Only process files that actually have fnRefBindings.
|
|
444
|
-
const filesWithBindings = [...ctx.fileSymbols].filter(([, symbols]) => symbols.fnRefBindings && symbols.fnRefBindings.length > 0);
|
|
445
|
-
if (filesWithBindings.length === 0)
|
|
446
|
-
return;
|
|
447
|
-
// Seed seenByPair from the existing rows so we don't duplicate native edges.
|
|
448
|
-
const seenByPair = new Set();
|
|
449
|
-
for (const [srcId, tgtId] of allEdgeRows) {
|
|
450
|
-
seenByPair.add(`${srcId}|${tgtId}`);
|
|
451
|
-
}
|
|
452
|
-
const { barrelOnlyFiles, rootDir } = ctx;
|
|
453
|
-
const lookup = sharedLookup ?? makeContextLookup(ctx, getNodeIdStmt);
|
|
454
|
-
for (const [relPath, symbols] of filesWithBindings) {
|
|
455
|
-
if (barrelOnlyFiles.has(relPath))
|
|
456
|
-
continue;
|
|
457
|
-
const fileNodeRow = getNodeIdStmt.get(relPath, 'file', relPath, 0);
|
|
458
|
-
if (!fileNodeRow)
|
|
459
|
-
continue;
|
|
460
|
-
const importedNames = buildImportedNamesMap(ctx, relPath, symbols, rootDir);
|
|
461
|
-
const typeMap = symbols.typeMap || new Map();
|
|
462
|
-
const ptsMap = buildPointsToMapForFile(symbols, importedNames);
|
|
463
|
-
if (!ptsMap)
|
|
464
|
-
continue;
|
|
465
|
-
// Only resolve calls whose name is an lhs in fnRefBindings — the same
|
|
466
|
-
// narrowed guard used in buildFileCallEdges case (c).
|
|
467
|
-
const fnRefBindingLhs = new Set(symbols.fnRefBindings.map((b) => b.lhs));
|
|
468
|
-
for (const call of symbols.calls) {
|
|
469
|
-
if (call.receiver || call.dynamic)
|
|
470
|
-
continue; // bind aliases are flat-keyed, never dynamic
|
|
471
|
-
if (!fnRefBindingLhs.has(call.name))
|
|
472
|
-
continue;
|
|
473
|
-
if (!ptsMap.has(call.name))
|
|
474
|
-
continue;
|
|
475
|
-
const caller = findCaller(lookup, call, symbols.definitions, relPath, fileNodeRow);
|
|
476
|
-
// Only resolve calls that had no direct targets (same guard as buildFileCallEdges).
|
|
477
|
-
const { targets } = resolveCallTargets(lookup, call, relPath, importedNames, typeMap);
|
|
478
|
-
if (targets.length > 0)
|
|
479
|
-
continue;
|
|
480
|
-
for (const alias of resolveViaPointsTo(call.name, ptsMap)) {
|
|
481
|
-
const { targets: aliasTargets, importedFrom: aliasFrom } = resolveCallTargets(lookup, { name: alias }, relPath, importedNames, typeMap);
|
|
482
|
-
for (const t of aliasTargets) {
|
|
483
|
-
const edgeKey = `${caller.id}|${t.id}`;
|
|
484
|
-
if (t.id !== caller.id && !seenByPair.has(edgeKey)) {
|
|
485
|
-
const conf = computeConfidence(relPath, t.file, aliasFrom ?? null) - PROPAGATION_HOP_PENALTY;
|
|
486
|
-
if (conf > 0) {
|
|
487
|
-
seenByPair.add(edgeKey);
|
|
488
|
-
allEdgeRows.push([caller.id, t.id, 'calls', conf, 0, 'points-to']);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
/**
|
|
497
|
-
* this-rebinding post-pass for the native call-edge path.
|
|
498
|
-
*
|
|
499
|
-
* When `fn.call(namedCtx, ...)` or `fn.apply(namedCtx, ...)` is extracted by the
|
|
500
|
-
* WASM layer, `thisCallBindings` records `{ callee: 'fn', thisArg: 'namedCtx' }`.
|
|
501
|
-
* The native Rust engine has no knowledge of these bindings, so `this()` calls
|
|
502
|
-
* inside `fn` remain unresolved. This JS post-pass adds the missing edges by
|
|
503
|
-
* resolving `this()` calls inside each `fn` that has a thisCallBinding.
|
|
504
|
-
*/
|
|
505
|
-
function buildThisCallBindingsPtsPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup) {
|
|
506
|
-
const filesWithBindings = [...ctx.fileSymbols].filter(([, symbols]) => symbols.thisCallBindings && symbols.thisCallBindings.length > 0);
|
|
507
|
-
if (filesWithBindings.length === 0)
|
|
508
|
-
return;
|
|
509
|
-
const seenByPair = new Set();
|
|
510
|
-
for (const [srcId, tgtId] of allEdgeRows) {
|
|
511
|
-
seenByPair.add(`${srcId}|${tgtId}`);
|
|
512
|
-
}
|
|
513
|
-
const { barrelOnlyFiles, rootDir } = ctx;
|
|
514
|
-
const lookup = sharedLookup ?? makeContextLookup(ctx, getNodeIdStmt);
|
|
515
|
-
for (const [relPath, symbols] of filesWithBindings) {
|
|
516
|
-
if (barrelOnlyFiles.has(relPath))
|
|
517
|
-
continue;
|
|
518
|
-
const fileNodeRow = getNodeIdStmt.get(relPath, 'file', relPath, 0);
|
|
519
|
-
if (!fileNodeRow)
|
|
520
|
-
continue;
|
|
521
|
-
const importedNames = buildImportedNamesMap(ctx, relPath, symbols, rootDir);
|
|
522
|
-
const typeMap = symbols.typeMap || new Map();
|
|
523
|
-
const ptsMap = buildPointsToMapForFile(symbols, importedNames);
|
|
524
|
-
if (!ptsMap)
|
|
525
|
-
continue;
|
|
526
|
-
// Only process calls named 'this' (callee-not-receiver usage)
|
|
527
|
-
for (const call of symbols.calls) {
|
|
528
|
-
if (call.name !== 'this' || call.receiver)
|
|
529
|
-
continue;
|
|
530
|
-
const caller = findCaller(lookup, call, symbols.definitions, relPath, fileNodeRow);
|
|
531
|
-
if (caller.callerName == null)
|
|
532
|
-
continue;
|
|
533
|
-
const scopedKey = `${caller.callerName}::this`;
|
|
534
|
-
if (!ptsMap.has(scopedKey))
|
|
535
|
-
continue;
|
|
536
|
-
for (const alias of resolveViaPointsTo(scopedKey, ptsMap)) {
|
|
537
|
-
const { targets: aliasTargets, importedFrom: aliasFrom } = resolveCallTargets(lookup, { name: alias }, relPath, importedNames, typeMap);
|
|
538
|
-
for (const t of aliasTargets) {
|
|
539
|
-
const edgeKey = `${caller.id}|${t.id}`;
|
|
540
|
-
if (t.id !== caller.id && !seenByPair.has(edgeKey)) {
|
|
541
|
-
const conf = computeConfidence(relPath, t.file, aliasFrom ?? null) - PROPAGATION_HOP_PENALTY;
|
|
542
|
-
if (conf > 0) {
|
|
543
|
-
seenByPair.add(edgeKey);
|
|
544
|
-
allEdgeRows.push([caller.id, t.id, 'calls', conf, 0, 'points-to']);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Phase 8.3f post-pass for the native call-edge path.
|
|
554
|
-
*
|
|
555
|
-
* The native Rust engine builds call edges without knowledge of
|
|
556
|
-
* objectRestParamBindings, so `rest.method()` calls inside functions with
|
|
557
|
-
* object-destructuring rest parameters are not resolved via the typeMap chain.
|
|
558
|
-
* The Rust engine already resolves same-file and directly-imported callees
|
|
559
|
-
* (via steps 1–2 of its resolution logic), so this post-pass only adds edges
|
|
560
|
-
* that require the typeMap-chain path:
|
|
561
|
-
* typeMap[restName] → argName → typeMap[argName.method] → target
|
|
562
|
-
*
|
|
563
|
-
* Mirrors the seeding in buildCallEdgesJS (Phase 8.3f) to ensure both engine
|
|
564
|
-
* paths produce identical results for receiver-typed rest-param calls.
|
|
565
|
-
*/
|
|
566
|
-
function buildObjectRestParamPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup) {
|
|
567
|
-
const filesWithRestBindings = [...ctx.fileSymbols].filter(([, symbols]) => symbols.objectRestParamBindings &&
|
|
568
|
-
symbols.objectRestParamBindings.length > 0 &&
|
|
569
|
-
symbols.paramBindings &&
|
|
570
|
-
symbols.paramBindings.length > 0);
|
|
571
|
-
if (filesWithRestBindings.length === 0)
|
|
572
|
-
return;
|
|
573
|
-
const seenByPair = new Set();
|
|
574
|
-
for (const [srcId, tgtId] of allEdgeRows) {
|
|
575
|
-
seenByPair.add(`${srcId}|${tgtId}`);
|
|
576
|
-
}
|
|
577
|
-
const { barrelOnlyFiles, rootDir } = ctx;
|
|
578
|
-
const lookup = sharedLookup ?? makeContextLookup(ctx, getNodeIdStmt);
|
|
579
|
-
for (const [relPath, symbols] of filesWithRestBindings) {
|
|
580
|
-
if (barrelOnlyFiles.has(relPath))
|
|
581
|
-
continue;
|
|
582
|
-
const fileNodeRow = getNodeIdStmt.get(relPath, 'file', relPath, 0);
|
|
583
|
-
if (!fileNodeRow)
|
|
584
|
-
continue;
|
|
585
|
-
const importedNames = buildImportedNamesMap(ctx, relPath, symbols, rootDir);
|
|
586
|
-
const typeMap = new Map(symbols.typeMap instanceof Map ? symbols.typeMap : []);
|
|
587
|
-
// Seed typeMap[callee::restName] = { type: argName } for each matching pair.
|
|
588
|
-
// Mirrors the seeding in buildCallEdgesJS Phase 8.3f. Keys are scoped by
|
|
589
|
-
// callee so two functions with the same rest-param name (e.g. `...rest`) in
|
|
590
|
-
// the same file don't collide (#1358).
|
|
591
|
-
// When only one callee uses a given rest name, also seed the unscoped key
|
|
592
|
-
// as a null-callerName fallback so edges aren't silently dropped if
|
|
593
|
-
// findCaller can't identify the enclosing function (#1358).
|
|
594
|
-
const restNameCallees = new Map();
|
|
595
|
-
for (const orpb of symbols.objectRestParamBindings) {
|
|
596
|
-
if (!restNameCallees.has(orpb.restName))
|
|
597
|
-
restNameCallees.set(orpb.restName, new Set());
|
|
598
|
-
restNameCallees.get(orpb.restName).add(orpb.callee);
|
|
599
|
-
}
|
|
600
|
-
const restNames = new Set();
|
|
601
|
-
for (const orpb of symbols.objectRestParamBindings) {
|
|
602
|
-
for (const pb of symbols.paramBindings) {
|
|
603
|
-
if (pb.callee === orpb.callee && pb.argIndex === orpb.argIndex) {
|
|
604
|
-
const scopedKey = `${orpb.callee}::${orpb.restName}`;
|
|
605
|
-
if (!typeMap.has(scopedKey)) {
|
|
606
|
-
typeMap.set(scopedKey, { type: pb.argName, confidence: 0.65 });
|
|
607
|
-
if (restNameCallees.get(orpb.restName).size === 1 && !typeMap.has(orpb.restName)) {
|
|
608
|
-
typeMap.set(orpb.restName, { type: pb.argName, confidence: 0.65 });
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
// restNames tracks every rest-parameter name found, regardless of whether the
|
|
612
|
-
// scoped key was already in typeMap. This ensures the post-pass (below) processes
|
|
613
|
-
// all calls whose receiver matches a known rest binding — not just those whose
|
|
614
|
-
// typeMap entry was seeded in this iteration.
|
|
615
|
-
restNames.add(orpb.restName);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
if (restNames.size === 0)
|
|
620
|
-
continue;
|
|
621
|
-
for (const call of symbols.calls) {
|
|
622
|
-
// Only process calls whose receiver is a known rest-binding name.
|
|
623
|
-
if (!call.receiver || !restNames.has(call.receiver))
|
|
624
|
-
continue;
|
|
625
|
-
const caller = findCaller(lookup, call, symbols.definitions, relPath, fileNodeRow);
|
|
626
|
-
// Resolve with the enriched typeMap. callerName is passed so
|
|
627
|
-
// resolveByMethodOrGlobal can look up the scoped key callee::restName (#1358).
|
|
628
|
-
// seenByPair deduplicates edges the native engine already emitted.
|
|
629
|
-
const { targets, importedFrom } = resolveCallTargets(lookup, call, relPath, importedNames, typeMap, caller.callerName);
|
|
630
|
-
for (const t of targets) {
|
|
631
|
-
const edgeKey = `${caller.id}|${t.id}`;
|
|
632
|
-
if (t.id !== caller.id && !seenByPair.has(edgeKey)) {
|
|
633
|
-
const conf = computeConfidence(relPath, t.file, importedFrom ?? null) - PROPAGATION_HOP_PENALTY;
|
|
634
|
-
if (conf > 0) {
|
|
635
|
-
seenByPair.add(edgeKey);
|
|
636
|
-
allEdgeRows.push([caller.id, t.id, 'calls', conf, 0, 'points-to']);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
383
|
/**
|
|
644
384
|
* Object.defineProperty accessor post-pass for the native call-edge path.
|
|
645
385
|
*
|
|
@@ -715,11 +455,11 @@ function buildDefinePropertyPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLook
|
|
|
715
455
|
*
|
|
716
456
|
* The native Rust engine has no knowledge of the CHA context, so `this.method()`
|
|
717
457
|
* calls and interface method dispatches are not expanded to their concrete
|
|
718
|
-
* implementations. This JS post-pass runs after the native edges
|
|
719
|
-
*
|
|
458
|
+
* implementations. This JS post-pass runs after the native edges and adds only
|
|
459
|
+
* the CHA-resolved edges that the native engine missed.
|
|
720
460
|
*
|
|
721
|
-
*
|
|
722
|
-
*
|
|
461
|
+
* Seeds seenByPair from the current allEdgeRows snapshot to avoid duplicating
|
|
462
|
+
* edges the native engine already produced.
|
|
723
463
|
*/
|
|
724
464
|
function buildChaPostPass(ctx, getNodeIdStmt, allEdgeRows, chaCtx) {
|
|
725
465
|
// Fast-exit when the CHA context is empty (no class hierarchy in the project)
|
|
@@ -748,8 +488,9 @@ function buildChaPostPass(ctx, getNodeIdStmt, allEdgeRows, chaCtx) {
|
|
|
748
488
|
continue;
|
|
749
489
|
const caller = findCaller(lookup, call, symbols.definitions, relPath, fileNodeRow);
|
|
750
490
|
let chaTargets = [];
|
|
491
|
+
let isTypedReceiverDispatch = false;
|
|
751
492
|
if (call.receiver === 'this' || call.receiver === 'self' || call.receiver === 'super') {
|
|
752
|
-
chaTargets = resolveThisDispatch(call.name, caller.callerName, call.receiver, chaCtx, lookup);
|
|
493
|
+
chaTargets = resolveThisDispatch(call.name, caller.callerName, call.receiver, chaCtx, lookup, relPath);
|
|
753
494
|
}
|
|
754
495
|
else {
|
|
755
496
|
const typeEntry = typeMap.get(call.receiver);
|
|
@@ -760,15 +501,25 @@ function buildChaPostPass(ctx, getNodeIdStmt, allEdgeRows, chaCtx) {
|
|
|
760
501
|
: null;
|
|
761
502
|
if (typeName) {
|
|
762
503
|
chaTargets = resolveChaTargets(typeName, call.name, chaCtx, lookup);
|
|
504
|
+
isTypedReceiverDispatch = true;
|
|
763
505
|
}
|
|
764
506
|
}
|
|
765
507
|
for (const t of chaTargets) {
|
|
766
508
|
const edgeKey = `${caller.id}|${t.id}`;
|
|
767
509
|
if (t.id !== caller.id && !seenByPair.has(edgeKey)) {
|
|
768
|
-
|
|
510
|
+
// Typed-receiver (interface/CHA) dispatch: use CHA_TYPED_DISPATCH_CONFIDENCE
|
|
511
|
+
// — file proximity is not meaningful for virtual dispatch confidence.
|
|
512
|
+
// this/super dispatch keeps computeConfidence-based proximity scoring to
|
|
513
|
+
// match runPostNativeThisDispatch (native-orchestrator.ts).
|
|
514
|
+
const conf = isTypedReceiverDispatch
|
|
515
|
+
? CHA_TYPED_DISPATCH_CONFIDENCE
|
|
516
|
+
: computeConfidence(relPath, t.file, null) - CHA_DISPATCH_PENALTY;
|
|
769
517
|
if (conf > 0) {
|
|
770
518
|
seenByPair.add(edgeKey);
|
|
771
|
-
|
|
519
|
+
// Tag super-dispatch edges distinctly so runChaPostPass can exclude them
|
|
520
|
+
// from further CHA expansion (super calls are not virtual dispatch).
|
|
521
|
+
const technique = call.receiver === 'super' ? 'super-dispatch' : 'cha';
|
|
522
|
+
allEdgeRows.push([caller.id, t.id, 'calls', conf, 0, technique]);
|
|
772
523
|
}
|
|
773
524
|
}
|
|
774
525
|
}
|
|
@@ -1054,6 +805,15 @@ function buildFileCallEdges(relPath, symbols, fileNodeRow, importedNames, seenCa
|
|
|
1054
805
|
}
|
|
1055
806
|
}
|
|
1056
807
|
}
|
|
808
|
+
// Sort targets by confidence descending before emitting edges.
|
|
809
|
+
// For multi-target calls with duplicate (source_id, target_id) pairs the
|
|
810
|
+
// stored confidence depends on which duplicate is processed last — sorting
|
|
811
|
+
// here guarantees the highest-confidence target wins on dedup, matching the
|
|
812
|
+
// native engine's sort_targets_by_confidence call in build_edges.rs.
|
|
813
|
+
if (targets.length > 1) {
|
|
814
|
+
targets = [...targets].sort((a, b) => computeConfidence(relPath, b.file, importedFrom ?? null) -
|
|
815
|
+
computeConfidence(relPath, a.file, importedFrom ?? null));
|
|
816
|
+
}
|
|
1057
817
|
for (const t of targets) {
|
|
1058
818
|
const edgeKey = `${caller.id}|${t.id}`;
|
|
1059
819
|
if (t.id !== caller.id) {
|
|
@@ -1126,7 +886,11 @@ function buildFileCallEdges(relPath, symbols, fileNodeRow, importedNames, seenCa
|
|
|
1126
886
|
// and line are not relevant for alias resolution (we are looking up the
|
|
1127
887
|
// aliased function by name, not dispatching a method call).
|
|
1128
888
|
const { targets: aliasTargets, importedFrom: aliasFrom } = resolveCallTargets(lookup, { name: alias }, relPath, importedNames, typeMap);
|
|
1129
|
-
|
|
889
|
+
const sortedAliasTargets = aliasTargets.length > 1
|
|
890
|
+
? [...aliasTargets].sort((a, b) => computeConfidence(relPath, b.file, aliasFrom ?? null) -
|
|
891
|
+
computeConfidence(relPath, a.file, aliasFrom ?? null))
|
|
892
|
+
: aliasTargets;
|
|
893
|
+
for (const t of sortedAliasTargets) {
|
|
1130
894
|
const edgeKey = `${caller.id}|${t.id}`;
|
|
1131
895
|
if (t.id !== caller.id && !seenCallEdges.has(edgeKey) && !ptsEdgeRows.has(edgeKey)) {
|
|
1132
896
|
const conf = computeConfidence(relPath, t.file, aliasFrom ?? null) - PROPAGATION_HOP_PENALTY;
|
|
@@ -1152,7 +916,11 @@ function buildFileCallEdges(relPath, symbols, fileNodeRow, importedNames, seenCa
|
|
|
1152
916
|
if (ptsMap.has(receiverKey)) {
|
|
1153
917
|
for (const alias of resolveViaPointsTo(receiverKey, ptsMap)) {
|
|
1154
918
|
const { targets: aliasTargets, importedFrom: aliasFrom } = resolveCallTargets(lookup, { name: alias }, relPath, importedNames, typeMap);
|
|
1155
|
-
|
|
919
|
+
const sortedAliasTargets = aliasTargets.length > 1
|
|
920
|
+
? [...aliasTargets].sort((a, b) => computeConfidence(relPath, b.file, aliasFrom ?? null) -
|
|
921
|
+
computeConfidence(relPath, a.file, aliasFrom ?? null))
|
|
922
|
+
: aliasTargets;
|
|
923
|
+
for (const t of sortedAliasTargets) {
|
|
1156
924
|
const edgeKey = `${caller.id}|${t.id}`;
|
|
1157
925
|
if (t.id !== caller.id && !seenCallEdges.has(edgeKey) && !ptsEdgeRows.has(edgeKey)) {
|
|
1158
926
|
const conf = computeConfidence(relPath, t.file, aliasFrom ?? null) - PROPAGATION_HOP_PENALTY;
|
|
@@ -1170,7 +938,7 @@ function buildFileCallEdges(relPath, symbols, fileNodeRow, importedNames, seenCa
|
|
|
1170
938
|
call.receiver !== 'this' &&
|
|
1171
939
|
call.receiver !== 'self' &&
|
|
1172
940
|
call.receiver !== 'super') {
|
|
1173
|
-
const recv = resolveReceiverEdge(lookup, { name: call.name, receiver: call.receiver }, caller, relPath, typeMap, seenCallEdges);
|
|
941
|
+
const recv = resolveReceiverEdge(lookup, { name: call.name, receiver: call.receiver }, caller, relPath, typeMap, seenCallEdges, importedNames);
|
|
1174
942
|
if (recv) {
|
|
1175
943
|
allEdgeRows.push([recv.callerId, recv.receiverId, 'receiver', recv.confidence, 0, null]);
|
|
1176
944
|
}
|
|
@@ -1181,8 +949,9 @@ function buildFileCallEdges(relPath, symbols, fileNodeRow, importedNames, seenCa
|
|
|
1181
949
|
// For typed receiver calls: expand to all instantiated concrete implementations.
|
|
1182
950
|
if (chaCtx && call.receiver) {
|
|
1183
951
|
let chaTargets = [];
|
|
952
|
+
let isTypedReceiverDispatch = false;
|
|
1184
953
|
if (call.receiver === 'this' || call.receiver === 'self' || call.receiver === 'super') {
|
|
1185
|
-
chaTargets = resolveThisDispatch(call.name, caller.callerName, call.receiver, chaCtx, lookup);
|
|
954
|
+
chaTargets = resolveThisDispatch(call.name, caller.callerName, call.receiver, chaCtx, lookup, relPath);
|
|
1186
955
|
}
|
|
1187
956
|
else if (!BUILTIN_RECEIVERS.has(call.receiver)) {
|
|
1188
957
|
const typeEntry = typeMap.get(call.receiver);
|
|
@@ -1193,12 +962,19 @@ function buildFileCallEdges(relPath, symbols, fileNodeRow, importedNames, seenCa
|
|
|
1193
962
|
: null;
|
|
1194
963
|
if (typeName) {
|
|
1195
964
|
chaTargets = resolveChaTargets(typeName, call.name, chaCtx, lookup);
|
|
965
|
+
isTypedReceiverDispatch = true;
|
|
1196
966
|
}
|
|
1197
967
|
}
|
|
1198
968
|
for (const t of chaTargets) {
|
|
1199
969
|
const edgeKey = `${caller.id}|${t.id}`;
|
|
1200
970
|
if (t.id !== caller.id && !seenCallEdges.has(edgeKey) && !ptsEdgeRows.has(edgeKey)) {
|
|
1201
|
-
|
|
971
|
+
// Typed-receiver (interface/CHA) dispatch: use CHA_TYPED_DISPATCH_CONFIDENCE
|
|
972
|
+
// — file proximity is not meaningful for virtual dispatch confidence.
|
|
973
|
+
// this/super dispatch keeps computeConfidence-based proximity scoring to
|
|
974
|
+
// match runPostNativeThisDispatch (native-orchestrator.ts).
|
|
975
|
+
const conf = isTypedReceiverDispatch
|
|
976
|
+
? CHA_TYPED_DISPATCH_CONFIDENCE
|
|
977
|
+
: computeConfidence(relPath, t.file, null) - CHA_DISPATCH_PENALTY;
|
|
1202
978
|
if (conf > 0) {
|
|
1203
979
|
seenCallEdges.add(edgeKey);
|
|
1204
980
|
allEdgeRows.push([caller.id, t.id, 'calls', conf, 0, 'cha']);
|
|
@@ -1330,7 +1106,7 @@ function reconnectReverseDepEdges(ctx) {
|
|
|
1330
1106
|
* their import targets. Falls back to loading ALL nodes for full builds or
|
|
1331
1107
|
* larger incremental changes.
|
|
1332
1108
|
*/
|
|
1333
|
-
const NODE_KIND_FILTER_SQL = `kind IN ('function','method','class','interface','struct','type','module','enum','trait','record','constant')`;
|
|
1109
|
+
const NODE_KIND_FILTER_SQL = `kind IN ('function','method','class','interface','struct','type','module','enum','trait','record','constant','variable')`;
|
|
1334
1110
|
function loadNodes(ctx) {
|
|
1335
1111
|
const { db, fileSymbols, isFullBuild, batchResolved } = ctx;
|
|
1336
1112
|
const nodeKindFilter = NODE_KIND_FILTER_SQL;
|
|
@@ -1399,7 +1175,15 @@ export async function buildEdges(ctx) {
|
|
|
1399
1175
|
// Enrich typeMap for .ts/.tsx files using the TypeScript compiler API.
|
|
1400
1176
|
// Runs before call-edge construction so the accurate types are available
|
|
1401
1177
|
// for method-call resolution. Gated on config so users can opt out.
|
|
1402
|
-
|
|
1178
|
+
//
|
|
1179
|
+
// Skip for small incremental builds: TypeScript program creation requires
|
|
1180
|
+
// loading the entire tsconfig file list (~700ms startup on the codegraph
|
|
1181
|
+
// corpus), which dominates the 1-file rebuild time. Native engine bypasses
|
|
1182
|
+
// this entirely via the Rust orchestrator; WASM/JS engines need this gate
|
|
1183
|
+
// to match native's effective behaviour on tiny incremental changes.
|
|
1184
|
+
// Mirrors the smallFilesThreshold gates for nativeDb and native call-edges.
|
|
1185
|
+
const isSmallIncremental = !ctx.isFullBuild && ctx.fileSymbols.size <= ctx.config.build.smallFilesThreshold;
|
|
1186
|
+
if (ctx.config.build.typescriptResolver && !isSmallIncremental) {
|
|
1403
1187
|
await enrichTypeMapWithTsc(ctx.rootDir, ctx.fileSymbols);
|
|
1404
1188
|
}
|
|
1405
1189
|
const native = engineName === 'native' ? loadNative() : null;
|
|
@@ -1454,26 +1238,12 @@ export async function buildEdges(ctx) {
|
|
|
1454
1238
|
(ctx.isFullBuild || ctx.fileSymbols.size > ctx.config.build.smallFilesThreshold);
|
|
1455
1239
|
if (useNativeCallEdges) {
|
|
1456
1240
|
buildCallEdgesNative(ctx, getNodeIdStmt, allEdgeRows, allNodesBefore, native);
|
|
1457
|
-
//
|
|
1458
|
-
//
|
|
1241
|
+
// The native engine receives all pts bindings (paramBindings,
|
|
1242
|
+
// fnRefBindings, thisCallBindings, objectRestParamBindings, …) through
|
|
1243
|
+
// NativeFileEntry and runs the same points-to solver as the JS path, so
|
|
1244
|
+
// no pts post-passes are needed here. Only capabilities that remain
|
|
1245
|
+
// JS-only run as post-passes below.
|
|
1459
1246
|
const sharedLookup = makeContextLookup(ctx, getNodeIdStmt);
|
|
1460
|
-
// Phase 8.3c post-pass: augment native call edges with parameter-flow pts
|
|
1461
|
-
// edges. The native Rust engine has no knowledge of paramBindings, so any
|
|
1462
|
-
// `fn()` call inside a higher-order function would be missed. This JS pass
|
|
1463
|
-
// runs on top of the native edges and adds only the pts-resolved edges that
|
|
1464
|
-
// the native engine could not produce.
|
|
1465
|
-
buildParamFlowPtsPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup);
|
|
1466
|
-
// bind/alias post-pass: augment native call edges with fnRefBindings-seeded
|
|
1467
|
-
// pts edges. The native Rust engine has no knowledge of JS fnRefBindings
|
|
1468
|
-
// (e.g. `const f = fn.bind(ctx)`), so calls to bind-created aliases are
|
|
1469
|
-
// not resolved to their original function on the native path.
|
|
1470
|
-
buildFnRefBindingsPtsPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup);
|
|
1471
|
-
// this-rebinding post-pass: resolve `this()` calls inside functions that
|
|
1472
|
-
// were invoked via `.call(namedCtx, ...)` / `.apply(namedCtx, ...)`.
|
|
1473
|
-
buildThisCallBindingsPtsPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup);
|
|
1474
|
-
// Phase 8.3f post-pass: augment native call edges with object rest-param
|
|
1475
|
-
// receiver resolution — typeMap[restName] → argName → typeMap[argName.method].
|
|
1476
|
-
buildObjectRestParamPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup);
|
|
1477
1247
|
// Object.defineProperty accessor post-pass: resolve this-dispatch inside
|
|
1478
1248
|
// getter/setter functions registered via Object.defineProperty.
|
|
1479
1249
|
buildDefinePropertyPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup);
|