From 5f59a771882004c87dd27525faec2369b9bebc08 Mon Sep 17 00:00:00 2001 From: Chris Tarazi Date: Wed, 28 Oct 2020 19:41:06 -0700 Subject: [PATCH 1/2] Fix incorrect godoc on GetFrom Signed-off-by: Chris Tarazi --- value/reflectcache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/value/reflectcache.go b/value/reflectcache.go index 49e6dd16..48473961 100644 --- a/value/reflectcache.go +++ b/value/reflectcache.go @@ -70,7 +70,7 @@ func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool { return f.isOmitEmpty && (safeIsNil(fieldVal) || isZero(fieldVal)) } -// GetUsing returns the field identified by this FieldCacheEntry from the provided struct. +// GetFrom returns the field identified by this FieldCacheEntry from the provided struct. func (f *FieldCacheEntry) GetFrom(structVal reflect.Value) reflect.Value { // field might be nested within 'inline' structs for _, elem := range f.fieldPath { From 005e28fdb3ab7e42168a7ac2f29039ea5aae499a Mon Sep 17 00:00:00 2001 From: Chris Tarazi Date: Thu, 17 Sep 2020 11:32:46 -0700 Subject: [PATCH 2/2] Fix panic on pointer to embedded struct This commit converts an embedded struct into its original type if it is a pointer. Fixes: https://github.com/kubernetes-sigs/structured-merge-diff/issues/172 Signed-off-by: Chris Tarazi --- value/reflectcache.go | 8 ++++++-- value/valuereflect_test.go | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/value/reflectcache.go b/value/reflectcache.go index 48473961..a5a467c0 100644 --- a/value/reflectcache.go +++ b/value/reflectcache.go @@ -74,7 +74,7 @@ func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool { func (f *FieldCacheEntry) GetFrom(structVal reflect.Value) reflect.Value { // field might be nested within 'inline' structs for _, elem := range f.fieldPath { - structVal = structVal.FieldByIndex(elem) + structVal = dereference(structVal).FieldByIndex(elem) } return structVal } @@ -150,7 +150,11 @@ func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fi continue } if isInline { - buildStructCacheEntry(field.Type, infos, append(fieldPath, field.Index)) + e := field.Type + if field.Type.Kind() == reflect.Ptr { + e = field.Type.Elem() + } + buildStructCacheEntry(e, infos, append(fieldPath, field.Index)) continue } info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type} diff --git a/value/valuereflect_test.go b/value/valuereflect_test.go index 5636ba91..08b0ba14 100644 --- a/value/valuereflect_test.go +++ b/value/valuereflect_test.go @@ -237,6 +237,9 @@ type testOmitemptyStruct struct { Noomit *string `json:"noomit"` Omit *string `json:"omit,omitempty"` } +type testEmbeddedStruct struct { + *testBasicStruct `json:",inline"` +} func TestReflectStruct(t *testing.T) { cases := []struct { @@ -281,6 +284,12 @@ func TestReflectStruct(t *testing.T) { expectedMap: map[string]interface{}{"noomit": (*string)(nil)}, expectedUnstructured: map[string]interface{}{"noomit": nil}, }, + { + name: "embedded", + val: testEmbeddedStruct{&testBasicStruct{I: 10, S: "string"}}, + expectedMap: map[string]interface{}{"int": int64(10), "S": "string"}, + expectedUnstructured: map[string]interface{}{"int": int64(10), "S": "string"}, + }, } for _, tc := range cases {