From 5ecc1643ff520131a8a2aa1e26f1b4a7da41512c Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Wed, 22 Jan 2020 19:23:30 -0500 Subject: [PATCH] internal/lsp/cache: fix GOPATH vendoring We treat package IDs and import paths as semi-interchangeable, which is wrong when GOPATH vendoring is in use. The only place it hurts us is during import resolution, which is fixed here. We should always have the package loaded, so it's just a matter of finding it by searching each possible vendor location. Fixes golang/go#36155. Change-Id: If789092d16fa3d3294b6d8a2bcb980264506c161 Reviewed-on: https://go-review.googlesource.com/c/tools/+/215904 Run-TryBot: Heschi Kreinick TryBot-Result: Gobot Gobot Reviewed-by: Rebecca Stambler --- internal/lsp/cache/check.go | 19 +++++++++++++++++++ internal/lsp/cache/load.go | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go index b3e9e04df1..b578bae2a0 100644 --- a/internal/lsp/cache/check.go +++ b/internal/lsp/cache/check.go @@ -11,6 +11,7 @@ import ( "go/ast" "go/token" "go/types" + "path" "sort" "sync" @@ -309,6 +310,24 @@ func typeCheck(ctx context.Context, fset *token.FileSet, m *metadata, mode sourc }, Importer: importerFunc(func(pkgPath string) (*types.Package, error) { dep := deps[packagePath(pkgPath)] + if dep == nil { + // We may be in GOPATH mode, in which case we need to check vendor dirs. + searchDir := path.Dir(pkg.PkgPath()) + for { + vdir := packagePath(path.Join(searchDir, "vendor", pkgPath)) + if vdep := deps[vdir]; vdep != nil { + dep = vdep + break + } + + // Search until Dir doesn't take us anywhere new, e.g. "." or "/". + next := path.Dir(searchDir) + if searchDir == next { + break + } + searchDir = next + } + } if dep == nil { return nil, errors.Errorf("no package for import %s", pkgPath) } diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go index 98b083a9fe..12839d6377 100644 --- a/internal/lsp/cache/load.go +++ b/internal/lsp/cache/load.go @@ -42,6 +42,9 @@ func (s *snapshot) load(ctx context.Context, scopes ...interface{}) ([]*metadata for _, scope := range scopes { switch scope := scope.(type) { case []packagePath: + // The only time we pass package paths is when we're doing a + // partial workspace load. In those cases, the paths came back from + // go list and should already be GOPATH-vendorized when appropriate. for _, p := range scope { query = append(query, string(p)) } @@ -59,6 +62,8 @@ func (s *snapshot) load(ctx context.Context, scopes ...interface{}) ([]*metadata q = "./..." } query = append(query, q) + default: + panic(fmt.Sprintf("unknown scope type %T", scope)) } } ctx, done := trace.StartSpan(ctx, "cache.view.load", telemetry.Query.Of(query))