Skip to content

Commit

Permalink
imports: don't look for, or find, empty packages
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
heschi committed Jan 3, 2019
1 parent ca9055e commit 8a60511
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 43 deletions.
72 changes: 29 additions & 43 deletions imports/fix.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ func collectReferences(f *ast.File) map[string]map[string]bool {
break
}
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
}
pkgName := xident.Name
Expand All @@ -166,9 +170,7 @@ func collectReferences(f *ast.File) map[string]map[string]bool {
r = make(map[string]bool)
refs[pkgName] = r
}
if ast.IsExported(v.Sel.Name) {
r[v.Sel.Name] = true
}
r[v.Sel.Name] = true
}
return visitor
}
Expand Down Expand Up @@ -855,10 +857,7 @@ func loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[strin
for _, fname := range pkg.goPackage.CompiledGoFiles {
f, err := parser.ParseFile(fset, fname, nil, 0)
if err != nil {
if Debug {
log.Printf("Parsing %s: %v", fname, err)
}
return nil, err
return nil, fmt.Errorf("parsing %s: %v", fname, err)
}
for name := range f.Scope.Objects {
if ast.IsExported(name) {
Expand All @@ -871,65 +870,49 @@ func loadExports(ctx context.Context, expectPackage string, pkg *pkg) (map[strin

exports := make(map[string]bool)

buildCtx := build.Default

// ReadDir is like ioutil.ReadDir, but only returns *.go files
// and filters out _test.go files since they're not relevant
// and only slow things down.
buildCtx.ReadDir = func(dir string) (notTests []os.FileInfo, err error) {
all, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
// Look for non-test, buildable .go files which could provide exports.
all, err := ioutil.ReadDir(pkg.dir)
if err != nil {
return nil, err
}
var files []os.FileInfo
for _, fi := range all {
name := fi.Name()
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
continue
}
notTests = all[:0]
for _, fi := range all {
name := fi.Name()
if strings.HasSuffix(name, ".go") && !strings.HasSuffix(name, "_test.go") {
notTests = append(notTests, fi)
}
match, err := build.Default.MatchFile(pkg.dir, fi.Name())
if err != nil || !match {
continue
}
return notTests, nil
files = append(files, fi)
}

files, err := buildCtx.ReadDir(pkg.dir)
if err != nil {
log.Print(err)
return nil, err
if len(files) == 0 {
return nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", pkg.dir)
}

fset := token.NewFileSet()

for _, fi := range files {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}

match, err := buildCtx.MatchFile(pkg.dir, fi.Name())
if err != nil || !match {
continue
}
fullFile := filepath.Join(pkg.dir, fi.Name())
f, err := parser.ParseFile(fset, fullFile, nil, 0)
if err != nil {
if Debug {
log.Printf("Parsing %s: %v", fullFile, err)
}
return nil, err
return nil, fmt.Errorf("parsing %s: %v", fullFile, err)
}
pkgName := f.Name.Name
if pkgName == "documentation" {
// Special case from go/build.ImportDir, not
// handled by buildCtx.MatchFile.
// handled by MatchFile above.
continue
}
if pkgName != expectPackage {
err := 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
return nil, fmt.Errorf("scan of dir %v is not expected package %v (actually %v)", pkg.dir, expectPackage, pkgName)
}
for name := range f.Scope.Objects {
if ast.IsExported(name) {
Expand Down Expand Up @@ -1015,6 +998,9 @@ func findImport(ctx context.Context, dirScan []*pkg, pkgName string, symbols map

exports, err := loadExports(ctx, pkgName, c.pkg)
if err != nil {
if Debug {
log.Printf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err)
}
resc <- nil
return
}
Expand Down
10 changes: 10 additions & 0 deletions imports/fix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
name: "formatonly_works",
Expand Down

0 comments on commit 8a60511

Please sign in to comment.