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