diff --git a/src/core.ts b/src/core.ts index 48aec15..76441a3 100644 --- a/src/core.ts +++ b/src/core.ts @@ -1,6 +1,6 @@ import * as path from "node:path"; import { buildProgramGraphs, startExtraction } from "./dataflow"; -import { type LinkerResolutions, mergeCallGraphs, runDefuseLinker, tscProvider } from "./semantic_analysis"; +import { type LinkerResolutions, indexCallExpressions, mergeCallGraphs, runDefuseLinker, tscProvider } from "./semantic_analysis"; import { loadCache, saveCache } from "./utils"; import { materialize } from "./build"; import { inventoryArtifacts } from "./artifacts"; @@ -58,6 +58,7 @@ export async function analyze(opts: AnalysisOptions): Promise { for (const prog of programs) { const ctx = { project: prog.project, + callExprIndex: indexCallExpressions(prog.project), symbol_table, root: opts.input, log, diff --git a/src/semantic_analysis/callGraph.ts b/src/semantic_analysis/callGraph.ts index a60835a..9ad2ae0 100644 --- a/src/semantic_analysis/callGraph.ts +++ b/src/semantic_analysis/callGraph.ts @@ -69,6 +69,7 @@ export function buildCallGraph( root: string, log: Logger, phantoms: boolean, + callExprIndex: ReadonlyMap, only?: Set, ): CallGraphResult { // 1. The node universe: every callable signature in the WHOLE symbol table. Edges may only target @@ -85,8 +86,7 @@ export function buildCallGraph( forEachCallable(mod, (c) => callables.push(c)); } - // 2. Index call/new expression AST nodes by full span so we can match recorded call sites. - const callExprIndex = indexCallExpressions(project); + // 2. The orchestrator shares this full-span AST index with the def-use linker for this program. // 3. Class metadata + subtype index (for RTA expansion), built from the symbol table. const classMeta = new Map(); diff --git a/src/semantic_analysis/defuseLinker.ts b/src/semantic_analysis/defuseLinker.ts index 67fdc61..e50399f 100644 --- a/src/semantic_analysis/defuseLinker.ts +++ b/src/semantic_analysis/defuseLinker.ts @@ -31,7 +31,7 @@ import { aliasedSymbolOf, computeSignatureForDecl, externalHomeOf, fileKeyOf, is import { callBodyKeys } from "../schema/l1Body"; import type { CallGraphContext } from "./provider"; import type { CallGraphResult } from "./callGraph"; -import { inInstancePropInit, indexCallExpressions } from "./callGraph"; +import { inInstancePropInit } from "./callGraph"; /** Per-call-site resolutions for the sanctioned `callee: null→id` refinement: callerSig → bodyKey → calleeSig. */ export type LinkerResolutions = Map>; @@ -46,7 +46,7 @@ const ALIAS_CHASE_LIMIT = 8; // hops through `const f = g` chains const CHA_FAN_LIMIT = 16; // max name-matched targets per T5 site export function runDefuseLinker(ctx: CallGraphContext): LinkerOutput { - const { project, symbol_table, root, log } = ctx; + const { project, symbol_table, root, log, callExprIndex } = ctx; // The signature universe (full table — cross-program targets resolve) + the name→sigs CHA index. const allSignatures = new Set(); @@ -69,7 +69,6 @@ export function runDefuseLinker(ctx: CallGraphContext): LinkerOutput { } callables.sort((a, b) => a.signature.localeCompare(b.signature)); - const callExprIndex = indexCallExpressions(project); /** The callee expression of a call/new/tagged-template node. */ const calleeExprOf = (node: Node): Node => Node.isTaggedTemplateExpression(node) ? node.getTag() : (node as unknown as { getExpression: () => Node }).getExpression(); diff --git a/src/semantic_analysis/provider.ts b/src/semantic_analysis/provider.ts index ec76134..e57c811 100644 --- a/src/semantic_analysis/provider.ts +++ b/src/semantic_analysis/provider.ts @@ -5,7 +5,7 @@ * linker's edges overlay the tsc base through it (an edge found by both carries * `["defuse", "tsc"]` after the wire sort). */ -import type { Project } from "ts-morph"; +import type { Node, Project } from "ts-morph"; import type { TSExternalSymbol, TSModule } from "../schema"; import type { Logger } from "../utils"; import { buildCallGraph, type CallGraphResult } from "./callGraph"; @@ -13,6 +13,7 @@ import { buildCallGraph, type CallGraphResult } from "./callGraph"; /** Everything the builder needs to produce a call graph over the analyzed project. */ export interface CallGraphContext { project: Project; + callExprIndex: ReadonlyMap; symbol_table: Record; root: string; log: Logger; @@ -31,7 +32,16 @@ export interface CallGraphProvider { /** The one backend — the ts-morph checker resolver (+ RTA + phantoms). */ export const tscProvider: CallGraphProvider = { name: "tsc", - build: (ctx) => buildCallGraph(ctx.project, ctx.symbol_table, ctx.root, ctx.log, ctx.phantoms, ctx.only), + build: (ctx) => + buildCallGraph( + ctx.project, + ctx.symbol_table, + ctx.root, + ctx.log, + ctx.phantoms, + ctx.callExprIndex, + ctx.only, + ), }; /**