-
Notifications
You must be signed in to change notification settings - Fork 2.4k
fix: attach Go receiver methods to owner types #588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -256,10 +256,73 @@ export class ReferenceResolver { | |
| }); | ||
| } | ||
| } | ||
| updated += this.linkGoReceiverMethodOwners(); | ||
| if (updated > 0) this.clearCaches(); | ||
| return updated; | ||
| } | ||
|
|
||
| private linkGoReceiverMethodOwners(): number { | ||
| const methods = this.queries.getNodesByKind('method') | ||
| .filter((node) => node.language === 'go' && node.qualifiedName.includes('::')); | ||
| if (methods.length === 0) return 0; | ||
|
|
||
| const ownersByName = new Map<string, Node[]>(); | ||
| for (const kind of ['struct', 'class', 'enum', 'trait'] as const) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For valid Go defined types whose underlying type is not a struct/interface, e.g. Useful? React with 👍 / 👎. |
||
| for (const owner of this.queries.getNodesByKind(kind)) { | ||
| if (owner.language !== 'go') continue; | ||
| const existing = ownersByName.get(owner.name) ?? []; | ||
| existing.push(owner); | ||
| ownersByName.set(owner.name, existing); | ||
| } | ||
| } | ||
|
|
||
| const packageNameCache = new Map<string, string | null>(); | ||
| const packageName = (filePath: string): string | null => { | ||
| if (packageNameCache.has(filePath)) return packageNameCache.get(filePath)!; | ||
| const source = this.context.readFile(filePath); | ||
| const match = source?.match(/^\s*package\s+([A-Za-z_][A-Za-z0-9_]*)/m); | ||
| const name = match?.[1] ?? null; | ||
| packageNameCache.set(filePath, name); | ||
| return name; | ||
| }; | ||
|
|
||
| const edges: Edge[] = []; | ||
| for (const method of methods) { | ||
| const receiverType = method.qualifiedName.split('::', 1)[0]; | ||
| if (!receiverType) continue; | ||
|
|
||
| const alreadyOwned = this.queries.getIncomingEdges(method.id, ['contains']) | ||
| .some((edge) => { | ||
| const source = this.queries.getNodeById(edge.source); | ||
| return source && source.language === 'go' && source.name === receiverType; | ||
| }); | ||
| if (alreadyOwned) continue; | ||
|
|
||
| const methodDir = path.dirname(method.filePath); | ||
| const methodPackage = packageName(method.filePath); | ||
| if (!methodPackage) continue; | ||
|
|
||
| const owner = (ownersByName.get(receiverType) ?? []).find((candidate) => | ||
| path.dirname(candidate.filePath) === methodDir && | ||
| packageName(candidate.filePath) === methodPackage | ||
| ); | ||
| if (!owner) continue; | ||
|
|
||
| edges.push({ | ||
| source: owner.id, | ||
| target: method.id, | ||
| kind: 'contains', | ||
| provenance: 'heuristic', | ||
| metadata: { synthesizedBy: 'go-receiver-owner' }, | ||
| }); | ||
| } | ||
|
|
||
| if (edges.length > 0) { | ||
| this.queries.insertEdges(edges); | ||
| } | ||
| return edges.length; | ||
| } | ||
|
|
||
| /** | ||
| * Pre-build lightweight caches for resolution. | ||
| * Node lookups are now handled by indexed SQLite queries instead of | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When callers use
CodeGraph.indexFiles()to index a selected set of Go files, this new owner-linking pass never runs because it is only wired throughrunPostExtract()(called byindexAll/sync, whilesrc/index.ts:392-400returns directly fromorchestrator.indexFiles). In that context, receiver methods declared in a different indexed file from their type remain without the synthesizedcontainsedge, so the fix behaves differently depending on which public indexing API was used.Useful? React with 👍 / 👎.