@@ -86,7 +86,7 @@ constant expressions, as we'll see in
86
86
87
87
88
88
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 )
90
90
from the ` x/tools ` repository is a client of the type
91
91
checker that loads, parses, and type-checks a complete Go program from
92
92
source code.
@@ -2190,13 +2190,11 @@ programs.
2190
2190
```
2191
2191
var bytesFlag = flag.Int("bytes", 48, "maximum parameter size in bytes")
2192
2192
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) {
2196
2194
checkTuple := func(descr string, tuple *types.Tuple) {
2197
2195
for i := 0; i < tuple.Len(); i++ {
2198
2196
v := tuple.At(i)
2199
- if sz := sizeof (v.Type()); sz > int64(*bytesFlag) {
2197
+ if sz := sizes.Sizeof (v.Type()); sz > int64(*bytesFlag) {
2200
2198
fmt.Printf("%s: %q %s: %s = %d bytes\n",
2201
2199
fset.Position(v.Pos()),
2202
2200
v.Name(), descr, v.Type(), sz)
@@ -2296,25 +2294,28 @@ ran a `go install` or `go build -i` command.
2296
2294
2297
2295
2298
2296
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.
2305
2306
It loads independent packages in parallel to hide I/O latency, and
2306
2307
detects and reports import cycles.
2307
2308
For each package, it provides the ` types.Package ` containing the
2308
2309
package's lexical environment, the list of ` ast.File ` syntax
2309
2310
trees 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 ` .
2318
2319
It is a rudimentary implementation of ` go doc ` that prints the type,
2319
2320
methods, and documentation of the package-level object specified on
2320
2321
the command line.
@@ -2324,10 +2325,10 @@ Here's an example:
2324
2325
```
2325
2326
$ ./doc net/http File
2326
2327
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}
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)
2329
2330
/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)
2331
2332
/go/src/net/http/fs.go:67:2: method (net/http.File) Stat() (os.FileInfo, error)
2332
2333
2333
2334
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.
2340
2341
Observe that it prints the correct location of each method
2341
2342
declaration, even though, due to embedding, some of
2342
2343
` 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.
2345
2348
2346
2349
2347
2350
// go get golang.org/x/example/gotypes/doc
2348
2351
2349
2352
```
2350
2353
pkgpath, name := os.Args[1], os.Args[2]
2351
2354
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)
2356
2360
if 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
2358
2365
}
2359
2366
2360
2367
// 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)
2363
2370
if obj == nil {
2364
- log.Fatalf("%s.%s not found", pkg.Path(), name)
2371
+ log.Fatalf("%s.%s not found", pkg.Types. Path(), name)
2365
2372
}
2366
2373
```
2367
2374
2368
2375
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.
2370
2377
The rest of the program prints the output:
2371
2378
2372
2379
@@ -2376,20 +2383,26 @@ The rest of the program prints the output:
2376
2383
// Print the object and its methods (incl. location of definition).
2377
2384
fmt.Println(obj)
2378
2385
for _, 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)
2380
2387
}
2381
2388
2382
2389
// Find the path from the root of the AST to the object's position.
2383
2390
// 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
+ }
2393
2406
}
2394
2407
}
2395
2408
```
@@ -2535,11 +2548,10 @@ helper function
2535
2548
[ ` astutil.PathEnclosingInterval ` ] ( https://pkg.go.dev/golang.org/x/tools/go/ast/astutil#PathEnclosingInterval ) .
2536
2549
It returns the enclosing ` ast.Node ` , and all its ancestors up to
2537
2550
the 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 ` .
2543
2555
2544
2556
2545
2557
To map ** from an ` Object ` to its declaring syntax** , call
0 commit comments