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

Function resolveMethodOnType

src/resolution/name-matcher.ts:482–569  ·  view source on GitHub ↗
(
  typeName: string,
  methodName: string,
  ref: UnresolvedRef,
  context: ResolutionContext,
  confidence: number,
  resolvedBy: ResolvedRef['resolvedBy'],
  /**
   * Optional FQN that identifies WHICH class declaration `typeName`
   * refers to in the caller's file. When multiple candidates share
   * the same qualifiedName (`FooConverter::convert` in both
   * `dao/converter/` and `service/converter/`), the FQN's
   * file-path-suffix picks the right one — the disambiguation
   * signal Java imports carry but the call site doesn't (#314).
   */
  preferredFqn?: string,
  /** Recursion guard for the supertype/conformance walk. */
  depth = 0,
)

Source from the content-addressed store, hash-verified

480// Exported for the precedence unit tests (#1079): they assert the
481// preferredFqn → same-file → matches[0] ordering directly.
482export function resolveMethodOnType(
483 typeName: string,
484 methodName: string,
485 ref: UnresolvedRef,
486 context: ResolutionContext,
487 confidence: number,
488 resolvedBy: ResolvedRef['resolvedBy'],
489 /**
490 * Optional FQN that identifies WHICH class declaration `typeName`
491 * refers to in the caller's file. When multiple candidates share
492 * the same qualifiedName (`FooConverter::convert` in both
493 * `dao/converter/` and `service/converter/`), the FQN's
494 * file-path-suffix picks the right one — the disambiguation
495 * signal Java imports carry but the call site doesn't (#314).
496 */
497 preferredFqn?: string,
498 /** Recursion guard for the supertype/conformance walk. */
499 depth = 0,
500): ResolvedRef | null {
501 // Look up methods by name and match by qualifiedName ending in
502 // `<typeName>::<methodName>`. This works whether the method is defined
503 // in-class (`class Foo { int bar() { ... } }`) or out-of-line in a separate
504 // file (`int Foo::bar() { ... }` in foo.cpp while class Foo is in foo.hpp).
505 // The previous same-file approach missed the latter — the typical C++ layout.
506 const methodCandidates = context.getNodesByName(methodName);
507 const want = `${typeName}::${methodName}`;
508 const matches: Node[] = [];
509 for (const m of methodCandidates) {
510 if (m.kind !== 'method') continue;
511 if (m.language !== ref.language) continue;
512 const qn = m.qualifiedName;
513 if (qn === want || qn.endsWith(`::${want}`)) {
514 matches.push(m);
515 }
516 }
517 if (matches.length === 0) {
518 // Conformance fallback: the method may be defined on a supertype `typeName`
519 // extends, or on a protocol / trait it conforms to (e.g. a Swift protocol-
520 // extension method, a C# default-interface or extension method, a Kotlin
521 // extension on a supertype). Walk supertypes transitively (depth-capped) via
522 // the resolved implements/extends edges — empty in the first resolution pass,
523 // populated in the conformance pass. Still VALIDATED (the method must exist on
524 // a supertype), so a wrong inference produces no edge.
525 if (depth < 4 && context.getSupertypes) {
526 for (const supertype of context.getSupertypes(typeName, ref.language)) {
527 const via = resolveMethodOnType(
528 supertype, methodName, ref, context, confidence, resolvedBy, preferredFqn, depth + 1,
529 );
530 if (via) return via;
531 }
532 }
533 return null;
534 }
535
536 if (matches.length > 1 && preferredFqn) {
537 const ext = ref.language === 'kotlin' ? '.kt' : '.java';
538 const fqnPath = preferredFqn.replace(/\./g, '/') + ext;
539 const chosen = matches.find((m) => {

Callers 5

resolution.test.tsFile · 0.90
matchCppCallChainFunction · 0.85
matchScopedCallChainFunction · 0.85
matchDottedCallChainFunction · 0.85
matchMethodCallFunction · 0.85

Calls 3

preferCallSiteFileFunction · 0.85
getSupertypesMethod · 0.80
getNodesByNameMethod · 0.65

Tested by

no test coverage detected