From eaf60c4043f8e06f78dc2dd96ea83402312231db Mon Sep 17 00:00:00 2001 From: Evan Wang Date: Fri, 1 May 2026 23:08:20 +0800 Subject: [PATCH] fix(go): handle chan T return types and tighten GOPATH suffix resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Strip 'chan ' prefix in return-type qualification loop so that func Events() chan Event does not emit pkg.chan Event (H2 edge case) - Require ≥2 path segments in GOPATH fallback to avoid false-positive matches when an external import suffix collides with a local directory named pkg/, util/, internal/, etc. (review H1) - Add import resolution tests for module sub-package, single-segment collision rejection, and multi-segment GOPATH match --- .../core/ingestion/languages/go/captures.ts | 2 + .../ingestion/languages/go/import-target.ts | 8 ++-- .../scope-resolution/go/go-imports.test.ts | 41 +++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/gitnexus/src/core/ingestion/languages/go/captures.ts b/gitnexus/src/core/ingestion/languages/go/captures.ts index 8065341b3..778ccce68 100644 --- a/gitnexus/src/core/ingestion/languages/go/captures.ts +++ b/gitnexus/src/core/ingestion/languages/go/captures.ts @@ -180,7 +180,9 @@ export function emitGoScopeCaptures( let raw = typeCap.text.trim(); while (raw.startsWith('*')) raw = raw.slice(1).trim(); if (raw.startsWith('[]')) raw = raw.slice(2).trim(); + if (raw.startsWith('chan ')) raw = raw.slice(5).trim(); if (raw.includes('.') || raw.startsWith('func(') || raw.startsWith('map[')) continue; + if (raw.startsWith('chan ')) continue; if (GO_BUILTIN_TYPES.has(raw)) continue; const idx = raw.indexOf('['); if (idx !== -1) raw = raw.slice(0, idx); diff --git a/gitnexus/src/core/ingestion/languages/go/import-target.ts b/gitnexus/src/core/ingestion/languages/go/import-target.ts index c334fb2a6..28e8113fd 100644 --- a/gitnexus/src/core/ingestion/languages/go/import-target.ts +++ b/gitnexus/src/core/ingestion/languages/go/import-target.ts @@ -37,10 +37,12 @@ export function resolveGoImportTarget( if (files.length > 0) return files; } - // 2) Non-go.mod / GOPATH: progressively shorter directory suffixes - // "github.com/xxx/yyy/pkg" → try "github.com/xxx/yyy/pkg/" → "xxx/yyy/pkg/" → "yyy/pkg/" → "pkg/" + // 2) Non-go.mod / GOPATH: progressively shorter directory suffixes. + // "github.com/xxx/yyy/pkg" → try "github.com/xxx/yyy/pkg/" → "xxx/yyy/pkg/" → "yyy/pkg/" + // Stop at ≥2 segments to avoid matching a single-segment suffix (e.g. + // "pkg", "util", "internal") to a local directory with the same name. const parts = targetRaw.split('/').filter(Boolean); - for (let i = 0; i < parts.length; i++) { + for (let i = 0; i < parts.length - 1; i++) { const files = findAllFilesInPkgDir(allFilePaths, parts.slice(i).join('/')); if (files.length > 0) return files; } diff --git a/gitnexus/test/unit/scope-resolution/go/go-imports.test.ts b/gitnexus/test/unit/scope-resolution/go/go-imports.test.ts index d13466532..e96d73ee7 100644 --- a/gitnexus/test/unit/scope-resolution/go/go-imports.test.ts +++ b/gitnexus/test/unit/scope-resolution/go/go-imports.test.ts @@ -111,4 +111,45 @@ describe('Go import target resolution', () => { expect(result).toEqual(['extra.go', 'root.go']); }); + + it('resolves sub-package imports under module root', () => { + const result = resolveGoImportTarget( + 'example.com/lib/internal/models', + 'cmd/app/main.go', + new Set(['internal/models/user.go', 'internal/models/repo.go', 'root.go']), + { modulePath: 'example.com/lib' }, + ); + + expect(Array.isArray(result)).toBe(true); + expect((result as string[]).sort()).toEqual([ + 'internal/models/repo.go', + 'internal/models/user.go', + ]); + }); + + it('rejects single-segment GOPATH suffix that collides with a local dir', () => { + // "github.com/other/team/pkg" suffix-stripped would eventually + // reach "pkg" which matches the local pkg/ dir — but we require + // ≥2 segments in the GOPATH fallback, so it must not resolve. + const result = resolveGoImportTarget( + 'github.com/other/team/pkg', + 'main.go', + new Set(['pkg/util.go', 'main.go']), + ); + + expect(result).toBeNull(); + }); + + it('resolves multi-segment GOPATH suffix that matches local dir', () => { + // "github.com/other/team/pkg" where "team/pkg/" exists locally + // — the 2-segment suffix "team/pkg" should still resolve. + const result = resolveGoImportTarget( + 'github.com/other/team/pkg', + 'main.go', + new Set(['team/pkg/util.go', 'main.go']), + ); + + expect(Array.isArray(result)).toBe(true); + expect(result as string[]).toEqual(['team/pkg/util.go']); + }); });