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 <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
Rebecca Stambler 2020-01-16 14:32:14 -05:00
Родитель 1c4842a210
Коммит 28ed04f882
6 изменённых файлов: 70 добавлений и 1 удалений

Просмотреть файл

@ -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:

Просмотреть файл

@ -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.

Просмотреть файл

@ -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 {

3
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,

6
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
}

Просмотреть файл

@ -0,0 +1,4 @@
// Package packagesinternal exposes internal-only fields from go/packages.
package packagesinternal
var GetForTest = func(p interface{}) string { return "" }