зеркало из https://github.com/golang/example.git
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 <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> Auto-Submit: Alan Donovan <adonovan@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Commit-Queue: Alan Donovan <adonovan@google.com>
This commit is contained in:
Родитель
d9923f6970
Коммит
1d6d2400d4
8
go.mod
8
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
|
||||
)
|
||||
|
|
32
go.sum
32
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=
|
||||
|
|
|
@ -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.)
|
||||
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 the loader.
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
//go:generate bash -c "go run ../internal/cmd/weave/weave.go ./go-types.md > README.md"
|
||||
|
||||
package gotypes
|
|
@ -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.)
|
||||
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 the loader.
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/tools/go/loader"
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
const usage = "Usage: skeleton <package> <interface> <concrete>"
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче