oracle: handle implicit selections in callees

The types only optimization for callees looked at the type of the
receiver to figure out if it was a dynamic call. If the selection
involves any implicit selections, we cannot be sure that this type
is the one that will actually receive the call.

Fix by working backwards from function signature to find the true
receiver

Change-Id: If79e3de7af33480e37bcf1081abe44bb04914da4
Reviewed-on: https://go-review.googlesource.com/18563
Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
Daniel Morsing 2016-01-13 15:50:34 +00:00
parent 5a2875abe7
commit ae18226edd
4 changed files with 29 additions and 4 deletions

View File

@ -92,12 +92,17 @@ func callees(q *Query) error {
return nil return nil
} }
} else if sel.Kind() == types.MethodVal { } else if sel.Kind() == types.MethodVal {
recvtype := sel.Recv() // Inspect the receiver type of the selected method.
// If it is concrete, the call is statically dispatched.
// (Due to implicit field selections, it is not enough to look
// at sel.Recv(), the type of the actual receiver expression.)
method := sel.Obj().(*types.Func)
recvtype := method.Type().(*types.Signature).Recv().Type()
if !types.IsInterface(recvtype) { if !types.IsInterface(recvtype) {
// static method call // static method call
q.result = &calleesTypesResult{ q.result = &calleesTypesResult{
site: e, site: e,
callee: sel.Obj().(*types.Func), callee: method,
} }
return nil return nil
} }

View File

@ -92,12 +92,17 @@ func callees(q *Query) error {
return nil return nil
} }
} else if sel.Kind() == types.MethodVal { } else if sel.Kind() == types.MethodVal {
recvtype := sel.Recv() // Inspect the receiver type of the selected method.
// If it is concrete, the call is statically dispatched.
// (Due to implicit field selections, it is not enough to look
// at sel.Recv(), the type of the actual receiver expression.)
method := sel.Obj().(*types.Func)
recvtype := method.Type().(*types.Signature).Recv().Type()
if !types.IsInterface(recvtype) { if !types.IsInterface(recvtype) {
// static method call // static method call
q.result = &calleesTypesResult{ q.result = &calleesTypesResult{
site: e, site: e,
callee: sel.Obj().(*types.Func), callee: method,
} }
return nil return nil
} }

View File

@ -83,6 +83,9 @@ func main() {
fmt.Println() // @callees callees-qualified-call "Println" fmt.Println() // @callees callees-qualified-call "Println"
m := new(method) m := new(method)
m.f() // @callees callees-static-method-call "f" m.f() // @callees callees-static-method-call "f"
g := new(embeddedIface)
g.iface = m
g.f() // @callees callees-implicit-selection-method-call "f"
} }
type myint int type myint int
@ -96,6 +99,14 @@ type method int
func (method) f() { func (method) f() {
} }
type embeddedIface struct {
iface
}
type iface interface {
f()
}
var dynamic = func() {} var dynamic = func() {}
func deadcode() { func deadcode() {

View File

@ -96,6 +96,10 @@ this static function call dispatches to:
this static function call dispatches to: this static function call dispatches to:
(main.method).f (main.method).f
-------- @callees callees-implicit-selection-method-call --------
this dynamic method call dispatches to:
(main.method).f
-------- @callers callers-not-a-wrapper -------- -------- @callers callers-not-a-wrapper --------
(main.myint).f is called from these 1 sites: (main.myint).f is called from these 1 sites:
dynamic method call from main.main dynamic method call from main.main