Skip to content

Commit 1d6d240

Browse files
adonovangopherbot
authored andcommitted
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 <[email protected]> Run-TryBot: Robert Findley <[email protected]> Auto-Submit: Alan Donovan <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Commit-Queue: Alan Donovan <[email protected]>
1 parent d9923f6 commit 1d6d240

File tree

8 files changed

+163
-143
lines changed

8 files changed

+163
-143
lines changed

go.mod

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ module golang.org/x/example
22

33
go 1.18
44

5-
require golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0
5+
require golang.org/x/tools v0.14.0
66

7-
require gopkg.in/yaml.v3 v3.0.1 // indirect
7+
require (
8+
golang.org/x/mod v0.13.0 // indirect
9+
golang.org/x/sys v0.13.0 // indirect
10+
gopkg.in/yaml.v3 v3.0.1
11+
)

go.sum

+8-24
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,11 @@
1-
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
2-
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
3-
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
4-
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
5-
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
6-
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
7-
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
8-
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
9-
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
10-
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
11-
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
12-
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
13-
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
14-
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
15-
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
16-
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
17-
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
18-
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
19-
golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0 h1:iZhiQWrjyEuXG495d9MXkcmhrlxbQyGp0uNBY+YBZDk=
20-
golang.org/x/tools v0.0.0-20210112183307-1e6ecd4bf1b0/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
21-
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
22-
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
23-
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
24-
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1+
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
2+
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
3+
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
4+
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
5+
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6+
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
7+
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
8+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
259
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2610
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
2711
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

gotypes/README.md

+60-48
Original file line numberDiff line numberDiff line change
@@ -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)
9090
from the `x/tools` repository is a client of the type
9191
checker that loads, parses, and type-checks a complete Go program from
9292
source code.
@@ -2190,13 +2190,11 @@ programs.
21902190
```
21912191
var 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.
23052306
It loads independent packages in parallel to hide I/O latency, and
23062307
detects and reports import cycles.
23072308
For each package, it provides the `types.Package` containing the
23082309
package's lexical environment, the list of `ast.File` syntax
23092310
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`.
23182319
It is a rudimentary implementation of `go doc` that prints the type,
23192320
methods, and documentation of the package-level object specified on
23202321
the command line.
@@ -2324,10 +2325,10 @@ Here's an example:
23242325
```
23252326
$ ./doc net/http File
23262327
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)
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.
23402341
Observe that it prints the correct location of each method
23412342
declaration, 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
```
23502353
pkgpath, 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)
23562360
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
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)
23632370
if 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.
23702377
The 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).
23772384
fmt.Println(obj)
23782385
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)
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).
25362549
It returns the enclosing `ast.Node`, and all its ancestors up to
25372550
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`.
25432555

25442556

25452557
To map **from an `Object` to its declaring syntax**, call

gotypes/doc/main.go

+36-24
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ package main
44
import (
55
"fmt"
66
"go/ast"
7-
"go/parser"
87
"log"
98
"os"
109

11-
// TODO: these will use std go/types after Feb 2016
12-
"golang.org/x/tools/go/loader"
10+
"golang.org/x/tools/go/ast/astutil"
11+
"golang.org/x/tools/go/packages"
1312
"golang.org/x/tools/go/types/typeutil"
1413
)
1514

@@ -20,53 +19,66 @@ func main() {
2019
//!+part1
2120
pkgpath, name := os.Args[1], os.Args[2]
2221

23-
// The loader loads a complete Go program from source code.
24-
conf := loader.Config{ParserMode: parser.ParseComments}
25-
conf.Import(pkgpath)
26-
lprog, err := conf.Load()
22+
// Load complete type information for the specified packages,
23+
// along with type-annotated syntax.
24+
// Types for dependencies are loaded from export data.
25+
conf := &packages.Config{Mode: packages.LoadSyntax}
26+
pkgs, err := packages.Load(conf, pkgpath)
2727
if err != nil {
28-
log.Fatal(err) // load error
28+
log.Fatal(err) // failed to load anything
29+
}
30+
if packages.PrintErrors(pkgs) > 0 {
31+
os.Exit(1) // some packages contained errors
2932
}
3033

3134
// Find the package and package-level object.
32-
pkg := lprog.Package(pkgpath).Pkg
33-
obj := pkg.Scope().Lookup(name)
35+
pkg := pkgs[0]
36+
obj := pkg.Types.Scope().Lookup(name)
3437
if obj == nil {
35-
log.Fatalf("%s.%s not found", pkg.Path(), name)
38+
log.Fatalf("%s.%s not found", pkg.Types.Path(), name)
3639
}
3740
//!-part1
3841
//!+part2
3942

4043
// Print the object and its methods (incl. location of definition).
4144
fmt.Println(obj)
4245
for _, sel := range typeutil.IntuitiveMethodSet(obj.Type(), nil) {
43-
fmt.Printf("%s: %s\n", lprog.Fset.Position(sel.Obj().Pos()), sel)
46+
fmt.Printf("%s: %s\n", pkg.Fset.Position(sel.Obj().Pos()), sel)
4447
}
4548

4649
// Find the path from the root of the AST to the object's position.
4750
// Walk up to the enclosing ast.Decl for the doc comment.
48-
_, path, _ := lprog.PathEnclosingInterval(obj.Pos(), obj.Pos())
49-
for _, n := range path {
50-
switch n := n.(type) {
51-
case *ast.GenDecl:
52-
fmt.Println("\n", n.Doc.Text())
53-
return
54-
case *ast.FuncDecl:
55-
fmt.Println("\n", n.Doc.Text())
56-
return
51+
for _, file := range pkg.Syntax {
52+
pos := obj.Pos()
53+
if !(file.FileStart <= pos && pos < file.FileEnd) {
54+
continue // not in this file
55+
}
56+
path, _ := astutil.PathEnclosingInterval(file, pos, pos)
57+
for _, n := range path {
58+
switch n := n.(type) {
59+
case *ast.GenDecl:
60+
fmt.Println("\n", n.Doc.Text())
61+
return
62+
case *ast.FuncDecl:
63+
fmt.Println("\n", n.Doc.Text())
64+
return
65+
}
5766
}
5867
}
5968
//!-part2
6069
}
6170

71+
// (The $GOROOT below is the actual string that appears in file names
72+
// loaded from export data for packages in the standard library.)
73+
6274
/*
6375
//!+output
6476
$ ./doc net/http File
6577
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}
66-
/go/src/io/io.go:92:2: method (net/http.File) Close() error
67-
/go/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error)
78+
$GOROOT/src/io/io.go:92:2: method (net/http.File) Close() error
79+
$GOROOT/src/io/io.go:71:2: method (net/http.File) Read(p []byte) (n int, err error)
6880
/go/src/net/http/fs.go:65:2: method (net/http.File) Readdir(count int) ([]os.FileInfo, error)
69-
/go/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error)
81+
$GOROOT/src/net/http/fs.go:66:2: method (net/http.File) Seek(offset int64, whence int) (int64, error)
7082
/go/src/net/http/fs.go:67:2: method (net/http.File) Stat() (os.FileInfo, error)
7183
7284
A File is returned by a FileSystem's Open method and can be

gotypes/gen.go

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//go:generate bash -c "go run ../internal/cmd/weave/weave.go ./go-types.md > README.md"
2+
3+
package gotypes

0 commit comments

Comments
 (0)