internal/importers: replace go/build usages with go/packages
This CL is a pure refactoring to replace go/build usage with
golang.org/x/tools/go/packages. This is a preparation for Go
modules.
Updates golang/go#27234
Change-Id: I3e6a30b962da1a64bc43a89a7f02c03d559f86d3
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/189597
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/cmd/gobind/gobind_test.go b/cmd/gobind/gobind_test.go
index 6ff40f7..7cdae3d 100644
--- a/cmd/gobind/gobind_test.go
+++ b/cmd/gobind/gobind_test.go
@@ -30,7 +30,7 @@
{"Go-Testpkg", "go", "golang.org/x/mobile/bind/testdata/testpkg", "", false},
{"Java-Javapkg", "java", "golang.org/x/mobile/bind/testdata/testpkg/javapkg", "android", true},
{"Go-Javapkg", "go", "golang.org/x/mobile/bind/testdata/testpkg/javapkg", "android", true},
- {"Go-Javapkg", "go,java,objc", "golang.org/x/mobile/bind/testdata/cgopkg", "android", false},
+ {"Go-Cgopkg", "go,java,objc", "golang.org/x/mobile/bind/testdata/cgopkg", "android", false},
}
var gobindBin string
@@ -109,10 +109,16 @@
t.Fatal(err)
}
+ gopath, err := exec.Command("go", "env", "GOPATH").Output()
+ if err != nil {
+ t.Fatal(err)
+ }
+
const comment = "This is a comment."
for _, lang := range []string{"java", "objc"} {
cmd := exec.Command(gobindBin, "-lang", lang, "doctest")
- cmd.Env = append(os.Environ(), "GOROOT="+tmpdir)
+ // TODO(hajimehoshi): Enable this test with Go modules.
+ cmd.Env = append(os.Environ(), "GOPATH="+tmpdir+string(filepath.ListSeparator)+string(gopath), "GO111MODULE=off")
out, err := cmd.CombinedOutput()
if err != nil {
t.Errorf("gobind -lang %s failed: %v: %s", lang, err, out)
diff --git a/cmd/gobind/main.go b/cmd/gobind/main.go
index 303938d..3c889d1 100644
--- a/cmd/gobind/main.go
+++ b/cmd/gobind/main.go
@@ -11,7 +11,6 @@
"go/ast"
"go/build"
"go/importer"
- "go/parser"
"go/types"
"io/ioutil"
"log"
@@ -23,6 +22,7 @@
"golang.org/x/mobile/internal/importers"
"golang.org/x/mobile/internal/importers/java"
"golang.org/x/mobile/internal/importers/objc"
+ "golang.org/x/tools/go/packages"
)
var (
@@ -53,17 +53,21 @@
} else {
langs = []string{"go", "java", "objc"}
}
- ctx := build.Default
- if *tags != "" {
- ctx.BuildTags = append(ctx.BuildTags, strings.Split(*tags, ",")...)
+
+ cfg := &packages.Config{
+ Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles |
+ packages.NeedImports | packages.NeedDeps |
+ packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo,
+ BuildFlags: []string{"-tags", *tags},
+
+ // packages.Load invokes `go list` command with `GOOS=android`, but in most cases
+ // go-list cannot find the header files for Android. Suppress this error by
+ // disabling Cgo.
+ Env: append(os.Environ(), "CGO_ENABLED=0"),
}
- var allPkg []*build.Package
- for _, path := range flag.Args() {
- pkg, err := ctx.Import(path, ".", build.ImportComment)
- if err != nil {
- log.Fatalf("package %q: %v", path, err)
- }
- allPkg = append(allPkg, pkg)
+ allPkg, err := packages.Load(cfg, flag.Args()...)
+ if err != nil {
+ log.Fatal(err)
}
jrefs, err := importers.AnalyzePackages(allPkg, "Java/")
if err != nil {
@@ -92,6 +96,12 @@
log.Fatal(err)
}
}
+
+ ctx := build.Default
+ if *tags != "" {
+ ctx.BuildTags = append(ctx.BuildTags, strings.Split(*tags, ",")...)
+ }
+
// Determine GOPATH from go env GOPATH in case the default $HOME/go GOPATH
// is in effect.
if out, err := exec.Command("go", "env", "GOPATH").Output(); err != nil {
@@ -142,16 +152,12 @@
imp := importer.For("source", nil)
for i, pkg := range allPkg {
var err error
- typePkgs[i], err = imp.Import(pkg.ImportPath)
+ typePkgs[i], err = imp.Import(pkg.PkgPath)
if err != nil {
errorf("%v\n", err)
return
}
- astPkgs[i], err = parse(pkg)
- if err != nil {
- errorf("%v\n", err)
- return
- }
+ astPkgs[i] = pkg.Syntax
}
for _, l := range langs {
for i, pkg := range typePkgs {
@@ -162,19 +168,6 @@
}
}
-func parse(pkg *build.Package) ([]*ast.File, error) {
- fileNames := append(append([]string{}, pkg.GoFiles...), pkg.CgoFiles...)
- var files []*ast.File
- for _, name := range fileNames {
- f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, parser.ParseComments)
- if err != nil {
- return nil, err
- }
- files = append(files, f)
- }
- return files, nil
-}
-
var exitStatus = 0
func errorf(format string, args ...interface{}) {
diff --git a/go.mod b/go.mod
index 534449e..a1a0c61 100644
--- a/go.mod
+++ b/go.mod
@@ -5,4 +5,5 @@
require (
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56
golang.org/x/image v0.0.0-20190802002840-cff245a6509b
+ golang.org/x/tools v0.0.0-20190808195139-e713427fea3f
)
diff --git a/go.sum b/go.sum
index 547f4b7..597a296 100644
--- a/go.sum
+++ b/go.sum
@@ -3,7 +3,6 @@
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
-golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -11,8 +10,13 @@
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190808195139-e713427fea3f h1:lSQQYboXWc71s9tnZRRBiMcc9Uc1BPWj3Bzvdk8UQ0Y=
+golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/internal/importers/ast.go b/internal/importers/ast.go
index 7f1759b..fb80014 100644
--- a/internal/importers/ast.go
+++ b/internal/importers/ast.go
@@ -28,14 +28,13 @@
import (
"errors"
"go/ast"
- "go/build"
- "go/parser"
"go/token"
"path"
- "path/filepath"
"sort"
"strconv"
"strings"
+
+ "golang.org/x/tools/go/packages"
)
// References is the result of analyzing a Go file or set of Go packages.
@@ -101,24 +100,19 @@
// AnalyzePackages scans the provided packages for references to packages with the given
// package prefix. The list of unique (package, identifier) pairs is returned
-func AnalyzePackages(pkgs []*build.Package, pkgPrefix string) (*References, error) {
+func AnalyzePackages(pkgs []*packages.Package, pkgPrefix string) (*References, error) {
visitor := newRefsSaver(pkgPrefix)
imp := visitor.importer()
fset := token.NewFileSet()
for _, pkg := range pkgs {
- fileNames := append(append([]string{}, pkg.GoFiles...), pkg.CgoFiles...)
files := make(map[string]*ast.File)
- for _, name := range fileNames {
- f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, name), nil, 0)
- if err != nil {
- return nil, err
- }
- files[name] = f
+ for i, name := range pkg.CompiledGoFiles {
+ files[name] = pkg.Syntax[i]
}
// Ignore errors (from unknown packages)
astpkg, _ := ast.NewPackage(fset, files, imp, nil)
ast.Walk(visitor, astpkg)
- visitor.findEmbeddingStructs(pkg.ImportPath, astpkg)
+ visitor.findEmbeddingStructs(pkg.PkgPath, astpkg)
}
return visitor.References, nil
}