1// +build ignore
2
3package main
4
5import "reflect"
6
7var zero, a, b int
8var false2 bool
9
10func f(p *int, q hasF) *int {
11	print(p)      // @pointsto main.a
12	print(q)      // @types *T
13	print(q.(*T)) // @pointsto new@newT1:22
14	return &b
15}
16
17func g(p *bool) (*int, *bool, hasF) {
18	return &b, p, new(T) // @line newT2
19}
20
21func reflectValueCall() {
22	rvf := reflect.ValueOf(f)
23	res := rvf.Call([]reflect.Value{
24		// argument order is not significant:
25		reflect.ValueOf(new(T)), // @line newT1
26		reflect.ValueOf(&a),
27	})
28	print(res[0].Interface())        // @types *int
29	print(res[0].Interface().(*int)) // @pointsto main.b
30}
31
32// @calls main.reflectValueCall -> main.f
33
34func reflectValueCallIndirect() {
35	rvf := reflect.ValueOf(g)
36	call := rvf.Call // kids, don't try this at home
37
38	// Indirect call uses shared contour.
39	//
40	// Also notice that argument position doesn't matter, and args
41	// of inappropriate type (e.g. 'a') are ignored.
42	res := call([]reflect.Value{
43		reflect.ValueOf(&a),
44		reflect.ValueOf(&false2),
45	})
46	res0 := res[0].Interface()
47	print(res0)         // @types *int | *bool | *T
48	print(res0.(*int))  // @pointsto main.b
49	print(res0.(*bool)) // @pointsto main.false2
50	print(res0.(hasF))  // @types *T
51	print(res0.(*T))    // @pointsto new@newT2:19
52}
53
54// @calls main.reflectValueCallIndirect -> (reflect.Value).Call$bound
55// @calls (reflect.Value).Call$bound -> main.g
56
57func reflectTypeInOut() {
58	var f func(float64, bool) (string, int)
59	print(reflect.Zero(reflect.TypeOf(f).In(0)).Interface())    // @types float64
60	print(reflect.Zero(reflect.TypeOf(f).In(1)).Interface())    // @types bool
61	print(reflect.Zero(reflect.TypeOf(f).In(-1)).Interface())   // @types float64 | bool
62	print(reflect.Zero(reflect.TypeOf(f).In(zero)).Interface()) // @types float64 | bool
63
64	print(reflect.Zero(reflect.TypeOf(f).Out(0)).Interface()) // @types string
65	print(reflect.Zero(reflect.TypeOf(f).Out(1)).Interface()) // @types int
66	print(reflect.Zero(reflect.TypeOf(f).Out(2)).Interface()) // @types
67
68	print(reflect.Zero(reflect.TypeOf(3).Out(0)).Interface()) // @types
69}
70
71type hasF interface {
72	F()
73}
74
75type T struct{}
76
77func (T) F()    {}
78func (T) g(int) {}
79
80type U struct{}
81
82func (U) F(int)    {}
83func (U) g(string) {}
84
85type I interface {
86	f()
87}
88
89var nonconst string
90
91func reflectTypeMethodByName() {
92	TU := reflect.TypeOf([]interface{}{T{}, U{}}[0])
93	print(reflect.Zero(TU)) // @types T | U
94
95	F, _ := TU.MethodByName("F")
96	print(reflect.Zero(F.Type)) // @types func(T) | func(U, int)
97	print(F.Func)               // @pointsto (main.T).F | (main.U).F
98
99	g, _ := TU.MethodByName("g")
100	print(reflect.Zero(g.Type)) // @types func(T, int) | func(U, string)
101	print(g.Func)               // @pointsto (main.T).g | (main.U).g
102
103	// Non-literal method names are treated less precisely.
104	U := reflect.TypeOf(U{})
105	X, _ := U.MethodByName(nonconst)
106	print(reflect.Zero(X.Type)) // @types func(U, int) | func(U, string)
107	print(X.Func)               // @pointsto (main.U).F | (main.U).g
108
109	// Interface methods.
110	rThasF := reflect.TypeOf(new(hasF)).Elem()
111	print(reflect.Zero(rThasF)) // @types hasF
112	F2, _ := rThasF.MethodByName("F")
113	print(reflect.Zero(F2.Type)) // @types func()
114	print(F2.Func)               // @pointsto
115
116}
117
118func reflectTypeMethod() {
119	m := reflect.TypeOf(T{}).Method(0)
120	print(reflect.Zero(m.Type)) // @types func(T) | func(T, int)
121	print(m.Func)               // @pointsto (main.T).F | (main.T).g
122}
123
124func main() {
125	reflectValueCall()
126	reflectValueCallIndirect()
127	reflectTypeInOut()
128	reflectTypeMethodByName()
129	reflectTypeMethod()
130}
131