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

Function matchDottedCallChain

src/resolution/name-matcher.ts:946–1033  ·  view source on GitHub ↗
(
  ref: UnresolvedRef,
  context: ResolutionContext,
)

Source from the content-addressed store, hash-verified

944 * (Java, Kotlin, C#, Swift) — same receiver shape, same `Class::method` qualified names.
945 */
946export function matchDottedCallChain(
947 ref: UnresolvedRef,
948 context: ResolutionContext,
949): ResolvedRef | null {
950 const m = ref.referenceName.match(/^(.+)\(\)\.(\w+)$/);
951 if (!m || !m[1] || !m[2]) return null;
952 const inner = m[1]; // `Foo.getInstance`
953 const method = m[2]; // `bar`
954 const lastDot = inner.lastIndexOf('.');
955
956 if (lastDot <= 0) {
957 // Go: bare package-level factory FUNCTION `New().method()` — the receiver's
958 // type is what `New` returns; resolve the method on that.
959 if (ref.language === 'go') {
960 const ret = lookupCalleeReturnType(inner, ref, context);
961 if (ret) {
962 return resolveMethodOnType(ret, method, ref, context, 0.85, 'instance-method', importedFqnOf(ret, ref, context));
963 }
964 // `inner` isn't a function with a captured return type — typically a
965 // package-level VARIABLE holding a function value (e.g. gin's `engine()`),
966 // whose type we can't recover. Fall back to bare-name resolution of the
967 // method so we don't DROP an edge the un-re-encoded bare path would have
968 // found. (When `inner` IS a real factory function but the method doesn't
969 // exist on its return type, `ret` is truthy and we returned no edge above —
970 // the absent-method safety guarantee is preserved.)
971 //
972 // CRITICAL: resolve the TARGET via a synthetic bare-name ref, but return the
973 // match tied to the ORIGINAL `ref` (referenceName `inner().method`). The
974 // batched resolver (resolveAndPersistBatched) reads unresolved rows from
975 // offset 0 every pass and relies on the post-batch cleanup (row-id delete
976 // for DB-loaded refs, referenceName-keyed delete otherwise, #1269) to
977 // clear each resolved row so the batch empties. If we propagated the
978 // synthetic ref's bare `method` as `.original`, a key-based delete
979 // would never match the stored `inner().method` row, the batch would
980 // never drain, and the loop would re-resolve + re-insert forever (a runaway
981 // that grew gin's graph to 5M edges / 1.4 GB before this fix).
982 const bareRef = { ...ref, referenceName: method };
983 const bareMatch = matchByExactName(bareRef, context) ?? matchFuzzy(bareRef, context);
984 return bareMatch ? { ...bareMatch, original: ref } : null;
985 }
986 // Constructor receiver `Foo(args).method()` (encoded `Foo().method`): a bare,
987 // capitalized inner is a class construction, so the receiver's type is the
988 // class itself — resolve the method on it. Only in languages where an
989 // unprefixed capitalized call constructs the class (Kotlin, Swift); in Java/C#
990 // a bare `Foo()` is a method call (constructors need `new`), so we must not
991 // assume construction. A lowercase bare inner is a top-level `factory().method()`
992 // whose type we can't recover — bail.
993 if (!CONSTRUCTS_VIA_BARE_CALL.has(ref.language) || !/^[A-Z]/.test(inner)) return null;
994 return resolveMethodOnType(inner, method, ref, context, 0.85, 'instance-method', importedFqnOf(inner, ref, context));
995 }
996
997 // Factory/fluent receiver `Receiver.factory(args).method()`: the receiver's
998 // type is what `Receiver.factory` returns (its declared return type).
999 const factoryClass = inner.slice(0, lastDot).split('.').pop(); // simple class name
1000 const factoryMethod = inner.slice(lastDot + 1);
1001 if (!factoryClass || !factoryMethod) return null;
1002 const ret = lookupCalleeReturnType(`${factoryClass}::${factoryMethod}`, ref, context);
1003 if (!ret) {

Callers 2

matchReferenceFunction · 0.85

Calls 6

lookupCalleeReturnTypeFunction · 0.85
resolveMethodOnTypeFunction · 0.85
importedFqnOfFunction · 0.85
matchByExactNameFunction · 0.85
matchFuzzyFunction · 0.85
hasMethod · 0.80

Tested by

no test coverage detected