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

Function goGrpcStubImplEdges

src/resolution/callback-synthesizer.ts:762–844  ·  view source on GitHub ↗

* Go gRPC stub → impl bridge. The protoc-gen-go-grpc codegen emits an * `UnimplementedXxxServer` struct in `*_grpc.pb.go` carrying one method * per service RPC; the real handler is a hand-written struct in another * file (`x/bank/keeper/msg_server.go::msgServer.Send` in cosmos-sdk). * Go's struc

(queries: QueryBuilder)

Source from the content-addressed store, hash-verified

760 * stub's source line is the wiring site shown in the trace trail.
761 */
762function goGrpcStubImplEdges(queries: QueryBuilder): Edge[] {
763 const edges: Edge[] = [];
764 const seen = new Set<string>();
765
766 const STUB_RE = /^Unimplemented.*Server$/;
767 // gRPC internal-helper methods that appear on every Unimplemented*Server;
768 // not part of the service contract, so exclude when computing the RPC-method
769 // signature used to match impls.
770 const isInternalMarker = (n: string) => n.startsWith('mustEmbed') || n === 'testEmbeddedByValue';
771
772 // Methods directly contained by each Go struct, name-only. Built once.
773 const methodNamesByStruct = new Map<string, Set<string>>();
774 const methodNodesByStruct = new Map<string, Node[]>();
775 const goStructs: Node[] = [];
776 for (const s of queries.getNodesByKind('struct')) {
777 if (s.language !== 'go') continue;
778 goStructs.push(s);
779 const ms = queries
780 .getOutgoingEdges(s.id, ['contains'])
781 .map((e) => queries.getNodeById(e.target))
782 .filter((n): n is Node => !!n && n.kind === 'method');
783 methodNodesByStruct.set(s.id, ms);
784 methodNamesByStruct.set(s.id, new Set(ms.map((m) => m.name)));
785 }
786
787 for (const stub of goStructs) {
788 if (!STUB_RE.test(stub.name)) continue;
789 // The stub MUST live in a generated file — that's what tells us this is
790 // a protoc-emitted scaffold rather than someone naming a struct
791 // `UnimplementedXxxServer` by hand. Without this gate we'd also bridge
792 // such hand-written structs and create misleading edges.
793 if (!isGeneratedFile(stub.filePath)) continue;
794
795 const stubMethods = (methodNodesByStruct.get(stub.id) ?? []).filter(
796 (m) => !isInternalMarker(m.name),
797 );
798 if (stubMethods.length === 0) continue;
799 const stubMethodNames = stubMethods.map((m) => m.name);
800
801 for (const cand of goStructs) {
802 if (cand.id === stub.id) continue;
803 // Skip generated-file candidates — they're siblings (msgClient,
804 // UnsafeMsgServer, …) whose method sets coincidentally match.
805 if (isGeneratedFile(cand.filePath)) continue;
806
807 const candNames = methodNamesByStruct.get(cand.id);
808 if (!candNames) continue;
809 // Subset: every RPC method must exist on the candidate by name.
810 // Signature-level match would tighten this further, but name-match
811 // alone already gives one-to-one pairing in real codebases because
812 // gRPC method-name sets are highly distinctive (Send + MultiSend +
813 // UpdateParams + SetSendEnabled is unique to bank's MsgServer).
814 if (!stubMethodNames.every((n) => candNames.has(n))) continue;
815
816 const candMethods = methodNodesByStruct.get(cand.id) ?? [];
817 let added = 0;
818 for (const sm of stubMethods) {
819 if (added >= MAX_CALLBACKS_PER_CHANNEL) break;

Callers 1

synthesizeCallbackEdgesFunction · 0.85

Calls 8

isGeneratedFileFunction · 0.90
isInternalMarkerFunction · 0.85
setMethod · 0.80
hasMethod · 0.80
getNodesByKindMethod · 0.65
getNodeByIdMethod · 0.65
getMethod · 0.65
getOutgoingEdgesMethod · 0.45

Tested by

no test coverage detected