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
|
// +build ignore
package main
import "reflect"
var zero, a, b int
var false2 bool
func f(p *int, q hasF) *int {
print(p) // @pointsto main.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 main.b
}
// @calls main.reflectValueCall -> main.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 main.b
print(res0.(*bool)) // @pointsto main.false2
print(res0.(hasF)) // @types *T
print(res0.(*T)) // @pointsto new@newT2:19
}
// @calls main.reflectValueCallIndirect -> (reflect.Value).Call$bound
// @calls (reflect.Value).Call$bound -> main.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 (main.T).F | (main.U).F
g, _ := TU.MethodByName("g")
print(reflect.Zero(g.Type)) // @types func(T, int) | func(U, string)
print(g.Func) // @pointsto (main.T).g | (main.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 (main.U).F | (main.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 (main.T).F | (main.T).g
}
func main() {
reflectValueCall()
reflectValueCallIndirect()
reflectTypeInOut()
reflectTypeMethodByName()
reflectTypeMethod()
}
|