diff --git a/_fixtures/fncall.go b/_fixtures/fncall.go index dac89fa4..be49ceb6 100644 --- a/_fixtures/fncall.go +++ b/_fixtures/fncall.go @@ -121,6 +121,19 @@ func noreturncall(n int) { return } +type Base struct{ + y int +} + +type Derived struct { + x int + Base +} + +func (b *Base) Method() int { + return b.y +} + func main() { one, two := 1, 2 intslice := []int{1, 2, 3} @@ -142,9 +155,13 @@ func main() { fn2ptrmeth := pa.PRcvr var fn2nil func() + d := &Derived{3, Base{4}} + runtime.Breakpoint() call1(one, two) fn2clos(2) strings.LastIndexByte(stringslice[1], 'w') - fmt.Println(one, two, zero, callpanic, callstacktrace, stringsJoin, intslice, stringslice, comma, a.VRcvr, a.PRcvr, pa, vable_a, vable_pa, pable_pa, fn2clos, fn2glob, fn2valmeth, fn2ptrmeth, fn2nil, ga, escapeArg, a2, square, intcallpanic, onetwothree, curriedAdd, getAStruct, getAStructPtr, getVRcvrableFromAStruct, getPRcvrableFromAStructPtr, getVRcvrableFromAStructPtr, pa2, noreturncall, str) + d.Method() + d.Base.Method() + fmt.Println(one, two, zero, callpanic, callstacktrace, stringsJoin, intslice, stringslice, comma, a.VRcvr, a.PRcvr, pa, vable_a, vable_pa, pable_pa, fn2clos, fn2glob, fn2valmeth, fn2ptrmeth, fn2nil, ga, escapeArg, a2, square, intcallpanic, onetwothree, curriedAdd, getAStruct, getAStructPtr, getVRcvrableFromAStruct, getPRcvrableFromAStructPtr, getVRcvrableFromAStructPtr, pa2, noreturncall, str, d) } diff --git a/pkg/proc/eval.go b/pkg/proc/eval.go index fa24c379..f2b59efd 100644 --- a/pkg/proc/eval.go +++ b/pkg/proc/eval.go @@ -1847,7 +1847,32 @@ func (v *Variable) findMethod(mname string) (*Variable, error) { } return r, nil } + return v.tryFindMethodInEmbeddedFields(mname) +} +func (v *Variable) tryFindMethodInEmbeddedFields(mname string) (*Variable, error) { + structVar := v.maybeDereference() + structVar.Name = v.Name + if structVar.Unreadable != nil { + return structVar, nil + } + switch t := structVar.RealType.(type) { + case *godwarf.StructType: + for _, field := range t.Field { + if field.Embedded { + // Recursively check for promoted fields on the embedded field + embeddedVar, err := structVar.toField(field) + if err != nil { + return nil, err + } + if embeddedMethod, err := embeddedVar.findMethod(mname); err != nil { + return nil, err + } else if embeddedMethod != nil { + return embeddedMethod, nil + } + } + } + } return nil, nil } diff --git a/service/test/variables_test.go b/service/test/variables_test.go index 0034f1c1..fb884747 100644 --- a/service/test/variables_test.go +++ b/service/test/variables_test.go @@ -1181,6 +1181,8 @@ func TestCallFunction(t *testing.T) { {`strings.Join(stringslice, ",")`, []string{`:string:"one,two,three"`}, nil}, {`strings.LastIndexByte(stringslice[1], 'w')`, []string{":int:1"}, nil}, {`strings.LastIndexByte(stringslice[1], 'o')`, []string{":int:2"}, nil}, + {`d.Base.Method()`, []string{ `:int:4` }, nil }, + {`d.Method()`, []string{ `:int:4` }, nil }, } var testcases113 = []testCaseCallFunction{