MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / buildPolymorphicBoundaries

Method buildPolymorphicBoundaries

src/mcp/tools.ts:2297–2363  ·  view source on GitHub ↗

* Interface/registry-dispatch announcement — #687 extended to GRAPH-visible * polymorphism (the body-scan can't see it: `nodeType.execute()` is textually * an ordinary call; the polymorphism lives in the `implements`/`extends` edges). * * A method the agent named that resolves to a large

(cg: CodeGraph, candidates: Array<{ token: string; family: Node[] }>, named: Map<string, Node>)

Source from the content-addressed store, hash-verified

2295 * TRUE graph-wide implementer count, NOT their frequency in the sample.
2296 */
2297 private buildPolymorphicBoundaries(cg: CodeGraph, candidates: Array<{ token: string; family: Node[] }>, named: Map<string, Node>): string {
2298 const CLASSY = new Set(['class', 'struct', 'interface', 'trait', 'protocol', 'abstract']);
2299 const MIN_IMPL = 8; // a supertype needs >= this many implementers to count as "polymorphic"
2300 const MIN_SUPPORT = 2; // >= this many sampled definers must share the supertype (ties it to the token)
2301 const SAMPLE = 40; // family members inspected per token
2302 const MAX_NOTES = 3;
2303 const rel = (p: string) => p.replace(/\\/g, '/');
2304 const containerOf = (m: Node): Node | null => {
2305 try { const ce = cg.getIncomingEdges(m.id).find((e) => e.kind === 'contains'); return ce ? cg.getNode(ce.source) : null; }
2306 catch { return null; }
2307 };
2308 const notes: string[] = [];
2309 const seenSuper = new Set<string>();
2310 for (const { token, family } of candidates) {
2311 if (notes.length >= MAX_NOTES) break;
2312 // supertype id → how many sampled definers share it + a few example definers
2313 const supers = new Map<string, { node: Node; count: number; targets: Node[] }>();
2314 for (const m of family.slice(0, SAMPLE)) {
2315 const container = containerOf(m);
2316 if (!container || !CLASSY.has(container.kind)) continue;
2317 let sups: Node[] = [];
2318 try {
2319 sups = cg.getOutgoingEdges(container.id)
2320 .filter((e) => e.kind === 'implements' || e.kind === 'extends')
2321 .map((e) => { try { return cg.getNode(e.target); } catch { return null; } })
2322 .filter((n): n is Node => !!n && CLASSY.has(n.kind) && (n.name?.length || 0) >= 3);
2323 } catch { /* no supertypes — free function or unresolved */ }
2324 for (const s of sups) {
2325 const e = supers.get(s.id) || { node: s, count: 0, targets: [] };
2326 e.count++;
2327 if (e.targets.length < 6) e.targets.push(m);
2328 supers.set(s.id, e);
2329 }
2330 }
2331 // Pick the supertype with the most TRUE implementers (graph-wide), among
2332 // those genuinely shared by the token's definers.
2333 let best: { node: Node; impl: number; targets: Node[] } | null = null;
2334 for (const { node, count, targets } of supers.values()) {
2335 if (count < MIN_SUPPORT) continue;
2336 let impl = 0;
2337 try { impl = cg.getIncomingEdges(node.id).filter((e) => e.kind === 'implements' || e.kind === 'extends').length; }
2338 catch { /* leave 0 — gated out below */ }
2339 if (impl < MIN_IMPL) continue;
2340 if (!best || impl > best.impl) best = { node, impl, targets };
2341 }
2342 if (!best || seenSuper.has(best.node.id)) continue;
2343 seenSuper.add(best.node.id);
2344 const namedNames = new Set([...named.values()].map((n) => n.name));
2345 const eg = best.targets.slice(0, 4).map((m) => {
2346 const cont = containerOf(m);
2347 const disp = cont ? `${cont.name}.${m.name}` : (m.qualifiedName || m.name);
2348 const mark = cont && namedNames.has(cont.name) ? ' ← you named this' : '';
2349 return `\`${disp}\` (${rel(m.filePath)}:${m.startLine})${mark}`;
2350 });
2351 const more = best.impl > eg.length ? ` +${best.impl - eg.length} more` : '';
2352 notes.push(`- \`${token}\` → runtime dispatch to **${best.impl}** types implementing \`${best.node.name}\` — the static path ends here, the target is chosen at runtime. e.g. ${eg.join(', ')}${more}`);
2353 }
2354 if (notes.length === 0) return '';

Callers 1

Calls 7

hasMethod · 0.80
getNodeMethod · 0.80
getMethod · 0.65
getOutgoingEdgesMethod · 0.45
setMethod · 0.45
getIncomingEdgesMethod · 0.45
joinMethod · 0.45

Tested by

no test coverage detected