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

Function matchFunctionRef

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

Source from the content-addressed store, hash-verified

206 * edge is worse than none.
207 */
208export function matchFunctionRef(
209 ref: UnresolvedRef,
210 context: ResolutionContext
211): ResolvedRef | null {
212 // `this.<member>` refs are resolved ONLY by the class-scoped resolver in
213 // resolveOne (resolveThisMemberFnRef) — never by name matching here.
214 if (ref.referenceName.startsWith('this.')) return null;
215
216 // In JS/TS/Python a bare identifier can never be a method value (methods
217 // are only reachable through a receiver — `this.m` / `self.m` /
218 // `Cls.m`), so bare fn-refs match FUNCTIONS only. This also sidesteps the
219 // pre-existing TS quirk of class fields extracting as method-kind nodes,
220 // which otherwise soaked up local names passed as arguments (excalidraw
221 // A/B finding; same pattern in vendored docopt.py). Python's `self.m`
222 // form keeps method targets via its own capture shape. C++ likewise: a
223 // bare identifier can only be a FREE function (member values need
224 // `&Cls::method`). PHP string callables name global FUNCTIONS (methods
225 // need the `[$obj, 'm']` array form, which carries its own shape). Other
226 // languages keep method targets: C# method groups, Swift/Dart
227 // implicit-self, Java/Kotlin method references.
228 const bareFnOnly =
229 ref.language === 'typescript' || ref.language === 'tsx' ||
230 ref.language === 'javascript' || ref.language === 'jsx' ||
231 ref.language === 'arkts' ||
232 ref.language === 'cpp' || ref.language === 'python' ||
233 ref.language === 'php';
234
235 // Qualified member-pointer (`&Widget::on_click` → "Widget::on_click"):
236 // resolve the member ON THAT SCOPE — exempt from bareFnOnly (the `&Cls::m`
237 // shape is an explicit member reference). Unique-or-drop like everything else.
238 if (ref.referenceName.includes('::')) {
239 const memberName = ref.referenceName.slice(ref.referenceName.lastIndexOf('::') + 2);
240 const scoped = context
241 .getNodesByName(memberName)
242 .filter(
243 (n) =>
244 (n.kind === 'function' || n.kind === 'method') &&
245 sameLanguageFamily(n.language, ref.language) &&
246 n.id !== ref.fromNodeId &&
247 (n.qualifiedName === ref.referenceName ||
248 n.qualifiedName.endsWith(`::${ref.referenceName}`))
249 );
250 if (scoped.length === 0) return null;
251 const sameFileScoped = scoped.filter((n) => n.filePath === ref.filePath);
252 const pool = sameFileScoped.length > 0 ? sameFileScoped : scoped;
253 if (sameFileScoped.length === 0 && scoped.length > 1) return null;
254 const target = pool.reduce((a, b) => (a.startLine <= b.startLine ? a : b));
255 return {
256 original: ref,
257 targetNodeId: target.id,
258 confidence: 0.9,
259 resolvedBy: 'function-ref',
260 };
261 }
262
263 let candidates = context
264 .getNodesByName(ref.referenceName)
265 .filter(

Callers 2

resolveOneMethod · 0.90
matchReferenceFunction · 0.85

Calls 3

sameLanguageFamilyFunction · 0.85
getNodesByNameMethod · 0.65
getNodeByIdMethod · 0.65

Tested by

no test coverage detected