@@ -86,7 +86,7 @@ constant expressions, as we'll see in
8686
8787
8888
89- The [ ` golang.org/x/tools/go/loader ` package] ( https://pkg.go.dev/golang.org/x/tools/go/loader )
89+ The [ ` golang.org/x/tools/go/packages ` package] ( https://pkg.go.dev/golang.org/x/tools/go/packages )
9090from the ` x/tools ` repository is a client of the type
9191checker that loads, parses, and type-checks a complete Go program from
9292source code.
@@ -2190,13 +2190,11 @@ programs.
21902190```
21912191var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes")
21922192
2193- var sizeof = (&types.StdSizes{8, 8}).Sizeof // the sizeof function
2194-
2195- func PrintHugeParams(fset *token.FileSet, info *types.Info, files []*ast.File) {
2193+ func PrintHugeParams(fset *token.FileSet, info *types.Info, sizes types.Sizes, files []*ast.File) {
21962194 checkTuple := func(descr string, tuple *types.Tuple) {
21972195 for i := 0; i < tuple.Len(); i++ {
21982196 v := tuple.At(i)
2199- if sz := sizeof (v.Type()); sz > int64(*bytesFlag) {
2197+ if sz := sizes.Sizeof (v.Type()); sz > int64(*bytesFlag) {
22002198 fmt.Printf("%s: %q %s: %s = %d bytes\n",
22012199 fset.Position(v.Pos()),
22022200 v.Name(), descr, v.Type(), sz)
@@ -2296,25 +2294,28 @@ ran a `go install` or `go build -i` command.
22962294
22972295
22982296
2299- The [ ` golang.org/tools/x/go/loader ` package] ( https://pkg.go.dev/golang.org/x/tools/go/loader )
2300- provides an alternative ` Importer ` that addresses
2301- some of these problems.
2302- It loads a complete program from source, performing
2303- [ ` cgo ` ] ( https://golang.org/cmd/cgo/cgo ) preprocessing if
2304- necessary, followed by parsing and type-checking.
2297+ The [ ` golang.org/tools/x/go/packages `
2298+ package] ( https://pkg.go.dev/golang.org/x/tools/go/packages ) provides
2299+ a comprehensive means of loading packages from source.
2300+ It runs ` go list ` to query the project metadata,
2301+ performs [ ` cgo ` ] ( https://golang.org/cmd/cgo/cgo ) preprocessing if necessary,
2302+ reads and parses the source files,
2303+ and optionally type-checks each package.
2304+ It can load a whole program from source, or load just the initial
2305+ packages from source and load all their dependencies from export data.
23052306It loads independent packages in parallel to hide I/O latency, and
23062307detects and reports import cycles.
23072308For each package, it provides the ` types.Package ` containing the
23082309package's lexical environment, the list of ` ast.File ` syntax
23092310trees for each file in the package, the ` types.Info ` containing
2310- type information for each syntax node, and a list of type errors
2311- associated with that package.
2312- (Please be aware that the ` go/loader ` package's API is likely to
2313- change before it finally stabilizes.)
2314-
2315-
2316-
2317- The ` doc ` program below demonstrates a simple use of the loader .
2311+ type information for each syntax node, a list of type errors
2312+ associated with that package, and other information too .
2313+ Since some of this information is more costly to compute,
2314+ the API allows you to select which parts you need,
2315+ but since this is a tutorial we'll generally request complete
2316+ information so that it is easier to explore.
2317+
2318+ The ` doc ` program below demonstrates a simple use of ` go/packages ` .
23182319It is a rudimentary implementation of ` go doc ` that prints the type,
23192320methods, and documentation of the package-level object specified on
23202321the command line.
@@ -2324,10 +2325,10 @@ Here's an example:
23242325```
23252326$ ./doc net/http File
23262327type 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}
2327- /go /src/io/io.go:92:2: method (net/http.File) Close() error
2328- /go /src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error)
2328+ $GOROOT /src/io/io.go:92:2: method (net/http.File) Close() error
2329+ $GOROOT /src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error)
23292330/go/src/net/http/fs.go:65:2: method (net/http.File) Readdir(count int) ([]os.FileInfo, error)
2330- /go /src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error)
2331+ $GOROOT /src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error)
23312332/go/src/net/http/fs.go:67:2: method (net/http.File) Stat() (os.FileInfo, error)
23322333
23332334 A File is returned by a FileSystem's Open method and can be
@@ -2340,33 +2341,39 @@ The methods should behave the same as those on an *os.File.
23402341Observe that it prints the correct location of each method
23412342declaration, even though, due to embedding, some of
23422343` http.File ` 's methods were declared in another package.
2343- Here's the first part of the program, showing how to load an entire
2344- program starting from the single package, ` pkgpath ` :
2344+ Here's the first part of the program, showing how to load
2345+ complete type information including typed syntax,
2346+ for a single package ` pkgpath ` ,
2347+ plus exported type information for its dependencies.
23452348
23462349
23472350 // go get golang.org/x/example/gotypes/doc
23482351
23492352```
23502353pkgpath, name := os.Args[1], os.Args[2]
23512354
2352- // The loader loads a complete Go program from source code.
2353- conf := loader.Config{ParserMode: parser.ParseComments}
2354- conf.Import(pkgpath)
2355- lprog, err := conf.Load()
2355+ // Load complete type information for the specified packages,
2356+ // along with type-annotated syntax.
2357+ // Types for dependencies are loaded from export data.
2358+ conf := &packages.Config{Mode: packages.LoadSyntax}
2359+ pkgs, err := packages.Load(conf, pkgpath)
23562360if err != nil {
2357- log.Fatal(err) // load error
2361+ log.Fatal(err) // failed to load anything
2362+ }
2363+ if packages.PrintErrors(pkgs) > 0 {
2364+ os.Exit(1) // some packages contained errors
23582365}
23592366
23602367// Find the package and package-level object.
2361- pkg := lprog.Package(pkgpath).Pkg
2362- obj := pkg.Scope().Lookup(name)
2368+ pkg := pkgs[0]
2369+ obj := pkg.Types. Scope().Lookup(name)
23632370if obj == nil {
2364- log.Fatalf("%s.%s not found", pkg.Path(), name)
2371+ log.Fatalf("%s.%s not found", pkg.Types. Path(), name)
23652372}
23662373```
23672374
23682375
2369- Notice that we instructed the parser to retain comments during parsing.
2376+ By default, ` go/packages ` , instructs the parser to retain comments during parsing.
23702377The rest of the program prints the output:
23712378
23722379
@@ -2376,20 +2383,26 @@ The rest of the program prints the output:
23762383// Print the object and its methods (incl. location of definition).
23772384fmt.Println(obj)
23782385for _, sel := range typeutil.IntuitiveMethodSet(obj.Type(), nil) {
2379- fmt.Printf("%s: %s\n", lprog .Fset.Position(sel.Obj().Pos()), sel)
2386+ fmt.Printf("%s: %s\n", pkg .Fset.Position(sel.Obj().Pos()), sel)
23802387}
23812388
23822389// Find the path from the root of the AST to the object's position.
23832390// Walk up to the enclosing ast.Decl for the doc comment.
2384- _, path, _ := lprog.PathEnclosingInterval(obj.Pos(), obj.Pos())
2385- for _, n := range path {
2386- switch n := n.(type) {
2387- case *ast.GenDecl:
2388- fmt.Println("\n", n.Doc.Text())
2389- return
2390- case *ast.FuncDecl:
2391- fmt.Println("\n", n.Doc.Text())
2392- return
2391+ for _, file := range pkg.Syntax {
2392+ pos := obj.Pos()
2393+ if !(file.FileStart <= pos && pos < file.FileEnd) {
2394+ continue // not in this file
2395+ }
2396+ path, _ := astutil.PathEnclosingInterval(file, pos, pos)
2397+ for _, n := range path {
2398+ switch n := n.(type) {
2399+ case *ast.GenDecl:
2400+ fmt.Println("\n", n.Doc.Text())
2401+ return
2402+ case *ast.FuncDecl:
2403+ fmt.Println("\n", n.Doc.Text())
2404+ return
2405+ }
23932406 }
23942407}
23952408```
@@ -2535,11 +2548,10 @@ helper function
25352548[ ` astutil.PathEnclosingInterval ` ] ( https://pkg.go.dev/golang.org/x/tools/go/ast/astutil#PathEnclosingInterval ) .
25362549It returns the enclosing ` ast.Node ` , and all its ancestors up to
25372550the root of the file.
2538- You must know which file ` *ast.File ` the ` token.Pos ` belongs to.
2539- Alternatively, you can search an entire program loaded by the
2540- ` loader ` package, using
2541- [ ` (*loader.Program).PathEnclosingInterval ` ] ( https://pkg.go.dev/golang.org/x/tools/go/loader#Program.PathEnclosingInterval ) .
2542-
2551+ If you don't know which file ` *ast.File ` the ` token.Pos ` belongs to,
2552+ you can iterate over the parsed files of the package and quickly test
2553+ whether its position falls within the file's range,
2554+ from ` File.FileStart ` to ` File.FileEnd ` .
25432555
25442556
25452557To map ** from an ` Object ` to its declaring syntax** , call
0 commit comments