mirror of
https://github.com/golang/go
synced 2024-11-18 14:54:40 -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 ext۰reflect۰rtype۰MethodByName(a *analysis, cgn *cgnode) {}
|
||||
// ---------- func (*rtype) Method(int) (Method, bool) ----------
|
||||
// ---------- 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
|
||||
}
|
||||
|
||||
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() {
|
||||
//reflectValueCall()
|
||||
reflectTypeInOut()
|
||||
reflectTypeMethodByName()
|
||||
reflectTypeMethod()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user