// +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() }