From ae18226edd6df820ca562ef374e4441e6f8f5145 Mon Sep 17 00:00:00 2001 From: Daniel Morsing Date: Wed, 13 Jan 2016 15:50:34 +0000 Subject: [PATCH] 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 --- oracle/callees.go | 9 +++++++-- oracle/callees14.go | 9 +++++++-- oracle/testdata/src/calls/main.go | 11 +++++++++++ oracle/testdata/src/calls/main.golden | 4 ++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/oracle/callees.go b/oracle/callees.go index 3029eed2..06c2c15e 100644 --- a/oracle/callees.go +++ b/oracle/callees.go @@ -92,12 +92,17 @@ func callees(q *Query) error { return nil } } 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) { // static method call q.result = &calleesTypesResult{ site: e, - callee: sel.Obj().(*types.Func), + callee: method, } return nil } diff --git a/oracle/callees14.go b/oracle/callees14.go index ef4d560b..b6d0ffeb 100644 --- a/oracle/callees14.go +++ b/oracle/callees14.go @@ -92,12 +92,17 @@ func callees(q *Query) error { return nil } } 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) { // static method call q.result = &calleesTypesResult{ site: e, - callee: sel.Obj().(*types.Func), + callee: method, } return nil } diff --git a/oracle/testdata/src/calls/main.go b/oracle/testdata/src/calls/main.go index 54bb8959..849fb6ed 100644 --- a/oracle/testdata/src/calls/main.go +++ b/oracle/testdata/src/calls/main.go @@ -83,6 +83,9 @@ func main() { fmt.Println() // @callees callees-qualified-call "Println" m := new(method) 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 @@ -96,6 +99,14 @@ type method int func (method) f() { } +type embeddedIface struct { + iface +} + +type iface interface { + f() +} + var dynamic = func() {} func deadcode() { diff --git a/oracle/testdata/src/calls/main.golden b/oracle/testdata/src/calls/main.golden index b5e65477..9159cd60 100644 --- a/oracle/testdata/src/calls/main.golden +++ b/oracle/testdata/src/calls/main.golden @@ -96,6 +96,10 @@ this static function call dispatches to: this static function call dispatches to: (main.method).f +-------- @callees callees-implicit-selection-method-call -------- +this dynamic method call dispatches to: + (main.method).f + -------- @callers callers-not-a-wrapper -------- (main.myint).f is called from these 1 sites: dynamic method call from main.main