Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / ssa / builder_test.go
1 // Copyright 2013 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 ssa_test
6
7 import (
8         "bytes"
9         "go/ast"
10         "go/importer"
11         "go/parser"
12         "go/token"
13         "go/types"
14         "os"
15         "reflect"
16         "sort"
17         "strings"
18         "testing"
19
20         "golang.org/x/tools/go/loader"
21         "golang.org/x/tools/go/ssa"
22         "golang.org/x/tools/go/ssa/ssautil"
23 )
24
25 func isEmpty(f *ssa.Function) bool { return f.Blocks == nil }
26
27 // Tests that programs partially loaded from gc object files contain
28 // functions with no code for the external portions, but are otherwise ok.
29 func TestBuildPackage(t *testing.T) {
30         input := `
31 package main
32
33 import (
34         "bytes"
35         "io"
36         "testing"
37 )
38
39 func main() {
40         var t testing.T
41         t.Parallel()    // static call to external declared method
42         t.Fail()        // static call to promoted external declared method
43         testing.Short() // static call to external package-level function
44
45         var w io.Writer = new(bytes.Buffer)
46         w.Write(nil)    // interface invoke of external declared method
47 }
48 `
49
50         // Parse the file.
51         fset := token.NewFileSet()
52         f, err := parser.ParseFile(fset, "input.go", input, 0)
53         if err != nil {
54                 t.Error(err)
55                 return
56         }
57
58         // Build an SSA program from the parsed file.
59         // Load its dependencies from gc binary export data.
60         mainPkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset,
61                 types.NewPackage("main", ""), []*ast.File{f}, ssa.SanityCheckFunctions)
62         if err != nil {
63                 t.Error(err)
64                 return
65         }
66
67         // The main package, its direct and indirect dependencies are loaded.
68         deps := []string{
69                 // directly imported dependencies:
70                 "bytes", "io", "testing",
71                 // indirect dependencies mentioned by
72                 // the direct imports' export data
73                 "sync", "unicode", "time",
74         }
75
76         prog := mainPkg.Prog
77         all := prog.AllPackages()
78         if len(all) <= len(deps) {
79                 t.Errorf("unexpected set of loaded packages: %q", all)
80         }
81         for _, path := range deps {
82                 pkg := prog.ImportedPackage(path)
83                 if pkg == nil {
84                         t.Errorf("package not loaded: %q", path)
85                         continue
86                 }
87
88                 // External packages should have no function bodies (except for wrappers).
89                 isExt := pkg != mainPkg
90
91                 // init()
92                 if isExt && !isEmpty(pkg.Func("init")) {
93                         t.Errorf("external package %s has non-empty init", pkg)
94                 } else if !isExt && isEmpty(pkg.Func("init")) {
95                         t.Errorf("main package %s has empty init", pkg)
96                 }
97
98                 for _, mem := range pkg.Members {
99                         switch mem := mem.(type) {
100                         case *ssa.Function:
101                                 // Functions at package level.
102                                 if isExt && !isEmpty(mem) {
103                                         t.Errorf("external function %s is non-empty", mem)
104                                 } else if !isExt && isEmpty(mem) {
105                                         t.Errorf("function %s is empty", mem)
106                                 }
107
108                         case *ssa.Type:
109                                 // Methods of named types T.
110                                 // (In this test, all exported methods belong to *T not T.)
111                                 if !isExt {
112                                         t.Fatalf("unexpected name type in main package: %s", mem)
113                                 }
114                                 mset := prog.MethodSets.MethodSet(types.NewPointer(mem.Type()))
115                                 for i, n := 0, mset.Len(); i < n; i++ {
116                                         m := prog.MethodValue(mset.At(i))
117                                         // For external types, only synthetic wrappers have code.
118                                         expExt := !strings.Contains(m.Synthetic, "wrapper")
119                                         if expExt && !isEmpty(m) {
120                                                 t.Errorf("external method %s is non-empty: %s",
121                                                         m, m.Synthetic)
122                                         } else if !expExt && isEmpty(m) {
123                                                 t.Errorf("method function %s is empty: %s",
124                                                         m, m.Synthetic)
125                                         }
126                                 }
127                         }
128                 }
129         }
130
131         expectedCallee := []string{
132                 "(*testing.T).Parallel",
133                 "(*testing.common).Fail",
134                 "testing.Short",
135                 "N/A",
136         }
137         callNum := 0
138         for _, b := range mainPkg.Func("main").Blocks {
139                 for _, instr := range b.Instrs {
140                         switch instr := instr.(type) {
141                         case ssa.CallInstruction:
142                                 call := instr.Common()
143                                 if want := expectedCallee[callNum]; want != "N/A" {
144                                         got := call.StaticCallee().String()
145                                         if want != got {
146                                                 t.Errorf("call #%d from main.main: got callee %s, want %s",
147                                                         callNum, got, want)
148                                         }
149                                 }
150                                 callNum++
151                         }
152                 }
153         }
154         if callNum != 4 {
155                 t.Errorf("in main.main: got %d calls, want %d", callNum, 4)
156         }
157 }
158
159 // TestRuntimeTypes tests that (*Program).RuntimeTypes() includes all necessary types.
160 func TestRuntimeTypes(t *testing.T) {
161         tests := []struct {
162                 input string
163                 want  []string
164         }{
165                 // An exported package-level type is needed.
166                 {`package A; type T struct{}; func (T) f() {}`,
167                         []string{"*p.T", "p.T"},
168                 },
169                 // An unexported package-level type is not needed.
170                 {`package B; type t struct{}; func (t) f() {}`,
171                         nil,
172                 },
173                 // Subcomponents of type of exported package-level var are needed.
174                 {`package C; import "bytes"; var V struct {*bytes.Buffer}`,
175                         []string{"*bytes.Buffer", "*struct{*bytes.Buffer}", "struct{*bytes.Buffer}"},
176                 },
177                 // Subcomponents of type of unexported package-level var are not needed.
178                 {`package D; import "bytes"; var v struct {*bytes.Buffer}`,
179                         nil,
180                 },
181                 // Subcomponents of type of exported package-level function are needed.
182                 {`package E; import "bytes"; func F(struct {*bytes.Buffer}) {}`,
183                         []string{"*bytes.Buffer", "struct{*bytes.Buffer}"},
184                 },
185                 // Subcomponents of type of unexported package-level function are not needed.
186                 {`package F; import "bytes"; func f(struct {*bytes.Buffer}) {}`,
187                         nil,
188                 },
189                 // Subcomponents of type of exported method of uninstantiated unexported type are not needed.
190                 {`package G; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v x`,
191                         nil,
192                 },
193                 // ...unless used by MakeInterface.
194                 {`package G2; import "bytes"; type x struct{}; func (x) G(struct {*bytes.Buffer}) {}; var v interface{} = x{}`,
195                         []string{"*bytes.Buffer", "*p.x", "p.x", "struct{*bytes.Buffer}"},
196                 },
197                 // Subcomponents of type of unexported method are not needed.
198                 {`package I; import "bytes"; type X struct{}; func (X) G(struct {*bytes.Buffer}) {}`,
199                         []string{"*bytes.Buffer", "*p.X", "p.X", "struct{*bytes.Buffer}"},
200                 },
201                 // Local types aren't needed.
202                 {`package J; import "bytes"; func f() { type T struct {*bytes.Buffer}; var t T; _ = t }`,
203                         nil,
204                 },
205                 // ...unless used by MakeInterface.
206                 {`package K; import "bytes"; func f() { type T struct {*bytes.Buffer}; _ = interface{}(T{}) }`,
207                         []string{"*bytes.Buffer", "*p.T", "p.T"},
208                 },
209                 // Types used as operand of MakeInterface are needed.
210                 {`package L; import "bytes"; func f() { _ = interface{}(struct{*bytes.Buffer}{}) }`,
211                         []string{"*bytes.Buffer", "struct{*bytes.Buffer}"},
212                 },
213                 // MakeInterface is optimized away when storing to a blank.
214                 {`package M; import "bytes"; var _ interface{} = struct{*bytes.Buffer}{}`,
215                         nil,
216                 },
217         }
218         for _, test := range tests {
219                 // Parse the file.
220                 fset := token.NewFileSet()
221                 f, err := parser.ParseFile(fset, "input.go", test.input, 0)
222                 if err != nil {
223                         t.Errorf("test %q: %s", test.input[:15], err)
224                         continue
225                 }
226
227                 // Create a single-file main package.
228                 // Load dependencies from gc binary export data.
229                 ssapkg, _, err := ssautil.BuildPackage(&types.Config{Importer: importer.Default()}, fset,
230                         types.NewPackage("p", ""), []*ast.File{f}, ssa.SanityCheckFunctions)
231                 if err != nil {
232                         t.Errorf("test %q: %s", test.input[:15], err)
233                         continue
234                 }
235
236                 var typstrs []string
237                 for _, T := range ssapkg.Prog.RuntimeTypes() {
238                         typstrs = append(typstrs, T.String())
239                 }
240                 sort.Strings(typstrs)
241
242                 if !reflect.DeepEqual(typstrs, test.want) {
243                         t.Errorf("test 'package %s': got %q, want %q",
244                                 f.Name.Name, typstrs, test.want)
245                 }
246         }
247 }
248
249 // TestInit tests that synthesized init functions are correctly formed.
250 // Bare init functions omit calls to dependent init functions and the use of
251 // an init guard. They are useful in cases where the client uses a different
252 // calling convention for init functions, or cases where it is easier for a
253 // client to analyze bare init functions. Both of these aspects are used by
254 // the llgo compiler for simpler integration with gccgo's runtime library,
255 // and to simplify the analysis whereby it deduces which stores to globals
256 // can be lowered to global initializers.
257 func TestInit(t *testing.T) {
258         tests := []struct {
259                 mode        ssa.BuilderMode
260                 input, want string
261         }{
262                 {0, `package A; import _ "errors"; var i int = 42`,
263                         `# Name: A.init
264 # Package: A
265 # Synthetic: package initializer
266 func init():
267 0:                                                                entry P:0 S:2
268         t0 = *init$guard                                                   bool
269         if t0 goto 2 else 1
270 1:                                                           init.start P:1 S:1
271         *init$guard = true:bool
272         t1 = errors.init()                                                   ()
273         *i = 42:int
274         jump 2
275 2:                                                            init.done P:2 S:0
276         return
277
278 `},
279                 {ssa.BareInits, `package B; import _ "errors"; var i int = 42`,
280                         `# Name: B.init
281 # Package: B
282 # Synthetic: package initializer
283 func init():
284 0:                                                                entry P:0 S:0
285         *i = 42:int
286         return
287
288 `},
289         }
290         for _, test := range tests {
291                 // Create a single-file main package.
292                 var conf loader.Config
293                 f, err := conf.ParseFile("<input>", test.input)
294                 if err != nil {
295                         t.Errorf("test %q: %s", test.input[:15], err)
296                         continue
297                 }
298                 conf.CreateFromFiles(f.Name.Name, f)
299
300                 lprog, err := conf.Load()
301                 if err != nil {
302                         t.Errorf("test 'package %s': Load: %s", f.Name.Name, err)
303                         continue
304                 }
305                 prog := ssautil.CreateProgram(lprog, test.mode)
306                 mainPkg := prog.Package(lprog.Created[0].Pkg)
307                 prog.Build()
308                 initFunc := mainPkg.Func("init")
309                 if initFunc == nil {
310                         t.Errorf("test 'package %s': no init function", f.Name.Name)
311                         continue
312                 }
313
314                 var initbuf bytes.Buffer
315                 _, err = initFunc.WriteTo(&initbuf)
316                 if err != nil {
317                         t.Errorf("test 'package %s': WriteTo: %s", f.Name.Name, err)
318                         continue
319                 }
320
321                 if initbuf.String() != test.want {
322                         t.Errorf("test 'package %s': got %s, want %s", f.Name.Name, initbuf.String(), test.want)
323                 }
324         }
325 }
326
327 // TestSyntheticFuncs checks that the expected synthetic functions are
328 // created, reachable, and not duplicated.
329 func TestSyntheticFuncs(t *testing.T) {
330         const input = `package P
331 type T int
332 func (T) f() int
333 func (*T) g() int
334 var (
335         // thunks
336         a = T.f
337         b = T.f
338         c = (struct{T}).f
339         d = (struct{T}).f
340         e = (*T).g
341         f = (*T).g
342         g = (struct{*T}).g
343         h = (struct{*T}).g
344
345         // bounds
346         i = T(0).f
347         j = T(0).f
348         k = new(T).g
349         l = new(T).g
350
351         // wrappers
352         m interface{} = struct{T}{}
353         n interface{} = struct{T}{}
354         o interface{} = struct{*T}{}
355         p interface{} = struct{*T}{}
356         q interface{} = new(struct{T})
357         r interface{} = new(struct{T})
358         s interface{} = new(struct{*T})
359         t interface{} = new(struct{*T})
360 )
361 `
362         // Parse
363         var conf loader.Config
364         f, err := conf.ParseFile("<input>", input)
365         if err != nil {
366                 t.Fatalf("parse: %v", err)
367         }
368         conf.CreateFromFiles(f.Name.Name, f)
369
370         // Load
371         lprog, err := conf.Load()
372         if err != nil {
373                 t.Fatalf("Load: %v", err)
374         }
375
376         // Create and build SSA
377         prog := ssautil.CreateProgram(lprog, 0)
378         prog.Build()
379
380         // Enumerate reachable synthetic functions
381         want := map[string]string{
382                 "(*P.T).g$bound": "bound method wrapper for func (*P.T).g() int",
383                 "(P.T).f$bound":  "bound method wrapper for func (P.T).f() int",
384
385                 "(*P.T).g$thunk":         "thunk for func (*P.T).g() int",
386                 "(P.T).f$thunk":          "thunk for func (P.T).f() int",
387                 "(struct{*P.T}).g$thunk": "thunk for func (*P.T).g() int",
388                 "(struct{P.T}).f$thunk":  "thunk for func (P.T).f() int",
389
390                 "(*P.T).f":          "wrapper for func (P.T).f() int",
391                 "(*struct{*P.T}).f": "wrapper for func (P.T).f() int",
392                 "(*struct{*P.T}).g": "wrapper for func (*P.T).g() int",
393                 "(*struct{P.T}).f":  "wrapper for func (P.T).f() int",
394                 "(*struct{P.T}).g":  "wrapper for func (*P.T).g() int",
395                 "(struct{*P.T}).f":  "wrapper for func (P.T).f() int",
396                 "(struct{*P.T}).g":  "wrapper for func (*P.T).g() int",
397                 "(struct{P.T}).f":   "wrapper for func (P.T).f() int",
398
399                 "P.init": "package initializer",
400         }
401         for fn := range ssautil.AllFunctions(prog) {
402                 if fn.Synthetic == "" {
403                         continue
404                 }
405                 name := fn.String()
406                 wantDescr, ok := want[name]
407                 if !ok {
408                         t.Errorf("got unexpected/duplicate func: %q: %q", name, fn.Synthetic)
409                         continue
410                 }
411                 delete(want, name)
412
413                 if wantDescr != fn.Synthetic {
414                         t.Errorf("(%s).Synthetic = %q, want %q", name, fn.Synthetic, wantDescr)
415                 }
416         }
417         for fn, descr := range want {
418                 t.Errorf("want func: %q: %q", fn, descr)
419         }
420 }
421
422 // TestPhiElimination ensures that dead phis, including those that
423 // participate in a cycle, are properly eliminated.
424 func TestPhiElimination(t *testing.T) {
425         const input = `
426 package p
427
428 func f() error
429
430 func g(slice []int) {
431         for {
432                 for range slice {
433                         // e should not be lifted to a dead φ-node.
434                         e := f()
435                         h(e)
436                 }
437         }
438 }
439
440 func h(error)
441 `
442         // The SSA code for this function should look something like this:
443         // 0:
444         //         jump 1
445         // 1:
446         //         t0 = len(slice)
447         //         jump 2
448         // 2:
449         //         t1 = phi [1: -1:int, 3: t2]
450         //         t2 = t1 + 1:int
451         //         t3 = t2 < t0
452         //         if t3 goto 3 else 1
453         // 3:
454         //         t4 = f()
455         //         t5 = h(t4)
456         //         jump 2
457         //
458         // But earlier versions of the SSA construction algorithm would
459         // additionally generate this cycle of dead phis:
460         //
461         // 1:
462         //         t7 = phi [0: nil:error, 2: t8] #e
463         //         ...
464         // 2:
465         //         t8 = phi [1: t7, 3: t4] #e
466         //         ...
467
468         // Parse
469         var conf loader.Config
470         f, err := conf.ParseFile("<input>", input)
471         if err != nil {
472                 t.Fatalf("parse: %v", err)
473         }
474         conf.CreateFromFiles("p", f)
475
476         // Load
477         lprog, err := conf.Load()
478         if err != nil {
479                 t.Fatalf("Load: %v", err)
480         }
481
482         // Create and build SSA
483         prog := ssautil.CreateProgram(lprog, 0)
484         p := prog.Package(lprog.Package("p").Pkg)
485         p.Build()
486         g := p.Func("g")
487
488         phis := 0
489         for _, b := range g.Blocks {
490                 for _, instr := range b.Instrs {
491                         if _, ok := instr.(*ssa.Phi); ok {
492                                 phis++
493                         }
494                 }
495         }
496         if phis != 1 {
497                 g.WriteTo(os.Stderr)
498                 t.Errorf("expected a single Phi (for the range index), got %d", phis)
499         }
500 }