From 28ed04f8828615ef8bc15bd089501b6d3b560421 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Thu, 16 Jan 2020 14:32:14 -0500 Subject: [PATCH] go/packages: internally expose ForTests in go/packages This change eliminates our need to guess what the package under test is in gopls, since `go list` always knows the answer. Change-Id: I16e482ed3b452bd57cd478b1f8280fcea56474d3 Reviewed-on: https://go-review.googlesource.com/c/tools/+/215020 Run-TryBot: Rebecca Stambler TryBot-Result: Gobot Gobot Reviewed-by: Heschi Kreinick --- go/packages/golist.go | 1 + go/packages/packages.go | 10 ++++++ go/packages/packages_test.go | 47 +++++++++++++++++++++++++++ internal/lsp/cache/load.go | 3 ++ internal/lsp/cache/view.go | 6 +++- internal/packagesinternal/packages.go | 4 +++ 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 internal/packagesinternal/packages.go diff --git a/go/packages/golist.go b/go/packages/golist.go index a9a1ba89e8..dce7b197fe 100644 --- a/go/packages/golist.go +++ b/go/packages/golist.go @@ -729,6 +729,7 @@ func golistDriver(cfg *Config, rootsDirs func() *goInfo, words ...string) (*driv GoFiles: absJoin(p.Dir, p.GoFiles, p.CgoFiles), CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles), OtherFiles: absJoin(p.Dir, otherFiles(p)...), + forTest: p.ForTest, } // Work around https://golang.org/issue/28749: diff --git a/go/packages/packages.go b/go/packages/packages.go index f98a0bdcae..bc11505a3e 100644 --- a/go/packages/packages.go +++ b/go/packages/packages.go @@ -23,6 +23,7 @@ import ( "sync" "golang.org/x/tools/go/gcexportdata" + "golang.org/x/tools/internal/packagesinternal" ) // A LoadMode controls the amount of detail to return when loading. @@ -292,6 +293,15 @@ type Package struct { // TypesSizes provides the effective size function for types in TypesInfo. TypesSizes types.Sizes + + // forTest is the package under test, if any. + forTest string +} + +func init() { + packagesinternal.GetForTest = func(p interface{}) string { + return p.(*Package).forTest + } } // An Error describes a problem with a package's metadata, syntax, or types. diff --git a/go/packages/packages_test.go b/go/packages/packages_test.go index 94bff03f13..fe8ef01415 100644 --- a/go/packages/packages_test.go +++ b/go/packages/packages_test.go @@ -27,6 +27,7 @@ import ( "golang.org/x/tools/go/packages" "golang.org/x/tools/go/packages/packagestest" + "golang.org/x/tools/internal/packagesinternal" "golang.org/x/tools/internal/testenv" ) @@ -2588,6 +2589,52 @@ func testCycleImportStack(t *testing.T, exporter packagestest.Exporter) { } } +func TestForTestField(t *testing.T) { + packagestest.TestAll(t, testForTestField) +} +func testForTestField(t *testing.T, exporter packagestest.Exporter) { + exported := packagestest.Export(t, exporter, []packagestest.Module{{ + Name: "golang.org/fake", + Files: map[string]interface{}{ + "a/a.go": `package a; func hello() {};`, + "a/a_test.go": `package a; import "testing"; func TestA1(t *testing.T) {};`, + "a/x_test.go": `package a_test; import "testing"; func TestA2(t *testing.T) {};`, + }}}) + defer exported.Cleanup() + + // Add overlays to make sure they don't affect anything. + exported.Config.Overlay = map[string][]byte{ + "a/a_test.go": []byte(`package a; import "testing"; func TestA1(t *testing.T) { hello(); };`), + "a/x_test.go": []byte(`package a_test; import "testing"; func TestA2(t *testing.T) { hello(); };`), + } + exported.Config.Tests = true + exported.Config.Mode = packages.NeedName | packages.NeedImports + forTest := "golang.org/fake/a" + pkgs, err := packages.Load(exported.Config, forTest) + if err != nil { + t.Fatal(err) + } + if len(pkgs) != 4 { + t.Errorf("expected 4 packages, got %v", len(pkgs)) + } + for _, pkg := range pkgs { + var hasTestFile bool + for _, f := range pkg.CompiledGoFiles { + if strings.Contains(f, "a_test.go") || strings.Contains(f, "x_test.go") { + hasTestFile = true + break + } + } + if !hasTestFile { + continue + } + got := packagesinternal.GetForTest(pkg) + if got != forTest { + t.Errorf("expected %q, got %q", forTest, got) + } + } +} + func errorMessages(errors []packages.Error) []string { var msgs []string for _, err := range errors { diff --git a/internal/lsp/cache/load.go b/internal/lsp/cache/load.go index 59eec9416e..8f8df23100 100644 --- a/internal/lsp/cache/load.go +++ b/internal/lsp/cache/load.go @@ -13,6 +13,7 @@ import ( "golang.org/x/tools/go/packages" "golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/telemetry" + "golang.org/x/tools/internal/packagesinternal" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/telemetry/log" "golang.org/x/tools/internal/telemetry/tag" @@ -26,6 +27,7 @@ type metadata struct { name string goFiles []span.URI compiledGoFiles []span.URI + forTest packagePath typesSizes types.Sizes errors []packages.Error deps []packageID @@ -179,6 +181,7 @@ func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg * id: id, pkgPath: pkgPath, name: pkg.Name, + forTest: packagePath(packagesinternal.GetForTest(pkg)), typesSizes: pkg.TypesSizes, errors: pkg.Errors, config: cfg, diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go index c27303e85d..6f2610672f 100644 --- a/internal/lsp/cache/view.go +++ b/internal/lsp/cache/view.go @@ -576,7 +576,11 @@ func (v *view) initialize(ctx context.Context, s *snapshot) { } // A test variant of a package can only be loaded directly by loading // the non-test variant with -test. Track the import path of the non-test variant. - s.setWorkspacePackage(m.id, m.pkgPath) + pkgPath := m.pkgPath + if m.forTest != "" { + pkgPath = m.forTest + } + s.setWorkspacePackage(m.id, pkgPath) if _, err := s.packageHandle(ctx, m.id); err != nil { return err } diff --git a/internal/packagesinternal/packages.go b/internal/packagesinternal/packages.go new file mode 100644 index 0000000000..0c0dbb6a9d --- /dev/null +++ b/internal/packagesinternal/packages.go @@ -0,0 +1,4 @@ +// Package packagesinternal exposes internal-only fields from go/packages. +package packagesinternal + +var GetForTest = func(p interface{}) string { return "" }