Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / ast / inspector / inspector_test.go
1 package inspector_test
2
3 import (
4         "go/ast"
5         "go/build"
6         "go/parser"
7         "go/token"
8         "log"
9         "path/filepath"
10         "reflect"
11         "strings"
12         "testing"
13
14         "golang.org/x/tools/go/ast/inspector"
15 )
16
17 var netFiles []*ast.File
18
19 func init() {
20         files, err := parseNetFiles()
21         if err != nil {
22                 log.Fatal(err)
23         }
24         netFiles = files
25 }
26
27 func parseNetFiles() ([]*ast.File, error) {
28         pkg, err := build.Default.Import("net", "", 0)
29         if err != nil {
30                 return nil, err
31         }
32         fset := token.NewFileSet()
33         var files []*ast.File
34         for _, filename := range pkg.GoFiles {
35                 filename = filepath.Join(pkg.Dir, filename)
36                 f, err := parser.ParseFile(fset, filename, nil, 0)
37                 if err != nil {
38                         return nil, err
39                 }
40                 files = append(files, f)
41         }
42         return files, nil
43 }
44
45 // TestAllNodes compares Inspector against ast.Inspect.
46 func TestInspectAllNodes(t *testing.T) {
47         inspect := inspector.New(netFiles)
48
49         var nodesA []ast.Node
50         inspect.Nodes(nil, func(n ast.Node, push bool) bool {
51                 if push {
52                         nodesA = append(nodesA, n)
53                 }
54                 return true
55         })
56         var nodesB []ast.Node
57         for _, f := range netFiles {
58                 ast.Inspect(f, func(n ast.Node) bool {
59                         if n != nil {
60                                 nodesB = append(nodesB, n)
61                         }
62                         return true
63                 })
64         }
65         compare(t, nodesA, nodesB)
66 }
67
68 // TestPruning compares Inspector against ast.Inspect,
69 // pruning descent within ast.CallExpr nodes.
70 func TestInspectPruning(t *testing.T) {
71         inspect := inspector.New(netFiles)
72
73         var nodesA []ast.Node
74         inspect.Nodes(nil, func(n ast.Node, push bool) bool {
75                 if push {
76                         nodesA = append(nodesA, n)
77                         _, isCall := n.(*ast.CallExpr)
78                         return !isCall // don't descend into function calls
79                 }
80                 return false
81         })
82         var nodesB []ast.Node
83         for _, f := range netFiles {
84                 ast.Inspect(f, func(n ast.Node) bool {
85                         if n != nil {
86                                 nodesB = append(nodesB, n)
87                                 _, isCall := n.(*ast.CallExpr)
88                                 return !isCall // don't descend into function calls
89                         }
90                         return false
91                 })
92         }
93         compare(t, nodesA, nodesB)
94 }
95
96 func compare(t *testing.T, nodesA, nodesB []ast.Node) {
97         if len(nodesA) != len(nodesB) {
98                 t.Errorf("inconsistent node lists: %d vs %d", len(nodesA), len(nodesB))
99         } else {
100                 for i := range nodesA {
101                         if a, b := nodesA[i], nodesB[i]; a != b {
102                                 t.Errorf("node %d is inconsistent: %T, %T", i, a, b)
103                         }
104                 }
105         }
106 }
107
108 func TestTypeFiltering(t *testing.T) {
109         const src = `package a
110 func f() {
111         print("hi")
112         panic("oops")
113 }
114 `
115         fset := token.NewFileSet()
116         f, _ := parser.ParseFile(fset, "a.go", src, 0)
117         inspect := inspector.New([]*ast.File{f})
118
119         var got []string
120         fn := func(n ast.Node, push bool) bool {
121                 if push {
122                         got = append(got, typeOf(n))
123                 }
124                 return true
125         }
126
127         // no type filtering
128         inspect.Nodes(nil, fn)
129         if want := strings.Fields("File Ident FuncDecl Ident FuncType FieldList BlockStmt ExprStmt CallExpr Ident BasicLit ExprStmt CallExpr Ident BasicLit"); !reflect.DeepEqual(got, want) {
130                 t.Errorf("inspect: got %s, want %s", got, want)
131         }
132
133         // type filtering
134         nodeTypes := []ast.Node{
135                 (*ast.BasicLit)(nil),
136                 (*ast.CallExpr)(nil),
137         }
138         got = nil
139         inspect.Nodes(nodeTypes, fn)
140         if want := strings.Fields("CallExpr BasicLit CallExpr BasicLit"); !reflect.DeepEqual(got, want) {
141                 t.Errorf("inspect: got %s, want %s", got, want)
142         }
143
144         // inspect with stack
145         got = nil
146         inspect.WithStack(nodeTypes, func(n ast.Node, push bool, stack []ast.Node) bool {
147                 if push {
148                         var line []string
149                         for _, n := range stack {
150                                 line = append(line, typeOf(n))
151                         }
152                         got = append(got, strings.Join(line, " "))
153                 }
154                 return true
155         })
156         want := []string{
157                 "File FuncDecl BlockStmt ExprStmt CallExpr",
158                 "File FuncDecl BlockStmt ExprStmt CallExpr BasicLit",
159                 "File FuncDecl BlockStmt ExprStmt CallExpr",
160                 "File FuncDecl BlockStmt ExprStmt CallExpr BasicLit",
161         }
162         if !reflect.DeepEqual(got, want) {
163                 t.Errorf("inspect: got %s, want %s", got, want)
164         }
165 }
166
167 func typeOf(n ast.Node) string {
168         return strings.TrimPrefix(reflect.TypeOf(n).String(), "*ast.")
169 }
170
171 // The numbers show a marginal improvement (ASTInspect/Inspect) of 3.5x,
172 // but a break-even point (NewInspector/(ASTInspect-Inspect)) of about 5
173 // traversals.
174 //
175 // BenchmarkNewInspector   4.5 ms
176 // BenchmarkNewInspect     0.33ms
177 // BenchmarkASTInspect    1.2  ms
178
179 func BenchmarkNewInspector(b *testing.B) {
180         // Measure one-time construction overhead.
181         for i := 0; i < b.N; i++ {
182                 inspector.New(netFiles)
183         }
184 }
185
186 func BenchmarkInspect(b *testing.B) {
187         b.StopTimer()
188         inspect := inspector.New(netFiles)
189         b.StartTimer()
190
191         // Measure marginal cost of traversal.
192         var ndecls, nlits int
193         for i := 0; i < b.N; i++ {
194                 inspect.Preorder(nil, func(n ast.Node) {
195                         switch n.(type) {
196                         case *ast.FuncDecl:
197                                 ndecls++
198                         case *ast.FuncLit:
199                                 nlits++
200                         }
201                 })
202         }
203 }
204
205 func BenchmarkASTInspect(b *testing.B) {
206         var ndecls, nlits int
207         for i := 0; i < b.N; i++ {
208                 for _, f := range netFiles {
209                         ast.Inspect(f, func(n ast.Node) bool {
210                                 switch n.(type) {
211                                 case *ast.FuncDecl:
212                                         ndecls++
213                                 case *ast.FuncLit:
214                                         nlits++
215                                 }
216                                 return true
217                         })
218                 }
219         }
220 }