mirror of
https://github.com/golang/go
synced 2024-11-18 19:44:46 -07:00
internal/imports: load test exports of package under test
x_tests can access exports from the test variant of the package under test. Change loadExportsFromFiles to understand that mode, and use it where appropriate. I didn't want to come up with a cache key for for the test variant, so for now we bypass the cache in these situations. Fixes golang/go#29979. Change-Id: I9959a08da97bbee64c5bcd56e06f548486693156 Reviewed-on: https://go-review.googlesource.com/c/tools/+/213221 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
e23c44e711
commit
3d14842334
@ -629,6 +629,14 @@ func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filena
|
|||||||
return notSelf(pkg) && wrappedCallback.packageNameLoaded(pkg)
|
return notSelf(pkg) && wrappedCallback.packageNameLoaded(pkg)
|
||||||
},
|
},
|
||||||
exportsLoaded: func(pkg *pkg, exports []string) {
|
exportsLoaded: func(pkg *pkg, exports []string) {
|
||||||
|
// If we're an x_test, load the package under test's test variant.
|
||||||
|
if strings.HasSuffix(filePkg, "_test") && pkg.dir == filepath.Dir(filename) {
|
||||||
|
var err error
|
||||||
|
_, exports, err = loadExportsFromFiles(ctx, env, pkg.dir, true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
wrappedCallback.exportsLoaded(pkg, exports)
|
wrappedCallback.exportsLoaded(pkg, exports)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -842,7 +850,7 @@ type Resolver interface {
|
|||||||
scan(ctx context.Context, callback *scanCallback) error
|
scan(ctx context.Context, callback *scanCallback) error
|
||||||
// loadExports returns the set of exported symbols in the package at dir.
|
// loadExports returns the set of exported symbols in the package at dir.
|
||||||
// loadExports may be called concurrently.
|
// loadExports may be called concurrently.
|
||||||
loadExports(ctx context.Context, pkg *pkg) (string, []string, error)
|
loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error)
|
||||||
|
|
||||||
ClearForNewScan()
|
ClearForNewScan()
|
||||||
}
|
}
|
||||||
@ -1192,7 +1200,7 @@ func (r *gopathResolver) scan(ctx context.Context, callback *scanCallback) error
|
|||||||
if !callback.packageNameLoaded(p) {
|
if !callback.packageNameLoaded(p) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, exports, err := r.loadExports(ctx, p); err == nil {
|
if _, exports, err := r.loadExports(ctx, p, false); err == nil {
|
||||||
callback.exportsLoaded(p, exports)
|
callback.exportsLoaded(p, exports)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1231,11 +1239,11 @@ func filterRoots(roots []gopathwalk.Root, include func(gopathwalk.Root) bool) []
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *gopathResolver) loadExports(ctx context.Context, pkg *pkg) (string, []string, error) {
|
func (r *gopathResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) {
|
||||||
if info, ok := r.cache.Load(pkg.dir); ok {
|
if info, ok := r.cache.Load(pkg.dir); ok && !includeTest {
|
||||||
return r.cache.CacheExports(ctx, r.env, info)
|
return r.cache.CacheExports(ctx, r.env, info)
|
||||||
}
|
}
|
||||||
return loadExportsFromFiles(ctx, r.env, pkg.dir)
|
return loadExportsFromFiles(ctx, r.env, pkg.dir, includeTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VendorlessPath returns the devendorized version of the import path ipath.
|
// VendorlessPath returns the devendorized version of the import path ipath.
|
||||||
@ -1251,7 +1259,7 @@ func VendorlessPath(ipath string) string {
|
|||||||
return ipath
|
return ipath
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string) (string, []string, error) {
|
func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) {
|
||||||
var exports []string
|
var exports []string
|
||||||
|
|
||||||
// Look for non-test, buildable .go files which could provide exports.
|
// Look for non-test, buildable .go files which could provide exports.
|
||||||
@ -1262,7 +1270,7 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string) (str
|
|||||||
var files []os.FileInfo
|
var files []os.FileInfo
|
||||||
for _, fi := range all {
|
for _, fi := range all {
|
||||||
name := fi.Name()
|
name := fi.Name()
|
||||||
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
if !strings.HasSuffix(name, ".go") || (!includeTest && strings.HasSuffix(name, "_test.go")) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
match, err := env.buildContext().MatchFile(dir, fi.Name())
|
match, err := env.buildContext().MatchFile(dir, fi.Name())
|
||||||
@ -1295,6 +1303,10 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string) (str
|
|||||||
// handled by MatchFile above.
|
// handled by MatchFile above.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if includeTest && strings.HasSuffix(f.Name.Name, "_test") {
|
||||||
|
// x_test package. We want internal test files only.
|
||||||
|
continue
|
||||||
|
}
|
||||||
pkgName = f.Name.Name
|
pkgName = f.Name.Name
|
||||||
for name := range f.Scope.Objects {
|
for name := range f.Scope.Objects {
|
||||||
if ast.IsExported(name) {
|
if ast.IsExported(name) {
|
||||||
@ -1360,7 +1372,9 @@ func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgNa
|
|||||||
if pass.env.Debug {
|
if pass.env.Debug {
|
||||||
pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName)
|
pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName)
|
||||||
}
|
}
|
||||||
exports, err := loadExportsForPackage(ctx, pass.env, pkgName, c.pkg)
|
// If we're an x_test, load the package under test's test variant.
|
||||||
|
includeTest := strings.HasSuffix(pass.f.Name.Name, "_test") && c.pkg.dir == pass.srcDir
|
||||||
|
_, exports, err := pass.env.GetResolver().loadExports(ctx, c.pkg, includeTest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if pass.env.Debug {
|
if pass.env.Debug {
|
||||||
pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
|
pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
|
||||||
@ -1397,17 +1411,6 @@ func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgNa
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadExportsForPackage(ctx context.Context, env *ProcessEnv, expectPkg string, pkg *pkg) ([]string, error) {
|
|
||||||
pkgName, exports, err := env.GetResolver().loadExports(ctx, pkg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if expectPkg != pkgName {
|
|
||||||
return nil, fmt.Errorf("dir %v is package %v, wanted %v", pkg.dir, pkgName, expectPkg)
|
|
||||||
}
|
|
||||||
return exports, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// pkgIsCandidate reports whether pkg is a candidate for satisfying the
|
// pkgIsCandidate reports whether pkg is a candidate for satisfying the
|
||||||
// finding which package pkgIdent in the file named by filename is trying
|
// finding which package pkgIdent in the file named by filename is trying
|
||||||
// to refer to.
|
// to refer to.
|
||||||
|
@ -2489,6 +2489,40 @@ var _ = bytes.Buffer{}
|
|||||||
}.processTest(t, "foo.com", "foo.go", nil, nil, want)
|
}.processTest(t, "foo.com", "foo.go", nil, nil, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that an external test package will import the package under test if it
|
||||||
|
// also uses symbols exported only in test files.
|
||||||
|
// https://golang.org/issues/29979
|
||||||
|
func TestExternalTest(t *testing.T) {
|
||||||
|
const input = `package a_test
|
||||||
|
func TestX() {
|
||||||
|
a.X()
|
||||||
|
a.Y()
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const want = `package a_test
|
||||||
|
|
||||||
|
import "foo.com/a"
|
||||||
|
|
||||||
|
func TestX() {
|
||||||
|
a.X()
|
||||||
|
a.Y()
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
testConfig{
|
||||||
|
modules: []packagestest.Module{
|
||||||
|
{
|
||||||
|
Name: "foo.com/a",
|
||||||
|
Files: fm{
|
||||||
|
"a.go": "package a\n func X() {}",
|
||||||
|
"export_test.go": "package a\n func Y() {}",
|
||||||
|
"a_test.go": input,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}.processTest(t, "foo.com/a", "a_test.go", nil, nil, want)
|
||||||
|
}
|
||||||
|
|
||||||
// TestStdLibGetCandidates tests that get packages finds std library packages
|
// TestStdLibGetCandidates tests that get packages finds std library packages
|
||||||
// with correct priorities.
|
// with correct priorities.
|
||||||
func TestGetCandidates(t *testing.T) {
|
func TestGetCandidates(t *testing.T) {
|
||||||
|
@ -413,7 +413,7 @@ func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error
|
|||||||
if !callback.packageNameLoaded(pkg) {
|
if !callback.packageNameLoaded(pkg) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, exports, err := r.loadExports(ctx, pkg)
|
_, exports, err := r.loadExports(ctx, pkg, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -529,14 +529,14 @@ func (r *ModuleResolver) canonicalize(info directoryPackageInfo) (*pkg, error) {
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg) (string, []string, error) {
|
func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) {
|
||||||
if err := r.init(); err != nil {
|
if err := r.init(); err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
if info, ok := r.cacheLoad(pkg.dir); ok {
|
if info, ok := r.cacheLoad(pkg.dir); ok && !includeTest {
|
||||||
return r.cacheExports(ctx, r.env, info)
|
return r.cacheExports(ctx, r.env, info)
|
||||||
}
|
}
|
||||||
return loadExportsFromFiles(ctx, r.env, pkg.dir)
|
return loadExportsFromFiles(ctx, r.env, pkg.dir, includeTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) directoryPackageInfo {
|
func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) directoryPackageInfo {
|
||||||
|
@ -215,7 +215,7 @@ func (d *dirInfoCache) CacheExports(ctx context.Context, env *ProcessEnv, info d
|
|||||||
if reached, err := info.reachedStatus(nameLoaded); reached && err != nil {
|
if reached, err := info.reachedStatus(nameLoaded); reached && err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
info.packageName, info.exports, info.err = loadExportsFromFiles(ctx, env, info.dir)
|
info.packageName, info.exports, info.err = loadExportsFromFiles(ctx, env, info.dir, false)
|
||||||
if info.err == context.Canceled || info.err == context.DeadlineExceeded {
|
if info.err == context.Canceled || info.err == context.DeadlineExceeded {
|
||||||
return info.packageName, info.exports, info.err
|
return info.packageName, info.exports, info.err
|
||||||
}
|
}
|
||||||
|
4
internal/lsp/testdata/summary.txt.golden
vendored
4
internal/lsp/testdata/summary.txt.golden
vendored
@ -1,7 +1,7 @@
|
|||||||
-- summary --
|
-- summary --
|
||||||
CompletionsCount = 225
|
CompletionsCount = 225
|
||||||
CompletionSnippetCount = 62
|
CompletionSnippetCount = 63
|
||||||
UnimportedCompletionsCount = 4
|
UnimportedCompletionsCount = 9
|
||||||
DeepCompletionsCount = 5
|
DeepCompletionsCount = 5
|
||||||
FuzzyCompletionsCount = 8
|
FuzzyCompletionsCount = 8
|
||||||
RankedCompletionsCount = 56
|
RankedCompletionsCount = 56
|
||||||
|
3
internal/lsp/testdata/unimported/export_test.go
vendored
Normal file
3
internal/lsp/testdata/unimported/export_test.go
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package unimported
|
||||||
|
|
||||||
|
var TestExport int //@item(testexport, "TestExport", "(from \"golang.org/x/tools/internal/lsp/unimported\")", "var")
|
9
internal/lsp/testdata/unimported/x_test.go
vendored
Normal file
9
internal/lsp/testdata/unimported/x_test.go
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package unimported_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSomething(t *testing.T) {
|
||||||
|
_ = unimported.TestExport //@unimported("TestExport", testexport)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user