From 1d6d2400d4027025cb8edc86a139c9c581d672f7 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Wed, 11 Oct 2023 17:52:55 -0400 Subject: [PATCH] gotypes: stop directing people to golang.org/x/tools/go/loader It is very obsolete. Use go/packages instead. Also, add a go generate command to weave the README. Fixes golang/go#60593 Change-Id: Ifaf3ffa588dc3e65fb1e96b39b249a9084d66451 Reviewed-on: https://go-review.googlesource.com/c/example/+/534695 Reviewed-by: Robert Findley Run-TryBot: Robert Findley Auto-Submit: Alan Donovan TryBot-Result: Gopher Robot Commit-Queue: Alan Donovan --- go.mod | 8 ++- go.sum | 32 +++-------- gotypes/README.md | 108 +++++++++++++++++++++----------------- gotypes/doc/main.go | 60 ++++++++++++--------- gotypes/gen.go | 3 ++ gotypes/go-types.md | 50 ++++++++++-------- gotypes/hugeparam/main.go | 28 +++++----- gotypes/skeleton/main.go | 17 +++--- 8 files changed, 163 insertions(+), 143 deletions(-) create mode 100644 gotypes/gen.go diff --git a/go.mod b/go.mod index 1996732f..e876fb92 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,10 @@ module golang.org/x/example go 1.18 -require golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0 +require golang.org/x/tools v0.14.0 -require gopkg.in/yaml.v3 v3.0.1 // indirect +require ( + golang.org/x/mod v0.13.0 // indirect + golang.org/x/sys v0.13.0 // indirect + gopkg.in/yaml.v3 v3.0.1 +) diff --git a/go.sum b/go.sum index 114d0dcc..25e95bda 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,11 @@ -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0 h1:iZhiQWrjyEuXG495d9MXkcmhrlxbQyGp0uNBY+YBZDk= -golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gotypes/README.md b/gotypes/README.md index ee12bef9..9923e108 100644 --- a/gotypes/README.md +++ b/gotypes/README.md @@ -86,7 +86,7 @@ constant expressions, as we'll see in -The [`golang.org/x/tools/go/loader` package](https://pkg.go.dev/golang.org/x/tools/go/loader) +The [`golang.org/x/tools/go/packages` package](https://pkg.go.dev/golang.org/x/tools/go/packages) from the `x/tools` repository is a client of the type checker that loads, parses, and type-checks a complete Go program from source code. @@ -2190,13 +2190,11 @@ programs. ``` var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes") -var sizeof = (&types.StdSizes{8, 8}).Sizeof // the sizeof function - -func PrintHugeParams(fset *token.FileSet, info *types.Info, files []*ast.File) { +func PrintHugeParams(fset *token.FileSet, info *types.Info, sizes types.Sizes, files []*ast.File) { checkTuple := func(descr string, tuple *types.Tuple) { for i := 0; i < tuple.Len(); i++ { v := tuple.At(i) - if sz := sizeof(v.Type()); sz > int64(*bytesFlag) { + if sz := sizes.Sizeof(v.Type()); sz > int64(*bytesFlag) { fmt.Printf("%s: %q %s: %s = %d bytes\n", fset.Position(v.Pos()), v.Name(), descr, v.Type(), sz) @@ -2296,25 +2294,28 @@ ran a `go install` or `go build -i` command. -The [`golang.org/tools/x/go/loader` package](https://pkg.go.dev/golang.org/x/tools/go/loader) -provides an alternative `Importer` that addresses -some of these problems. -It loads a complete program from source, performing -[`cgo`](https://golang.org/cmd/cgo/cgo) preprocessing if -necessary, followed by parsing and type-checking. +The [`golang.org/tools/x/go/packages` +package](https://pkg.go.dev/golang.org/x/tools/go/packages) provides +a comprehensive means of loading packages from source. +It runs `go list` to query the project metadata, +performs [`cgo`](https://golang.org/cmd/cgo/cgo) preprocessing if necessary, +reads and parses the source files, +and optionally type-checks each package. +It can load a whole program from source, or load just the initial +packages from source and load all their dependencies from export data. It loads independent packages in parallel to hide I/O latency, and detects and reports import cycles. For each package, it provides the `types.Package` containing the package's lexical environment, the list of `ast.File` syntax trees for each file in the package, the `types.Info` containing -type information for each syntax node, and a list of type errors -associated with that package. -(Please be aware that the `go/loader` package's API is likely to -change before it finally stabilizes.) - - - -The `doc` program below demonstrates a simple use of the loader. +type information for each syntax node, a list of type errors +associated with that package, and other information too. +Since some of this information is more costly to compute, +the API allows you to select which parts you need, +but since this is a tutorial we'll generally request complete +information so that it is easier to explore. + +The `doc` program below demonstrates a simple use of `go/packages`. It is a rudimentary implementation of `go doc` that prints the type, methods, and documentation of the package-level object specified on the command line. @@ -2324,10 +2325,10 @@ Here's an example: ``` $ ./doc net/http File type net/http.File interface{Readdir(count int) ([]os.FileInfo, error); Seek(offset int64, whence int) (int64, error); Stat() (os.FileInfo, error); io.Closer; io.Reader} -/go/src/io/io.go:92:2: method (net/http.File) Close() error -/go/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error) +$GOROOT/src/io/io.go:92:2: method (net/http.File) Close() error +$GOROOT/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error) /go/src/net/http/fs.go:65:2: method (net/http.File) Readdir(count int) ([]os.FileInfo, error) -/go/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error) +$GOROOT/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error) /go/src/net/http/fs.go:67:2: method (net/http.File) Stat() (os.FileInfo, error) A File is returned by a FileSystem's Open method and can be @@ -2340,8 +2341,10 @@ The methods should behave the same as those on an *os.File. Observe that it prints the correct location of each method declaration, even though, due to embedding, some of `http.File`'s methods were declared in another package. -Here's the first part of the program, showing how to load an entire -program starting from the single package, `pkgpath`: +Here's the first part of the program, showing how to load +complete type information including typed syntax, +for a single package `pkgpath`, +plus exported type information for its dependencies. // go get golang.org/x/example/gotypes/doc @@ -2349,24 +2352,28 @@ program starting from the single package, `pkgpath`: ``` pkgpath, name := os.Args[1], os.Args[2] -// The loader loads a complete Go program from source code. -conf := loader.Config{ParserMode: parser.ParseComments} -conf.Import(pkgpath) -lprog, err := conf.Load() +// Load complete type information for the specified packages, +// along with type-annotated syntax. +// Types for dependencies are loaded from export data. +conf := &packages.Config{Mode: packages.LoadSyntax} +pkgs, err := packages.Load(conf, pkgpath) if err != nil { - log.Fatal(err) // load error + log.Fatal(err) // failed to load anything +} +if packages.PrintErrors(pkgs) > 0 { + os.Exit(1) // some packages contained errors } // Find the package and package-level object. -pkg := lprog.Package(pkgpath).Pkg -obj := pkg.Scope().Lookup(name) +pkg := pkgs[0] +obj := pkg.Types.Scope().Lookup(name) if obj == nil { - log.Fatalf("%s.%s not found", pkg.Path(), name) + log.Fatalf("%s.%s not found", pkg.Types.Path(), name) } ``` -Notice that we instructed the parser to retain comments during parsing. +By default, `go/packages`, instructs the parser to retain comments during parsing. The rest of the program prints the output: @@ -2376,20 +2383,26 @@ The rest of the program prints the output: // Print the object and its methods (incl. location of definition). fmt.Println(obj) for _, sel := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { - fmt.Printf("%s: %s\n", lprog.Fset.Position(sel.Obj().Pos()), sel) + fmt.Printf("%s: %s\n", pkg.Fset.Position(sel.Obj().Pos()), sel) } // Find the path from the root of the AST to the object's position. // Walk up to the enclosing ast.Decl for the doc comment. -_, path, _ := lprog.PathEnclosingInterval(obj.Pos(), obj.Pos()) -for _, n := range path { - switch n := n.(type) { - case *ast.GenDecl: - fmt.Println("\n", n.Doc.Text()) - return - case *ast.FuncDecl: - fmt.Println("\n", n.Doc.Text()) - return +for _, file := range pkg.Syntax { + pos := obj.Pos() + if !(file.FileStart <= pos && pos < file.FileEnd) { + continue // not in this file + } + path, _ := astutil.PathEnclosingInterval(file, pos, pos) + for _, n := range path { + switch n := n.(type) { + case *ast.GenDecl: + fmt.Println("\n", n.Doc.Text()) + return + case *ast.FuncDecl: + fmt.Println("\n", n.Doc.Text()) + return + } } } ``` @@ -2535,11 +2548,10 @@ helper function [`astutil.PathEnclosingInterval`](https://pkg.go.dev/golang.org/x/tools/go/ast/astutil#PathEnclosingInterval). It returns the enclosing `ast.Node`, and all its ancestors up to the root of the file. -You must know which file `*ast.File` the `token.Pos` belongs to. -Alternatively, you can search an entire program loaded by the -`loader` package, using -[`(*loader.Program).PathEnclosingInterval`](https://pkg.go.dev/golang.org/x/tools/go/loader#Program.PathEnclosingInterval). - +If you don't know which file `*ast.File` the `token.Pos` belongs to, +you can iterate over the parsed files of the package and quickly test +whether its position falls within the file's range, +from `File.FileStart` to `File.FileEnd`. To map **from an `Object` to its declaring syntax**, call diff --git a/gotypes/doc/main.go b/gotypes/doc/main.go index 3140f473..8e7027f0 100644 --- a/gotypes/doc/main.go +++ b/gotypes/doc/main.go @@ -4,12 +4,11 @@ package main import ( "fmt" "go/ast" - "go/parser" "log" "os" - // TODO: these will use std go/types after Feb 2016 - "golang.org/x/tools/go/loader" + "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/go/packages" "golang.org/x/tools/go/types/typeutil" ) @@ -20,19 +19,23 @@ func main() { //!+part1 pkgpath, name := os.Args[1], os.Args[2] - // The loader loads a complete Go program from source code. - conf := loader.Config{ParserMode: parser.ParseComments} - conf.Import(pkgpath) - lprog, err := conf.Load() + // Load complete type information for the specified packages, + // along with type-annotated syntax. + // Types for dependencies are loaded from export data. + conf := &packages.Config{Mode: packages.LoadSyntax} + pkgs, err := packages.Load(conf, pkgpath) if err != nil { - log.Fatal(err) // load error + log.Fatal(err) // failed to load anything + } + if packages.PrintErrors(pkgs) > 0 { + os.Exit(1) // some packages contained errors } // Find the package and package-level object. - pkg := lprog.Package(pkgpath).Pkg - obj := pkg.Scope().Lookup(name) + pkg := pkgs[0] + obj := pkg.Types.Scope().Lookup(name) if obj == nil { - log.Fatalf("%s.%s not found", pkg.Path(), name) + log.Fatalf("%s.%s not found", pkg.Types.Path(), name) } //!-part1 //!+part2 @@ -40,33 +43,42 @@ func main() { // Print the object and its methods (incl. location of definition). fmt.Println(obj) for _, sel := range typeutil.IntuitiveMethodSet(obj.Type(), nil) { - fmt.Printf("%s: %s\n", lprog.Fset.Position(sel.Obj().Pos()), sel) + fmt.Printf("%s: %s\n", pkg.Fset.Position(sel.Obj().Pos()), sel) } // Find the path from the root of the AST to the object's position. // Walk up to the enclosing ast.Decl for the doc comment. - _, path, _ := lprog.PathEnclosingInterval(obj.Pos(), obj.Pos()) - for _, n := range path { - switch n := n.(type) { - case *ast.GenDecl: - fmt.Println("\n", n.Doc.Text()) - return - case *ast.FuncDecl: - fmt.Println("\n", n.Doc.Text()) - return + for _, file := range pkg.Syntax { + pos := obj.Pos() + if !(file.FileStart <= pos && pos < file.FileEnd) { + continue // not in this file + } + path, _ := astutil.PathEnclosingInterval(file, pos, pos) + for _, n := range path { + switch n := n.(type) { + case *ast.GenDecl: + fmt.Println("\n", n.Doc.Text()) + return + case *ast.FuncDecl: + fmt.Println("\n", n.Doc.Text()) + return + } } } //!-part2 } +// (The $GOROOT below is the actual string that appears in file names +// loaded from export data for packages in the standard library.) + /* //!+output $ ./doc net/http File type net/http.File interface{Readdir(count int) ([]os.FileInfo, error); Seek(offset int64, whence int) (int64, error); Stat() (os.FileInfo, error); io.Closer; io.Reader} -/go/src/io/io.go:92:2: method (net/http.File) Close() error -/go/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error) +$GOROOT/src/io/io.go:92:2: method (net/http.File) Close() error +$GOROOT/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error) /go/src/net/http/fs.go:65:2: method (net/http.File) Readdir(count int) ([]os.FileInfo, error) -/go/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error) +$GOROOT/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error) /go/src/net/http/fs.go:67:2: method (net/http.File) Stat() (os.FileInfo, error) A File is returned by a FileSystem's Open method and can be diff --git a/gotypes/gen.go b/gotypes/gen.go new file mode 100644 index 00000000..bce6efe7 --- /dev/null +++ b/gotypes/gen.go @@ -0,0 +1,3 @@ +//go:generate bash -c "go run ../internal/cmd/weave/weave.go ./go-types.md > README.md" + +package gotypes diff --git a/gotypes/go-types.md b/gotypes/go-types.md index 4cd3d812..ce5a430d 100644 --- a/gotypes/go-types.md +++ b/gotypes/go-types.md @@ -62,7 +62,7 @@ constant expressions, as we'll see in -The [`golang.org/x/tools/go/loader` package](https://pkg.go.dev/golang.org/x/tools/go/loader) +The [`golang.org/x/tools/go/packages` package](https://pkg.go.dev/golang.org/x/tools/go/packages) from the `x/tools` repository is a client of the type checker that loads, parses, and type-checks a complete Go program from source code. @@ -1850,25 +1850,28 @@ ran a `go install` or `go build -i` command. -The [`golang.org/tools/x/go/loader` package](https://pkg.go.dev/golang.org/x/tools/go/loader) -provides an alternative `Importer` that addresses -some of these problems. -It loads a complete program from source, performing -[`cgo`](https://golang.org/cmd/cgo/cgo) preprocessing if -necessary, followed by parsing and type-checking. +The [`golang.org/tools/x/go/packages` +package](https://pkg.go.dev/golang.org/x/tools/go/packages) provides +a comprehensive means of loading packages from source. +It runs `go list` to query the project metadata, +performs [`cgo`](https://golang.org/cmd/cgo/cgo) preprocessing if necessary, +reads and parses the source files, +and optionally type-checks each package. +It can load a whole program from source, or load just the initial +packages from source and load all their dependencies from export data. It loads independent packages in parallel to hide I/O latency, and detects and reports import cycles. For each package, it provides the `types.Package` containing the package's lexical environment, the list of `ast.File` syntax trees for each file in the package, the `types.Info` containing -type information for each syntax node, and a list of type errors -associated with that package. -(Please be aware that the `go/loader` package's API is likely to -change before it finally stabilizes.) - - - -The `doc` program below demonstrates a simple use of the loader. +type information for each syntax node, a list of type errors +associated with that package, and other information too. +Since some of this information is more costly to compute, +the API allows you to select which parts you need, +but since this is a tutorial we'll generally request complete +information so that it is easier to explore. + +The `doc` program below demonstrates a simple use of `go/packages`. It is a rudimentary implementation of `go doc` that prints the type, methods, and documentation of the package-level object specified on the command line. @@ -1881,14 +1884,16 @@ Here's an example: Observe that it prints the correct location of each method declaration, even though, due to embedding, some of `http.File`'s methods were declared in another package. -Here's the first part of the program, showing how to load an entire -program starting from the single package, `pkgpath`: +Here's the first part of the program, showing how to load +complete type information including typed syntax, +for a single package `pkgpath`, +plus exported type information for its dependencies. %include doc/main.go part1 -Notice that we instructed the parser to retain comments during parsing. +By default, `go/packages`, instructs the parser to retain comments during parsing. The rest of the program prints the output: @@ -2035,11 +2040,10 @@ helper function [`astutil.PathEnclosingInterval`](https://pkg.go.dev/golang.org/x/tools/go/ast/astutil#PathEnclosingInterval). It returns the enclosing `ast.Node`, and all its ancestors up to the root of the file. -You must know which file `*ast.File` the `token.Pos` belongs to. -Alternatively, you can search an entire program loaded by the -`loader` package, using -[`(*loader.Program).PathEnclosingInterval`](https://pkg.go.dev/golang.org/x/tools/go/loader#Program.PathEnclosingInterval). - +If you don't know which file `*ast.File` the `token.Pos` belongs to, +you can iterate over the parsed files of the package and quickly test +whether its position falls within the file's range, +from `File.FileStart` to `File.FileEnd`. To map **from an `Object` to its declaring syntax**, call diff --git a/gotypes/hugeparam/main.go b/gotypes/hugeparam/main.go index 80fc47e2..9577a090 100644 --- a/gotypes/hugeparam/main.go +++ b/gotypes/hugeparam/main.go @@ -12,20 +12,19 @@ import ( "go/token" "go/types" "log" + "os" - "golang.org/x/tools/go/loader" + "golang.org/x/tools/go/packages" ) // !+ var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes") -var sizeof = (&types.StdSizes{8, 8}).Sizeof // the sizeof function - -func PrintHugeParams(fset *token.FileSet, info *types.Info, files []*ast.File) { +func PrintHugeParams(fset *token.FileSet, info *types.Info, sizes types.Sizes, files []*ast.File) { checkTuple := func(descr string, tuple *types.Tuple) { for i := 0; i < tuple.Len(); i++ { v := tuple.At(i) - if sz := sizeof(v.Type()); sz > int64(*bytesFlag) { + if sz := sizes.Sizeof(v.Type()); sz > int64(*bytesFlag) { fmt.Printf("%s: %q %s: %s = %d bytes\n", fset.Position(v.Pos()), v.Name(), descr, v.Type(), sz) @@ -54,19 +53,20 @@ func PrintHugeParams(fset *token.FileSet, info *types.Info, files []*ast.File) { func main() { flag.Parse() - // The loader loads a complete Go program from source code. - var conf loader.Config - _, err := conf.FromArgs(flag.Args(), false) + // Load complete type information for the specified packages, + // along with type-annotated syntax and the "sizeof" function. + // Types for dependencies are loaded from export data. + conf := &packages.Config{Mode: packages.LoadSyntax} + pkgs, err := packages.Load(conf, flag.Args()...) if err != nil { - log.Fatal(err) // command syntax error + log.Fatal(err) // failed to load anything } - lprog, err := conf.Load() - if err != nil { - log.Fatal(err) // load error + if packages.PrintErrors(pkgs) > 0 { + os.Exit(1) // some packages contained errors } - for _, info := range lprog.InitialPackages() { - PrintHugeParams(lprog.Fset, &info.Info, info.Files) + for _, pkg := range pkgs { + PrintHugeParams(pkg.Fset, pkg.TypesInfo, pkg.TypesSizes, pkg.Syntax) } } diff --git a/gotypes/skeleton/main.go b/gotypes/skeleton/main.go index 1e6ee827..ab79b2c3 100644 --- a/gotypes/skeleton/main.go +++ b/gotypes/skeleton/main.go @@ -20,7 +20,7 @@ import ( "unicode" "unicode/utf8" - "golang.org/x/tools/go/loader" + "golang.org/x/tools/go/packages" ) const usage = "Usage: skeleton " @@ -76,15 +76,16 @@ func main() { } pkgpath, ifacename, concname := os.Args[1], os.Args[2], os.Args[3] - // The loader loads a complete Go program from source code. - var conf loader.Config - conf.Import(pkgpath) - lprog, err := conf.Load() + // Load only exported type information for the specified package. + conf := &packages.Config{Mode: packages.NeedTypes} + pkgs, err := packages.Load(conf, pkgpath) if err != nil { - log.Fatal(err) // load error + log.Fatal(err) // failed to load anything } - pkg := lprog.Package(pkgpath).Pkg - if err := PrintSkeleton(pkg, ifacename, concname); err != nil { + if packages.PrintErrors(pkgs) > 0 { + os.Exit(1) // some packages contained errors + } + if err := PrintSkeleton(pkgs[0].Types, ifacename, concname); err != nil { log.Fatal(err) } }