Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion src/core.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -58,6 +58,7 @@ export async function analyze(opts: AnalysisOptions): Promise<AnalysisResult> {
for (const prog of programs) {
const ctx = {
project: prog.project,
callExprIndex: indexCallExpressions(prog.project),
symbol_table,
root: opts.input,
log,
Expand Down
4 changes: 2 additions & 2 deletions src/semantic_analysis/callGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function buildCallGraph(
root: string,
log: Logger,
phantoms: boolean,
callExprIndex: ReadonlyMap<string, Node>,
only?: Set<string>,
): CallGraphResult {
// 1. The node universe: every callable signature in the WHOLE symbol table. Edges may only target
Expand All @@ -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<string, ClassMeta>();
Expand Down
5 changes: 2 additions & 3 deletions src/semantic_analysis/defuseLinker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, Map<string, string>>;
Expand All @@ -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<string>();
Expand All @@ -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();
Expand Down
14 changes: 12 additions & 2 deletions src/semantic_analysis/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
* 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";

/** Everything the builder needs to produce a call graph over the analyzed project. */
export interface CallGraphContext {
project: Project;
callExprIndex: ReadonlyMap<string, Node>;
symbol_table: Record<string, TSModule>;
root: string;
log: Logger;
Expand All @@ -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,
),
};

/**
Expand Down