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

Function inferJavaFieldReceiverType

src/resolution/name-matcher.ts:973–1020  ·  view source on GitHub ↗

* Java/Kotlin: infer a receiver's declared type by walking field declarations * in the class enclosing the call site. The field's `signature` is already in * the form " " (set by tree-sitter.ts extractField), so we * pull the type from there. Handles Spring `@Resource UserBO

(
  receiverName: string,
  ref: UnresolvedRef,
  context: ResolutionContext,
)

Source from the content-addressed store, hash-verified

971 * null when no matching field is in the enclosing class.
972 */
973function inferJavaFieldReceiverType(
974 receiverName: string,
975 ref: UnresolvedRef,
976 context: ResolutionContext,
977): string | null {
978 const inFile = context.getNodesInFile(ref.filePath);
979 if (inFile.length === 0) return null;
980
981 // Find the class enclosing the call line (tightest match by latest start).
982 let enclosing: Node | null = null;
983 for (const n of inFile) {
984 if (n.kind !== 'class' && n.kind !== 'interface') continue;
985 if (n.language !== ref.language) continue;
986 const end = n.endLine ?? n.startLine;
987 if (n.startLine <= ref.line && end >= ref.line) {
988 if (!enclosing || n.startLine >= enclosing.startLine) enclosing = n;
989 }
990 }
991 if (!enclosing) return null;
992
993 const enclosingEnd = enclosing.endLine ?? enclosing.startLine;
994 const field = inFile.find(
995 (n) =>
996 n.kind === 'field' &&
997 n.name === receiverName &&
998 n.language === ref.language &&
999 n.startLine >= enclosing.startLine &&
1000 (n.endLine ?? n.startLine) <= enclosingEnd,
1001 );
1002 if (!field || !field.signature) return null;
1003
1004 // Signature shape: "<TypeName> <fieldName>" (extractField). Pull the type,
1005 // strip generics + dotted package, drop array/varargs markers.
1006 const beforeName = field.signature.slice(
1007 0,
1008 field.signature.lastIndexOf(field.name),
1009 );
1010 const typeRaw = beforeName.trim();
1011 if (!typeRaw) return null;
1012
1013 const typeNoGenerics = typeRaw.replace(/<[^>]*>/g, '').trim();
1014 const typeNoArray = typeNoGenerics.replace(/\[\s*\]/g, '').replace(/\.\.\.$/, '').trim();
1015 const parts = typeNoArray.split(/[.\s]+/).filter(Boolean);
1016 const lastPart = parts[parts.length - 1];
1017 if (!lastPart) return null;
1018 if (!/^[A-Z]/.test(lastPart)) return null; // primitives / lowercase → skip
1019 return lastPart;
1020}
1021
1022// ── Local-variable receiver-type inference (#1108) ──────────────────────────
1023//

Callers 1

matchMethodCallFunction · 0.85

Calls 1

getNodesInFileMethod · 0.65

Tested by

no test coverage detected