1
2
3
4
5 package ssa_test
6
7 import (
8 "bytes"
9 "fmt"
10 "go/parser"
11 "go/token"
12 "reflect"
13 "sort"
14 "testing"
15
16 "golang.org/x/tools/go/expect"
17 "golang.org/x/tools/go/loader"
18 "golang.org/x/tools/go/ssa"
19 )
20
21
22
23
24
25
26
27
28
29
30
31
32
33 func TestGenericBodies(t *testing.T) {
34 for _, contents := range []string{
35 `
36 package p00
37
38 func f(x int) {
39 var i interface{}
40 print(i, 0) //@ types("interface{}", int)
41 print() //@ types()
42 print(x) //@ types(int)
43 }
44 `,
45 `
46 package p01
47
48 func f[T any](x T) {
49 print(x) //@ types(T)
50 }
51 `,
52 `
53 package p02
54
55 func f[T ~int]() {
56 var x T
57 print(x) //@ types(T)
58 }
59 `,
60 `
61 package p03
62
63 func a[T ~[4]byte](x T) {
64 for k, v := range x {
65 print(x, k, v) //@ types(T, int, byte)
66 }
67 }
68 func b[T ~*[4]byte](x T) {
69 for k, v := range x {
70 print(x, k, v) //@ types(T, int, byte)
71 }
72 }
73 func c[T ~[]byte](x T) {
74 for k, v := range x {
75 print(x, k, v) //@ types(T, int, byte)
76 }
77 }
78 func d[T ~string](x T) {
79 for k, v := range x {
80 print(x, k, v) //@ types(T, int, rune)
81 }
82 }
83 func e[T ~map[int]string](x T) {
84 for k, v := range x {
85 print(x, k, v) //@ types(T, int, string)
86 }
87 }
88 func f[T ~chan string](x T) {
89 for v := range x {
90 print(x, v) //@ types(T, string)
91 }
92 }
93
94 func From() {
95 type A [4]byte
96 print(a[A]) //@ types("func(x p03.A)")
97
98 type B *[4]byte
99 print(b[B]) //@ types("func(x p03.B)")
100
101 type C []byte
102 print(c[C]) //@ types("func(x p03.C)")
103
104 type D string
105 print(d[D]) //@ types("func(x p03.D)")
106
107 type E map[int]string
108 print(e[E]) //@ types("func(x p03.E)")
109
110 type F chan string
111 print(f[F]) //@ types("func(x p03.F)")
112 }
113 `,
114 `
115 package p05
116
117 func f[S any, T ~chan S](x T) {
118 for v := range x {
119 print(x, v) //@ types(T, S)
120 }
121 }
122
123 func From() {
124 type F chan string
125 print(f[string, F]) //@ types("func(x p05.F)")
126 }
127 `,
128 `
129 package p06
130
131 func fibonacci[T ~chan int](c, quit T) {
132 x, y := 0, 1
133 for {
134 select {
135 case c <- x:
136 x, y = y, x+y
137 case <-quit:
138 print(c, quit, x, y) //@ types(T, T, int, int)
139 return
140 }
141 }
142 }
143 func start[T ~chan int](c, quit T) {
144 go func() {
145 for i := 0; i < 10; i++ {
146 print(<-c) //@ types(int)
147 }
148 quit <- 0
149 }()
150 }
151 func From() {
152 type F chan int
153 c := make(F)
154 quit := make(F)
155 print(start[F], c, quit) //@ types("func(c p06.F, quit p06.F)", "p06.F", "p06.F")
156 print(fibonacci[F], c, quit) //@ types("func(c p06.F, quit p06.F)", "p06.F", "p06.F")
157 }
158 `,
159 `
160 package p07
161
162 func f[T ~struct{ x int; y string }](i int) T {
163 u := []T{ T{0, "lorem"}, T{1, "ipsum"}}
164 return u[i]
165 }
166 func From() {
167 type S struct{ x int; y string }
168 print(f[S]) //@ types("func(i int) p07.S")
169 }
170 `,
171 `
172 package p08
173
174 func f[T ~[4]int8](x T, l, h int) []int8 {
175 return x[l:h]
176 }
177 func g[T ~*[4]int16](x T, l, h int) []int16 {
178 return x[l:h]
179 }
180 func h[T ~[]int32](x T, l, h int) T {
181 return x[l:h]
182 }
183 func From() {
184 type F [4]int8
185 type G *[4]int16
186 type H []int32
187 print(f[F](F{}, 0, 0)) //@ types("[]int8")
188 print(g[G](nil, 0, 0)) //@ types("[]int16")
189 print(h[H](nil, 0, 0)) //@ types("p08.H")
190 }
191 `,
192 `
193 package p09
194
195 func h[E any, T ~[]E](x T, l, h int) []E {
196 s := x[l:h]
197 print(s) //@ types("T")
198 return s
199 }
200 func From() {
201 type H []int32
202 print(h[int32, H](nil, 0, 0)) //@ types("[]int32")
203 }
204 `,
205 `
206 package p10
207
208 // Test "make" builtin with different forms on core types and
209 // when capacities are constants or variable.
210 func h[E any, T ~[]E](m, n int) {
211 print(make(T, 3)) //@ types(T)
212 print(make(T, 3, 5)) //@ types(T)
213 print(make(T, m)) //@ types(T)
214 print(make(T, m, n)) //@ types(T)
215 }
216 func i[K comparable, E any, T ~map[K]E](m int) {
217 print(make(T)) //@ types(T)
218 print(make(T, 5)) //@ types(T)
219 print(make(T, m)) //@ types(T)
220 }
221 func j[E any, T ~chan E](m int) {
222 print(make(T)) //@ types(T)
223 print(make(T, 6)) //@ types(T)
224 print(make(T, m)) //@ types(T)
225 }
226 func From() {
227 type H []int32
228 h[int32, H](3, 4)
229 type I map[int8]H
230 i[int8, H, I](5)
231 type J chan I
232 j[I, J](6)
233 }
234 `,
235 `
236 package p11
237
238 func h[T ~[4]int](x T) {
239 print(len(x), cap(x)) //@ types(int, int)
240 }
241 func i[T ~[4]byte | []int | ~chan uint8](x T) {
242 print(len(x), cap(x)) //@ types(int, int)
243 }
244 func j[T ~[4]int | any | map[string]int]() {
245 print(new(T)) //@ types("*T")
246 }
247 func k[T ~[4]int | any | map[string]int](x T) {
248 print(x) //@ types(T)
249 panic(x)
250 }
251 `,
252 `
253 package p12
254
255 func f[E any, F ~func() E](x F) {
256 print(x, x()) //@ types(F, E)
257 }
258 func From() {
259 type T func() int
260 f[int, T](func() int { return 0 })
261 f[int, func() int](func() int { return 1 })
262 }
263 `,
264 `
265 package p13
266
267 func f[E any, M ~map[string]E](m M) {
268 y, ok := m["lorem"]
269 print(m, y, ok) //@ types(M, E, bool)
270 }
271 func From() {
272 type O map[string][]int
273 f(O{"lorem": []int{0, 1, 2, 3}})
274 }
275 `,
276 `
277 package p14
278
279 func a[T interface{ []int64 | [5]int64 }](x T) int64 {
280 print(x, x[2], x[3]) //@ types(T, int64, int64)
281 x[2] = 5
282 return x[3]
283 }
284 func b[T interface{ []byte | string }](x T) byte {
285 print(x, x[3]) //@ types(T, byte)
286 return x[3]
287 }
288 func c[T interface{ []byte }](x T) byte {
289 print(x, x[2], x[3]) //@ types(T, byte, byte)
290 x[2] = 'b'
291 return x[3]
292 }
293 func d[T interface{ map[int]int64 }](x T) int64 {
294 print(x, x[2], x[3]) //@ types(T, int64, int64)
295 x[2] = 43
296 return x[3]
297 }
298 func e[T ~string](t T) {
299 print(t, t[0]) //@ types(T, uint8)
300 }
301 func f[T ~string|[]byte](t T) {
302 print(t, t[0]) //@ types(T, uint8)
303 }
304 func g[T []byte](t T) {
305 print(t, t[0]) //@ types(T, byte)
306 }
307 func h[T ~[4]int|[]int](t T) {
308 print(t, t[0]) //@ types(T, int)
309 }
310 func i[T ~[4]int|*[4]int|[]int](t T) {
311 print(t, t[0]) //@ types(T, int)
312 }
313 func j[T ~[4]int|*[4]int|[]int](t T) {
314 print(t, &t[0]) //@ types(T, "*int")
315 }
316 `,
317 `
318 package p15
319
320 type MyInt int
321 type Other int
322 type MyInterface interface{ foo() }
323
324 // ChangeType tests
325 func ct0(x int) { v := MyInt(x); print(x, v) /*@ types(int, "p15.MyInt")*/ }
326 func ct1[T MyInt | Other, S int ](x S) { v := T(x); print(x, v) /*@ types(S, T)*/ }
327 func ct2[T int, S MyInt | int ](x S) { v := T(x); print(x, v) /*@ types(S, T)*/ }
328 func ct3[T MyInt | Other, S MyInt | int ](x S) { v := T(x) ; print(x, v) /*@ types(S, T)*/ }
329
330 // Convert tests
331 func co0[T int | int8](x MyInt) { v := T(x); print(x, v) /*@ types("p15.MyInt", T)*/}
332 func co1[T int | int8](x T) { v := MyInt(x); print(x, v) /*@ types(T, "p15.MyInt")*/ }
333 func co2[S, T int | int8](x T) { v := S(x); print(x, v) /*@ types(T, S)*/ }
334
335 // MakeInterface tests
336 func mi0[T MyInterface](x T) { v := MyInterface(x); print(x, v) /*@ types(T, "p15.MyInterface")*/ }
337
338 // NewConst tests
339 func nc0[T any]() { v := (*T)(nil); print(v) /*@ types("*T")*/}
340
341 // SliceToArrayPointer
342 func sl0[T *[4]int | *[2]int](x []int) { v := T(x); print(x, v) /*@ types("[]int", T)*/ }
343 func sl1[T *[4]int | *[2]int, S []int](x S) { v := T(x); print(x, v) /*@ types(S, T)*/ }
344 `,
345 `
346 package p16
347
348 func c[T interface{ foo() string }](x T) {
349 print(x, x.foo, x.foo()) /*@ types(T, "func() string", string)*/
350 }
351 `,
352 `
353 package p17
354
355 func eq[T comparable](t T, i interface{}) bool {
356 return t == i
357 }
358 `,
359
360 `
361 package p18
362
363 type S struct{ f int }
364 func c[P *S]() []P { return []P{{f: 1}} }
365 `,
366 `
367 package p19
368
369 func sign[bytes []byte | string](s bytes) (bool, bool) {
370 neg := false
371 if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
372 neg = s[0] == '-'
373 s = s[1:]
374 }
375 return !neg, len(s) > 0
376 }
377 `,
378 `package p20
379
380 func digits[bytes []byte | string](s bytes) bool {
381 for _, c := range []byte(s) {
382 if c < '0' || '9' < c {
383 return false
384 }
385 }
386 return true
387 }
388 `,
389 `
390 package p21
391
392 type E interface{}
393
394 func Foo[T E, PT interface{ *T }]() T {
395 pt := PT(new(T))
396 x := *pt
397 print(x) /*@ types(T)*/
398 return x
399 }
400 `,
401 `
402 package p22
403
404 func f[M any, PM *M](p PM) {
405 var m M
406 *p = m
407 print(m) /*@ types(M)*/
408 print(p) /*@ types(PM)*/
409 }
410 `,
411 `
412 package p23
413
414 type A struct{int}
415 func (*A) Marker() {}
416
417 type B struct{string}
418 func (*B) Marker() {}
419
420 type C struct{float32}
421 func (*C) Marker() {}
422
423 func process[T interface {
424 *A
425 *B
426 *C
427 Marker()
428 }](v T) {
429 v.Marker()
430 a := *(any(v).(*A)); print(a) /*@ types("p23.A")*/
431 b := *(any(v).(*B)); print(b) /*@ types("p23.B")*/
432 c := *(any(v).(*C)); print(c) /*@ types("p23.C")*/
433 }
434 `,
435 `
436 package p24
437
438 func a[T any](f func() [4]T) {
439 x := len(f())
440 print(x) /*@ types("int")*/
441 }
442
443 func b[T [4]any](f func() T) {
444 x := len(f())
445 print(x) /*@ types("int")*/
446 }
447
448 func c[T any](f func() *[4]T) {
449 x := len(f())
450 print(x) /*@ types("int")*/
451 }
452
453 func d[T *[4]any](f func() T) {
454 x := len(f())
455 print(x) /*@ types("int")*/
456 }
457 `,
458 `
459 package p25
460
461 func a[T any]() {
462 var f func() [4]T
463 for i, v := range f() {
464 print(i, v) /*@ types("int", "T")*/
465 }
466 }
467
468 func b[T [4]any](f func() T) {
469 for i, v := range f() {
470 print(i, v) /*@ types("int", "any")*/
471 }
472 }
473
474 func c[T any](f func() *[4]T) {
475 for i, v := range f() {
476 print(i, v) /*@ types("int", "T")*/
477 }
478 }
479
480 func d[T *[4]any](f func() T) {
481 for i, v := range f() {
482 print(i, v) /*@ types("int", "any")*/
483 }
484 }
485 `,
486 `
487 package issue64324
488
489 type bar[T any] interface {
490 Bar(int) T
491 }
492 type foo[T any] interface {
493 bar[[]T]
494 *T
495 }
496 func Foo[T any, F foo[T]](d int) {
497 m := new(T)
498 f := F(m)
499 print(f.Bar(d)) /*@ types("[]T")*/
500 }
501 `, `
502 package issue64324b
503
504 type bar[T any] interface {
505 Bar(int) T
506 }
507 type baz[T any] interface {
508 bar[*int]
509 *int
510 }
511
512 func Baz[I baz[string]](d int) {
513 m := new(int)
514 f := I(m)
515 print(f.Bar(d)) /*@ types("*int")*/
516 }
517 `,
518 } {
519 contents := contents
520 pkgname := packageName(t, contents)
521 t.Run(pkgname, func(t *testing.T) {
522
523 conf := loader.Config{ParserMode: parser.ParseComments}
524 f, err := conf.ParseFile("file.go", contents)
525 if err != nil {
526 t.Fatalf("parse: %v", err)
527 }
528 conf.CreateFromFiles(pkgname, f)
529
530
531 lprog, err := conf.Load()
532 if err != nil {
533 t.Fatalf("Load: %v", err)
534 }
535
536
537 prog := ssa.NewProgram(lprog.Fset, ssa.SanityCheckFunctions)
538 for _, info := range lprog.AllPackages {
539 if info.TransitivelyErrorFree {
540 prog.CreatePackage(info.Pkg, info.Files, &info.Info, info.Importable)
541 }
542 }
543 p := prog.Package(lprog.Package(pkgname).Pkg)
544 p.Build()
545
546
547 notes, err := expect.ExtractGo(prog.Fset, f)
548 if err != nil {
549 t.Errorf("expect.ExtractGo: %v", err)
550 }
551
552
553 probes := callsTo(p, "print")
554 expectations := matchNotes(prog.Fset, notes, probes)
555
556 for call := range probes {
557 if expectations[call] == nil {
558 t.Errorf("Unmatched call: %v", call)
559 }
560 }
561
562
563 for call, note := range expectations {
564 var args []string
565 for _, a := range call.Args {
566 args = append(args, a.Type().String())
567 }
568 if got, want := fmt.Sprint(args), fmt.Sprint(note.Args); got != want {
569 t.Errorf("Arguments to print() were expected to be %q. got %q", want, got)
570 logFunction(t, probes[call])
571 }
572 }
573 })
574 }
575 }
576
577
578
579 func callsTo(p *ssa.Package, fname string) map[*ssa.CallCommon]*ssa.Function {
580 callsites := make(map[*ssa.CallCommon]*ssa.Function)
581 for _, mem := range p.Members {
582 if fn, ok := mem.(*ssa.Function); ok {
583 for _, bb := range fn.Blocks {
584 for _, i := range bb.Instrs {
585 if i, ok := i.(ssa.CallInstruction); ok {
586 call := i.Common()
587 if call.Value.Name() == fname {
588 callsites[call] = fn
589 }
590 }
591 }
592 }
593 }
594 }
595 return callsites
596 }
597
598
599
600 func matchNotes(fset *token.FileSet, notes []*expect.Note, calls map[*ssa.CallCommon]*ssa.Function) map[*ssa.CallCommon]*expect.Note {
601
602 sameLine := func(x, y token.Pos) bool {
603 xp := fset.Position(x)
604 yp := fset.Position(y)
605 return xp.Filename == yp.Filename && xp.Line == yp.Line
606 }
607 expectations := make(map[*ssa.CallCommon]*expect.Note)
608 for call := range calls {
609 for _, note := range notes {
610 if sameLine(call.Pos(), note.Pos) {
611 expectations[call] = note
612 break
613 }
614 }
615 }
616 return expectations
617 }
618
619
620 func TestInstructionString(t *testing.T) {
621
622
623
624
625
626
627
628
629
630
631 const contents = `
632 package p
633
634 //@ instrs("f0", "*ssa.TypeAssert")
635 //@ instrs("f0", "*ssa.Call", "print(nil:interface{}, 0:int)")
636 func f0(x int) { // non-generic smoke test.
637 var i interface{}
638 print(i, 0)
639 }
640
641 //@ instrs("f1", "*ssa.Alloc", "local T (u)")
642 //@ instrs("f1", "*ssa.FieldAddr", "&t0.x [#0]")
643 func f1[T ~struct{ x string }]() T {
644 u := T{"lorem"}
645 return u
646 }
647
648 //@ instrs("f1b", "*ssa.Alloc", "new T (complit)")
649 //@ instrs("f1b", "*ssa.FieldAddr", "&t0.x [#0]")
650 func f1b[T ~struct{ x string }]() *T {
651 u := &T{"lorem"}
652 return u
653 }
654
655 //@ instrs("f2", "*ssa.TypeAssert", "typeassert t0.(interface{})")
656 //@ instrs("f2", "*ssa.Call", "invoke x.foo()")
657 func f2[T interface{ foo() string }](x T) {
658 _ = x.foo
659 _ = x.foo()
660 }
661
662 //@ instrs("f3", "*ssa.TypeAssert", "typeassert t0.(interface{})")
663 //@ instrs("f3", "*ssa.Call", "invoke x.foo()")
664 func f3[T interface{ foo() string; comparable }](x T) {
665 _ = x.foo
666 _ = x.foo()
667 }
668
669 //@ instrs("f4", "*ssa.BinOp", "t1 + 1:int", "t2 < 4:int")
670 //@ instrs("f4", "*ssa.Call", "f()", "print(t2, t4)")
671 func f4[T [4]string](f func() T) {
672 for i, v := range f() {
673 print(i, v)
674 }
675 }
676
677 //@ instrs("f5", "*ssa.Call", "nil:func()()")
678 func f5() {
679 var f func()
680 f()
681 }
682
683 type S struct{ f int }
684
685 //@ instrs("f6", "*ssa.Alloc", "new [1]P (slicelit)", "new S (complit)")
686 //@ instrs("f6", "*ssa.IndexAddr", "&t0[0:int]")
687 //@ instrs("f6", "*ssa.FieldAddr", "&t2.f [#0]")
688 func f6[P *S]() []P { return []P{{f: 1}} }
689
690 //@ instrs("f7", "*ssa.Alloc", "local S (complit)")
691 //@ instrs("f7", "*ssa.FieldAddr", "&t0.f [#0]")
692 func f7[T any, S struct{f T}](x T) S { return S{f: x} }
693
694 //@ instrs("f8", "*ssa.Alloc", "new [1]P (slicelit)", "new struct{f T} (complit)")
695 //@ instrs("f8", "*ssa.IndexAddr", "&t0[0:int]")
696 //@ instrs("f8", "*ssa.FieldAddr", "&t2.f [#0]")
697 func f8[T any, P *struct{f T}](x T) []P { return []P{{f: x}} }
698
699 //@ instrs("f9", "*ssa.Alloc", "new [1]PS (slicelit)", "new S (complit)")
700 //@ instrs("f9", "*ssa.IndexAddr", "&t0[0:int]")
701 //@ instrs("f9", "*ssa.FieldAddr", "&t2.f [#0]")
702 func f9[T any, S struct{f T}, PS *S](x T) {
703 _ = []PS{{f: x}}
704 }
705
706 //@ instrs("f10", "*ssa.FieldAddr", "&t0.x [#0]")
707 //@ instrs("f10", "*ssa.Store", "*t0 = *new(T):T", "*t1 = 4:int")
708 func f10[T ~struct{ x, y int }]() T {
709 var u T
710 u = T{x: 4}
711 return u
712 }
713
714 //@ instrs("f11", "*ssa.FieldAddr", "&t1.y [#1]")
715 //@ instrs("f11", "*ssa.Store", "*t1 = *new(T):T", "*t2 = 5:int")
716 func f11[T ~struct{ x, y int }, PT *T]() PT {
717 var u PT = new(T)
718 *u = T{y: 5}
719 return u
720 }
721
722 //@ instrs("f12", "*ssa.Alloc", "new struct{f T} (complit)")
723 //@ instrs("f12", "*ssa.MakeMap", "make map[P]bool 1:int")
724 func f12[T any, P *struct{f T}](x T) map[P]bool { return map[P]bool{{}: true} }
725
726 //@ instrs("f13", "*ssa.IndexAddr", "&v[0:int]")
727 //@ instrs("f13", "*ssa.Store", "*t0 = 7:int", "*v = *new(A):A")
728 func f13[A [3]int, PA *A](v PA) {
729 *v = A{7}
730 }
731
732 //@ instrs("f14", "*ssa.Call", "invoke t1.Set(0:int)")
733 func f14[T any, PT interface {
734 Set(int)
735 *T
736 }]() {
737 var t T
738 p := PT(&t)
739 p.Set(0)
740 }
741
742 //@ instrs("f15", "*ssa.MakeClosure", "make closure (interface{Set(int); *T}).Set$bound [t1]")
743 func f15[T any, PT interface {
744 Set(int)
745 *T
746 }]() func(int) {
747 var t T
748 p := PT(&t)
749 return p.Set
750 }
751 `
752
753
754 conf := loader.Config{ParserMode: parser.ParseComments}
755 const fname = "p.go"
756 f, err := conf.ParseFile(fname, contents)
757 if err != nil {
758 t.Fatalf("parse: %v", err)
759 }
760 conf.CreateFromFiles("p", f)
761
762
763 lprog, err := conf.Load()
764 if err != nil {
765 t.Fatalf("Load: %v", err)
766 }
767
768
769 prog := ssa.NewProgram(lprog.Fset, ssa.SanityCheckFunctions)
770 for _, info := range lprog.AllPackages {
771 if info.TransitivelyErrorFree {
772 prog.CreatePackage(info.Pkg, info.Files, &info.Info, info.Importable)
773 }
774 }
775 p := prog.Package(lprog.Package("p").Pkg)
776 p.Build()
777
778
779 notes, err := expect.ExtractGo(prog.Fset, f)
780 if err != nil {
781 t.Errorf("expect.ExtractGo: %v", err)
782 }
783
784
785
786
787 type expKey struct {
788 function string
789 kind string
790 }
791 type expValue struct {
792 wants []string
793 matches []string
794 }
795 expectations := make(map[expKey]*expValue)
796 for _, note := range notes {
797 if note.Name == "instrs" {
798 if len(note.Args) < 2 {
799 t.Error("Had @instrs annotation without at least 2 arguments")
800 continue
801 }
802 fn, kind := fmt.Sprint(note.Args[0]), fmt.Sprint(note.Args[1])
803 var wants []string
804 for _, arg := range note.Args[2:] {
805 wants = append(wants, fmt.Sprint(arg))
806 }
807 expectations[expKey{fn, kind}] = &expValue{wants, nil}
808 }
809 }
810
811
812 for _, mem := range p.Members {
813 if fn, ok := mem.(*ssa.Function); ok {
814 for _, bb := range fn.Blocks {
815 for _, i := range bb.Instrs {
816 kind := fmt.Sprintf("%T", i)
817 if e := expectations[expKey{fn.Name(), kind}]; e != nil {
818 e.matches = append(e.matches, i.String())
819 }
820 }
821 }
822 }
823 }
824
825
826 for key, value := range expectations {
827 fn, ok := p.Members[key.function].(*ssa.Function)
828 if !ok {
829 t.Errorf("Expectation on %s does not match a member in %s", key.function, p.Pkg.Name())
830 }
831 got, want := value.matches, value.wants
832 sort.Strings(got)
833 sort.Strings(want)
834 if !reflect.DeepEqual(want, got) {
835 t.Errorf("Within %s wanted instructions of kind %s: %q. got %q", key.function, key.kind, want, got)
836 logFunction(t, fn)
837 }
838 }
839 }
840
841
842
843 func packageName(t testing.TB, content string) string {
844 f, err := parser.ParseFile(token.NewFileSet(), "", content, parser.PackageClauseOnly)
845 if err != nil {
846 t.Fatalf("parsing the file %q failed with error: %s", content, err)
847 }
848 return f.Name.Name
849 }
850
851 func logFunction(t testing.TB, fn *ssa.Function) {
852
853 var buf bytes.Buffer
854 ssa.WriteFunction(&buf, fn)
855 t.Log(buf.String())
856 }
857
View as plain text