mirror of
https://github.com/golang/go
synced 2024-11-18 19:34:41 -07:00
go.tools/pointer: support reflect.Method{,ByName}.
R=crawshaw CC=golang-dev https://golang.org/cl/14589043
This commit is contained in:
parent
3edc3b18a9
commit
9c8d9fe736
@ -906,5 +906,100 @@ func ext۰reflect۰rtype۰Key(a *analysis, cgn *cgnode) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func ext۰reflect۰rtype۰Method(a *analysis, cgn *cgnode) {}
|
// ---------- func (*rtype) Method(int) (Method, bool) ----------
|
||||||
func ext۰reflect۰rtype۰MethodByName(a *analysis, cgn *cgnode) {}
|
// ---------- func (*rtype) MethodByName(string) (Method, bool) ----------
|
||||||
|
|
||||||
|
// result = MethodByName(t, name)
|
||||||
|
// result = Method(t, _)
|
||||||
|
type rtypeMethodByNameConstraint struct {
|
||||||
|
cgn *cgnode
|
||||||
|
name string // name of method; "" for unknown
|
||||||
|
t nodeid // (ptr)
|
||||||
|
result nodeid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *rtypeMethodByNameConstraint) String() string {
|
||||||
|
return fmt.Sprintf("n%d = (*reflect.rtype).MethodByName(n%d, %q)", c.result, c.t, c.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *rtypeMethodByNameConstraint) ptr() nodeid {
|
||||||
|
return c.t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *rtypeMethodByNameConstraint) addMethod(a *analysis, meth *types.Selection) {
|
||||||
|
// type Method struct {
|
||||||
|
// 0 __identity__
|
||||||
|
// 1 Name string
|
||||||
|
// 2 PkgPath string
|
||||||
|
// 3 Type Type
|
||||||
|
// 4 Func Value
|
||||||
|
// 5 Index int
|
||||||
|
// }
|
||||||
|
fn := a.prog.Method(meth)
|
||||||
|
|
||||||
|
// a.offsetOf(Type) is 3.
|
||||||
|
if id := c.result + 3; a.addLabel(id, a.makeRtype(changeRecv(fn.Signature))) {
|
||||||
|
a.addWork(id)
|
||||||
|
}
|
||||||
|
// a.offsetOf(Func) is 4.
|
||||||
|
if id := c.result + 4; a.addLabel(id, a.objectNode(nil, fn)) {
|
||||||
|
a.addWork(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// changeRecv returns sig with Recv prepended to Params().
|
||||||
|
func changeRecv(sig *types.Signature) *types.Signature {
|
||||||
|
params := sig.Params()
|
||||||
|
n := params.Len()
|
||||||
|
p2 := make([]*types.Var, n+1)
|
||||||
|
p2[0] = sig.Recv()
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
p2[i+1] = params.At(i)
|
||||||
|
}
|
||||||
|
return types.NewSignature(nil, nil, types.NewTuple(p2...), sig.Results(), sig.IsVariadic())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *rtypeMethodByNameConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
|
for tObj := range delta {
|
||||||
|
T := a.nodes[tObj].obj.data.(types.Type)
|
||||||
|
|
||||||
|
// We don't use Lookup(c.name) when c.name != "" to avoid
|
||||||
|
// ambiguity: >1 unexported methods could match.
|
||||||
|
mset := T.MethodSet()
|
||||||
|
for i, n := 0, mset.Len(); i < n; i++ {
|
||||||
|
sel := mset.At(i)
|
||||||
|
if c.name == "" || c.name == sel.Obj().Name() {
|
||||||
|
c.addMethod(a, sel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰rtype۰MethodByName(a *analysis, cgn *cgnode) {
|
||||||
|
// If we have access to the callsite,
|
||||||
|
// and the argument is a string constant,
|
||||||
|
// return only that method.
|
||||||
|
var name string
|
||||||
|
if site := cgn.callersite; site != nil {
|
||||||
|
if c, ok := site.instr.Common().Args[0].(*ssa.Const); ok {
|
||||||
|
name = exact.StringVal(c.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.addConstraint(&rtypeMethodByNameConstraint{
|
||||||
|
cgn: cgn,
|
||||||
|
name: name,
|
||||||
|
t: a.funcParams(cgn.obj),
|
||||||
|
result: a.funcResults(cgn.obj),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰reflect۰rtype۰Method(a *analysis, cgn *cgnode) {
|
||||||
|
// No-one ever calls Method with a constant argument,
|
||||||
|
// so we don't specialize that case.
|
||||||
|
a.addConstraint(&rtypeMethodByNameConstraint{
|
||||||
|
cgn: cgn,
|
||||||
|
t: a.funcParams(cgn.obj),
|
||||||
|
result: a.funcResults(cgn.obj),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
39
pointer/testdata/funcreflect.go
vendored
39
pointer/testdata/funcreflect.go
vendored
@ -38,7 +38,46 @@ func reflectTypeInOut() {
|
|||||||
print(reflect.Zero(reflect.TypeOf(3).Out(0)).Interface()) // @types
|
print(reflect.Zero(reflect.TypeOf(3).Out(0)).Interface()) // @types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type T struct{}
|
||||||
|
|
||||||
|
func (T) F() {}
|
||||||
|
func (T) g(int) {}
|
||||||
|
|
||||||
|
type U struct{}
|
||||||
|
|
||||||
|
func (U) F(int) {}
|
||||||
|
func (U) g(string) {}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
func main() {
|
||||||
//reflectValueCall()
|
//reflectValueCall()
|
||||||
reflectTypeInOut()
|
reflectTypeInOut()
|
||||||
|
reflectTypeMethodByName()
|
||||||
|
reflectTypeMethod()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user