MCPcopy
hub / github.com/colbymchenry/codegraph / buildPolymorphicBoundaries

Method buildPolymorphicBoundaries

src/mcp/tools.ts:2183–2249  ·  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

2181 * TRUE graph-wide implementer count, NOT their frequency in the sample.
2182 */
2183 private buildPolymorphicBoundaries(cg: CodeGraph, candidates: Array<{ token: string; family: Node[] }>, named: Map<string, Node>): string {
2184 const CLASSY = new Set(['class', 'struct', 'interface', 'trait', 'protocol', 'abstract']);
2185 const MIN_IMPL = 8; // a supertype needs >= this many implementers to count as "polymorphic"
2186 const MIN_SUPPORT = 2; // >= this many sampled definers must share the supertype (ties it to the token)
2187 const SAMPLE = 40; // family members inspected per token
2188 const MAX_NOTES = 3;
2189 const rel = (p: string) => p.replace(/\\/g, '/');
2190 const containerOf = (m: Node): Node | null => {
2191 try { const ce = cg.getIncomingEdges(m.id).find((e) => e.kind === 'contains'); return ce ? cg.getNode(ce.source) : null; }
2192 catch { return null; }
2193 };
2194 const notes: string[] = [];
2195 const seenSuper = new Set<string>();
2196 for (const { token, family } of candidates) {
2197 if (notes.length >= MAX_NOTES) break;
2198 // supertype id → how many sampled definers share it + a few example definers
2199 const supers = new Map<string, { node: Node; count: number; targets: Node[] }>();
2200 for (const m of family.slice(0, SAMPLE)) {
2201 const container = containerOf(m);
2202 if (!container || !CLASSY.has(container.kind)) continue;
2203 let sups: Node[] = [];
2204 try {
2205 sups = cg.getOutgoingEdges(container.id)
2206 .filter((e) => e.kind === 'implements' || e.kind === 'extends')
2207 .map((e) => { try { return cg.getNode(e.target); } catch { return null; } })
2208 .filter((n): n is Node => !!n && CLASSY.has(n.kind) && (n.name?.length || 0) >= 3);
2209 } catch { /* no supertypes — free function or unresolved */ }
2210 for (const s of sups) {
2211 const e = supers.get(s.id) || { node: s, count: 0, targets: [] };
2212 e.count++;
2213 if (e.targets.length < 6) e.targets.push(m);
2214 supers.set(s.id, e);
2215 }
2216 }
2217 // Pick the supertype with the most TRUE implementers (graph-wide), among
2218 // those genuinely shared by the token's definers.
2219 let best: { node: Node; impl: number; targets: Node[] } | null = null;
2220 for (const { node, count, targets } of supers.values()) {
2221 if (count < MIN_SUPPORT) continue;
2222 let impl = 0;
2223 try { impl = cg.getIncomingEdges(node.id).filter((e) => e.kind === 'implements' || e.kind === 'extends').length; }
2224 catch { /* leave 0 — gated out below */ }
2225 if (impl < MIN_IMPL) continue;
2226 if (!best || impl > best.impl) best = { node, impl, targets };
2227 }
2228 if (!best || seenSuper.has(best.node.id)) continue;
2229 seenSuper.add(best.node.id);
2230 const namedNames = new Set([...named.values()].map((n) => n.name));
2231 const eg = best.targets.slice(0, 4).map((m) => {
2232 const cont = containerOf(m);
2233 const disp = cont ? `${cont.name}.${m.name}` : (m.qualifiedName || m.name);
2234 const mark = cont && namedNames.has(cont.name) ? ' ← you named this' : '';
2235 return `\`${disp}\` (${rel(m.filePath)}:${m.startLine})${mark}`;
2236 });
2237 const more = best.impl > eg.length ? ` +${best.impl - eg.length} more` : '';
2238 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}`);
2239 }
2240 if (notes.length === 0) return '';

Callers 1

Calls 7

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

Tested by

no test coverage detected