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

Method findSymbolMatches

src/mcp/tools.ts:4447–4492  ·  view source on GitHub ↗

* Find ALL definitions matching a name, ranked, so codegraph_node can return * every overload instead of guessing one (the wrong guess → a Read). Keepers * rank before generated stubs (.pb.go etc.); stable within a group preserves * FTS order. Returns [] when nothing matches; a qualified lo

(cg: CodeGraph, symbol: string)

Source from the content-addressed store, hash-verified

4445 * bare name with no exact match falls back to the single top fuzzy result.
4446 */
4447 private findSymbolMatches(cg: CodeGraph, symbol: string): Node[] {
4448 const isQualified = /[.\/]|::/.test(symbol);
4449
4450 // For a bare name, enumerate EVERY exact-name definition via the direct index
4451 // (not FTS, which caps + ranks): tokio's `poll` has 50+ defs and the one the
4452 // caller wants (`Harness::poll` at harness.rs:153) ranks below any search cut,
4453 // so it could be neither rendered nor pinned by the file/line disambiguator —
4454 // and the agent Read it. With the full set, the multi-overload render + the
4455 // file/line filter can both reach it.
4456 if (!isQualified) {
4457 const exact = cg.getNodesByName(symbol);
4458 if (exact.length > 0) {
4459 return [...exact].sort((a, b) => (isGeneratedFile(a.filePath) ? 1 : 0) - (isGeneratedFile(b.filePath) ? 1 : 0));
4460 }
4461 // No exact match — use the single top fuzzy result (e.g. a file basename).
4462 const fuzzy = cg.searchNodes(symbol, { limit: 10 });
4463 return fuzzy[0] ? [fuzzy[0].node] : [];
4464 }
4465
4466 // Qualified lookup (`Session.request`, `stage_apply::run`): FTS + matchesSymbol.
4467 const limit = 50;
4468 let results = cg.searchNodes(symbol, { limit });
4469
4470 // FTS strips colons, so `stage_apply::run` searches the literal
4471 // `stage_applyrun` and finds nothing. Re-search by the bare last part and
4472 // let `matchesSymbol` filter by qualifier.
4473 if (isQualified && results.length === 0) {
4474 const tail = lastQualifierPart(symbol);
4475 if (tail && tail !== symbol) results = cg.searchNodes(tail, { limit });
4476 }
4477
4478 if (results.length === 0) return [];
4479
4480 const exactMatches = results.filter((r) => this.matchesSymbol(r.node, symbol));
4481 if (exactMatches.length === 0) {
4482 // No exact match — a qualified lookup must not fall back to a fuzzy file
4483 // hit (#173); a bare name may use the single top fuzzy result.
4484 return isQualified ? [] : results[0] ? [results[0].node] : [];
4485 }
4486
4487 // Down-rank generated files (.pb.go, .pulsar.go, _grpc.pb.go, …) so a flow
4488 // query prefers the keeper implementation over the protobuf-generated stub.
4489 return [...exactMatches]
4490 .sort((a, b) => (isGeneratedFile(a.node.filePath) ? 1 : 0) - (isGeneratedFile(b.node.filePath) ? 1 : 0))
4491 .map((r) => r.node);
4492 }
4493
4494 /**
4495 * Find ALL symbols matching a name. Used by callers/callees/impact to aggregate

Callers 1

handleNodeMethod · 0.95

Calls 5

matchesSymbolMethod · 0.95
isGeneratedFileFunction · 0.90
lastQualifierPartFunction · 0.85
getNodesByNameMethod · 0.65
searchNodesMethod · 0.45

Tested by

no test coverage detected