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