aboutsummaryrefslogtreecommitdiff
path: root/go/pointer/testdata/funcreflect.go
blob: 2b4315ba5554045ba30d39cbf25aec4cd9342570 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//go:build ignore
// +build ignore

package main

import "reflect"

var zero, a, b int
var false2 bool

func f(p *int, q hasF) *int {
	print(p)      // @pointsto command-line-arguments.a
	print(q)      // @types *T
	print(q.(*T)) // @pointsto new@newT1:22
	return &b
}

func g(p *bool) (*int, *bool, hasF) {
	return &b, p, new(T) // @line newT2
}

func reflectValueCall() {
	rvf := reflect.ValueOf(f)
	res := rvf.Call([]reflect.Value{
		// argument order is not significant:
		reflect.ValueOf(new(T)), // @line newT1
		reflect.ValueOf(&a),
	})
	print(res[0].Interface())        // @types *int
	print(res[0].Interface().(*int)) // @pointsto command-line-arguments.b
}

// @calls command-line-arguments.reflectValueCall -> command-line-arguments.f

func reflectValueCallIndirect() {
	rvf := reflect.ValueOf(g)
	call := rvf.Call // kids, don't try this at home

	// Indirect call uses shared contour.
	//
	// Also notice that argument position doesn't matter, and args
	// of inappropriate type (e.g. 'a') are ignored.
	res := call([]reflect.Value{
		reflect.ValueOf(&a),
		reflect.ValueOf(&false2),
	})
	res0 := res[0].Interface()
	print(res0)         // @types *int | *bool | *T
	print(res0.(*int))  // @pointsto command-line-arguments.b
	print(res0.(*bool)) // @pointsto command-line-arguments.false2
	print(res0.(hasF))  // @types *T
	print(res0.(*T))    // @pointsto new@newT2:19
}

// @calls command-line-arguments.reflectValueCallIndirect -> (reflect.Value).Call$bound
// @calls (reflect.Value).Call$bound -> command-line-arguments.g

func reflectTypeInOut() {
	var f func(float64, bool) (string, int)
	print(reflect.Zero(reflect.TypeOf(f).In(0)).Interface())    // @types float64
	print(reflect.Zero(reflect.TypeOf(f).In(1)).Interface())    // @types bool
	print(reflect.Zero(reflect.TypeOf(f).In(-1)).Interface())   // @types float64 | bool
	print(reflect.Zero(reflect.TypeOf(f).In(zero)).Interface()) // @types float64 | bool

	print(reflect.Zero(reflect.TypeOf(f).Out(0)).Interface()) // @types string
	print(reflect.Zero(reflect.TypeOf(f).Out(1)).Interface()) // @types int
	print(reflect.Zero(reflect.TypeOf(f).Out(2)).Interface()) // @types

	print(reflect.Zero(reflect.TypeOf(3).Out(0)).Interface()) // @types
}

type hasF interface {
	F()
}

type T struct{}

func (T) F()    {}
func (T) g(int) {}

type U struct{}

func (U) F(int)    {}
func (U) g(string) {}

type I interface {
	f()
}

var nonconst string

func reflectTypeMethodByName() {
	TU := reflect.TypeOf([]interface{}{T{}, U{}}[0])
	print(reflect.Zero(TU)) // @types T | U

	F, _ := TU.MethodByName("F")
	print(reflect.Zero(F.Type)) // @types func(T) | func(U, int)
	print(F.Func)               // @pointsto (command-line-arguments.T).F | (command-line-arguments.U).F

	g, _ := TU.MethodByName("g")
	print(reflect.Zero(g.Type)) // @types func(T, int) | func(U, string)
	print(g.Func)               // @pointsto (command-line-arguments.T).g | (command-line-arguments.U).g

	// Non-literal method names are treated less precisely.
	U := reflect.TypeOf(U{})
	X, _ := U.MethodByName(nonconst)
	print(reflect.Zero(X.Type)) // @types func(U, int) | func(U, string)
	print(X.Func)               // @pointsto (command-line-arguments.U).F | (command-line-arguments.U).g

	// Interface methods.
	rThasF := reflect.TypeOf(new(hasF)).Elem()
	print(reflect.Zero(rThasF)) // @types hasF
	F2, _ := rThasF.MethodByName("F")
	print(reflect.Zero(F2.Type)) // @types func()
	print(F2.Func)               // @pointsto

}

func reflectTypeMethod() {
	m := reflect.TypeOf(T{}).Method(0)
	print(reflect.Zero(m.Type)) // @types func(T) | func(T, int)
	print(m.Func)               // @pointsto (command-line-arguments.T).F | (command-line-arguments.T).g
}

func main() {
	reflectValueCall()
	reflectValueCallIndirect()
	reflectTypeInOut()
	reflectTypeMethodByName()
	reflectTypeMethod()
}