1
0
mirror of https://github.com/golang/go synced 2024-11-18 13:14:47 -07:00

imports: don't look for, or find, empty packages

Fix a pair of bugs that combined to cause golang/go#29520. First, don't go
looking for a package if we've only seen unexported identifiers selected
from it. It's probably a typo. Second, don't find packages with no files
in them, e.g. because they're all build tagged out. We can't know what
package they form, so we have no business considering them.

Test only for the first, since without the first bug the second has no
observable effect on behavior, and I don't want to test the private API.

Fixes golang/go#29520

Change-Id: I5b797940bec051be5945b9c5cb4e7bf28527a939
Reviewed-on: https://go-review.googlesource.com/c/156178
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Heschi Kreinick 2019-01-03 13:53:54 -05:00
parent ca9055ed7d
commit 8a60511975
2 changed files with 39 additions and 43 deletions

View File

@ -157,7 +157,11 @@ func collectReferences(f *ast.File) map[string]map[string]bool {
break break
} }
if xident.Obj != nil { if xident.Obj != nil {
// if the parser can resolve it, it's not a package ref // If the parser can resolve it, it's not a package ref.
break
}
if !ast.IsExported(v.Sel.Name) {
// Whatever this is, it's not exported from a package.
break break
} }
pkgName := xident.Name pkgName := xident.Name
@ -166,9 +170,7 @@ func collectReferences(f *ast.File) map[string]map[string]bool {
r = make(map[string]bool) r = make(map[string]bool)
refs[pkgName] = r refs[pkgName] = r
} }
if ast.IsExported(v.Sel.Name) { r[v.Sel.Name] = true
r[v.Sel.Name] = true
}
} }
return visitor return visitor
} }
@ -855,10 +857,7 @@ func loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[strin
for _, fname := range pkg.goPackage.CompiledGoFiles { for _, fname := range pkg.goPackage.CompiledGoFiles {
f, err := parser.ParseFile(fset, fname, nil, 0) f, err := parser.ParseFile(fset, fname, nil, 0)
if err != nil { if err != nil {
if Debug { return nil, fmt.Errorf("parsing %s: %v", fname, err)
log.Printf("Parsing %s: %v", fname, err)
}
return nil, err
} }
for name := range f.Scope.Objects { for name := range f.Scope.Objects {
if ast.IsExported(name) { if ast.IsExported(name) {
@ -871,34 +870,29 @@ func loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[strin
exports := make(map[string]bool) exports := make(map[string]bool)
buildCtx := build.Default // Look for non-test, buildable .go files which could provide exports.
all, err := ioutil.ReadDir(pkg.dir)
// ReadDir is like ioutil.ReadDir, but only returns *.go files if err != nil {
// and filters out _test.go files since they're not relevant return nil, err
// and only slow things down. }
buildCtx.ReadDir = func(dir string) (notTests []os.FileInfo, err error) { var files []os.FileInfo
all, err := ioutil.ReadDir(dir) for _, fi := range all {
if err != nil { name := fi.Name()
return nil, err if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
continue
} }
notTests = all[:0] match, err := build.Default.MatchFile(pkg.dir, fi.Name())
for _, fi := range all { if err != nil || !match {
name := fi.Name() continue
if strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go") {
notTests = append(notTests, fi)
}
} }
return notTests, nil files = append(files, fi)
} }
files, err := buildCtx.ReadDir(pkg.dir) if len(files) == 0 {
if err != nil { return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", pkg.dir)
log.Print(err)
return nil, err
} }
fset := token.NewFileSet() fset := token.NewFileSet()
for _, fi := range files { for _, fi := range files {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@ -906,30 +900,19 @@ func loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[strin
default: default:
} }
match, err := buildCtx.MatchFile(pkg.dir, fi.Name())
if err != nil || !match {
continue
}
fullFile := filepath.Join(pkg.dir, fi.Name()) fullFile := filepath.Join(pkg.dir, fi.Name())
f, err := parser.ParseFile(fset, fullFile, nil, 0) f, err := parser.ParseFile(fset, fullFile, nil, 0)
if err != nil { if err != nil {
if Debug { return nil, fmt.Errorf("parsing %s: %v", fullFile, err)
log.Printf("Parsing %s: %v", fullFile, err)
}
return nil, err
} }
pkgName := f.Name.Name pkgName := f.Name.Name
if pkgName == "documentation" { if pkgName == "documentation" {
// Special case from go/build.ImportDir, not // Special case from go/build.ImportDir, not
// handled by buildCtx.MatchFile. // handled by MatchFile above.
continue continue
} }
if pkgName != expectPackage { if pkgName != expectPackage {
err := fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", pkg.dir, expectPackage, pkgName) return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", pkg.dir, expectPackage, pkgName)
if Debug {
log.Print(err)
}
return nil, err
} }
for name := range f.Scope.Objects { for name := range f.Scope.Objects {
if ast.IsExported(name) { if ast.IsExported(name) {
@ -1015,6 +998,9 @@ func findImport(ctx context.Context, dirScan []*pkg, pkgName string, symbols map
exports, err := loadExports(ctx, pkgName, c.pkg) exports, err := loadExports(ctx, pkgName, c.pkg)
if err != nil { if err != nil {
if Debug {
log.Printf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
}
resc <- nil resc <- nil
return return
} }

View File

@ -752,6 +752,16 @@ func main() { fmt.Println() }
`, `,
}, },
{
name: "ignore_unexported_identifier",
in: `package main
var _ = fmt.unexported`,
out: `package main
var _ = fmt.unexported
`,
},
// FormatOnly // FormatOnly
{ {
name: "formatonly_works", name: "formatonly_works",