mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-10 03:27:59 +00:00
fix(group): require in-file-unique resolution for ambiguous Go handler names
Selector handlers emit the field name only (`h.List`, `o.List` → `List`), and the non-strict resolver takes the first same-named row in the registration file. When that file declares the name more than once (methods on different receivers), mark the detection strictHandlerResolution so it resolves only to an in-file-unique match and otherwise keeps a file-level anchor instead of a wrong handler. Names declared once, or defined in other files, keep the existing resolution. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
39f16b6111
commit
2bc0bed628
2 changed files with 52 additions and 0 deletions
|
|
@ -465,6 +465,17 @@ export const GO_HTTP_PLUGIN: HttpLanguagePlugin = {
|
|||
const imports = readFrameworkImports(tree.rootNode);
|
||||
const echoOnly = imports.echo.size > 0 && imports.gin.size === 0;
|
||||
const mixed = imports.echo.size > 0 && imports.gin.size > 0;
|
||||
// Handler names declared more than once in this file (`(h *A) List` and
|
||||
// `(o *B) List`): the emitted name is field-only, so these must resolve
|
||||
// only when unique in the file instead of taking the first same-named row.
|
||||
const declaredNames = new Map<string, number>();
|
||||
for (const decl of tree.rootNode.descendantsOfType([
|
||||
'function_declaration',
|
||||
'method_declaration',
|
||||
])) {
|
||||
const declName = decl.childForFieldName('name')?.text;
|
||||
if (declName) declaredNames.set(declName, (declaredNames.get(declName) ?? 0) + 1);
|
||||
}
|
||||
for (const match of runCompiledPatterns(FRAMEWORK_ROUTE_PATTERNS, tree)) {
|
||||
const methodNode = match.captures.http_method;
|
||||
const pathNode = match.captures.path;
|
||||
|
|
@ -517,6 +528,12 @@ export const GO_HTTP_PLUGIN: HttpLanguagePlugin = {
|
|||
name: isInlineHandler ? null : handlerName,
|
||||
line: (handlerNode ?? pathNode).startPosition.row + 1,
|
||||
confidence: 0.8,
|
||||
// An ambiguous in-file name resolves only when the file holds exactly
|
||||
// one match (otherwise the route keeps a file-level anchor) rather than
|
||||
// binding to whichever same-named method the graph lists first.
|
||||
...(!isInlineHandler && handlerName && (declaredNames.get(handlerName) ?? 0) > 1
|
||||
? { strictHandlerResolution: true }
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -671,6 +671,41 @@ func routes() {
|
|||
]);
|
||||
});
|
||||
|
||||
it('requests in-file-unique resolution when the handler name is declared twice', () => {
|
||||
// `h.List` and `o.List` both emit the field name `List`; with two `List`
|
||||
// methods in this file, first-match resolution could bind either route to
|
||||
// the wrong one, so both are marked strict. A unique name (`Show`) and a
|
||||
// name defined elsewhere (`Remote`) keep the default resolution.
|
||||
parser.setLanguage(Go);
|
||||
const flags = GO_HTTP_PLUGIN.scan(
|
||||
parser.parse(`package main
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
type A struct{}
|
||||
type B struct{}
|
||||
|
||||
func (a *A) List(c *gin.Context) {}
|
||||
func (b *B) List(c *gin.Context) {}
|
||||
func (a *A) Show(c *gin.Context) {}
|
||||
|
||||
func routes(r *gin.Engine, h *A, o *B) {
|
||||
r.GET("/a", h.List)
|
||||
r.GET("/b", o.List)
|
||||
r.GET("/s", h.Show)
|
||||
r.GET("/r", other.Remote)
|
||||
}
|
||||
`),
|
||||
)
|
||||
.filter((d) => d.role === 'provider')
|
||||
.map((d) => [d.path, d.name, d.strictHandlerResolution ?? false]);
|
||||
expect(flags).toEqual([
|
||||
['/a', 'List', true],
|
||||
['/b', 'List', true],
|
||||
['/s', 'Show', false],
|
||||
['/r', 'Remote', false],
|
||||
]);
|
||||
});
|
||||
|
||||
it('applies the same group logic to echo', () => {
|
||||
expect(
|
||||
providers(`package main
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue