Commit 296b3538 authored by thoeni's avatar thoeni Committed by Russ Cox

encoding/json: don't marshal unexported embedded fields of non struct type

Marshal must process unexported embedded fields of struct type,
looking for exported fields in those structs. However, it must
not process unexported embedded fields of non-struct type.

For example, consider:

    type t1 struct {
        X int
    }
    type t2 int
    type T struct {
        t1
        t2
    }

When considering T, Marshal must process t1 to find t1.X.
Marshal must not process t2, but it was. Fix that.

Fixes #18009

Change-Id: I62ba0b65ba30fd927990e101a26405a9998787a3
Reviewed-on: https://go-review.googlesource.com/33773
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent e2160cc5
...@@ -1093,7 +1093,7 @@ func typeFields(t reflect.Type) []field { ...@@ -1093,7 +1093,7 @@ func typeFields(t reflect.Type) []field {
// Scan f.typ for fields to include. // Scan f.typ for fields to include.
for i := 0; i < f.typ.NumField(); i++ { for i := 0; i < f.typ.NumField(); i++ {
sf := f.typ.Field(i) sf := f.typ.Field(i)
if sf.PkgPath != "" && !sf.Anonymous { // unexported if sf.PkgPath != "" && (!sf.Anonymous || sf.Type.Kind() != reflect.Struct) { // unexported
continue continue
} }
tag := sf.Tag.Get("json") tag := sf.Tag.Get("json")
......
...@@ -273,6 +273,59 @@ func TestAnonymousNonstruct(t *testing.T) { ...@@ -273,6 +273,59 @@ func TestAnonymousNonstruct(t *testing.T) {
} }
} }
type unexportedIntType int
type MyStructWithUnexportedIntType struct {
unexportedIntType
}
func TestAnonymousNonstructWithUnexportedType(t *testing.T) {
a := MyStructWithUnexportedIntType{11}
const want = `{}`
b, err := Marshal(a)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got := string(b); got != want {
t.Errorf("got %q, want %q", got, want)
}
}
type MyStructContainingUnexportedStruct struct {
unexportedStructType1
unexportedIntType
}
type unexportedStructType1 struct {
ExportedIntType1
unexportedIntType
unexportedStructType2
}
type unexportedStructType2 struct {
ExportedIntType2
unexportedIntType
}
type ExportedIntType1 int
type ExportedIntType2 int
func TestUnexportedAnonymousStructWithExportedType(t *testing.T) {
s2 := unexportedStructType2{3, 4}
s1 := unexportedStructType1{1, 2, s2}
a := MyStructContainingUnexportedStruct{s1, 6}
const want = `{"ExportedIntType1":1,"ExportedIntType2":3}`
b, err := Marshal(a)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got := string(b); got != want {
t.Errorf("got %q, want %q", got, want)
}
}
type BugA struct { type BugA struct {
S string S string
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment