return dsymptrOff(s, ot, pkg.Pathsym, 0)
}
-// isExportedField reports whether a struct field is exported.
-// It also returns the package to use for PkgPath for an unexported field.
-func isExportedField(ft *types.Field) (bool, *types.Pkg) {
- if ft.Sym != nil && ft.Embedded == 0 {
- return exportname(ft.Sym.Name), ft.Sym.Pkg
- }
- if ft.Type.Sym != nil &&
- (ft.Type.Sym.Pkg == builtinpkg || !exportname(ft.Type.Sym.Name)) {
- return false, ft.Type.Sym.Pkg
- }
- return true, nil
-}
-
// dnameField dumps a reflect.name for a struct field.
func dnameField(lsym *obj.LSym, ot int, spkg *types.Pkg, ft *types.Field) int {
- var name string
- if ft.Sym != nil {
- name = ft.Sym.Name
- }
- isExported, fpkg := isExportedField(ft)
- if isExported || fpkg == spkg {
- fpkg = nil
+ if !exportname(ft.Sym.Name) && ft.Sym.Pkg != spkg {
+ Fatalf("package mismatch for %v", ft.Sym)
}
- nsym := dname(name, ft.Note, fpkg, isExported)
+ nsym := dname(ft.Sym.Name, ft.Note, nil, exportname(ft.Sym.Name))
return dsymptr(lsym, ot, nsym, 0)
}
n++
}
- ot = dcommontype(lsym, ot, t)
- pkg := localpkg
- if t.Sym != nil {
- pkg = t.Sym.Pkg
- } else {
- // Unnamed type. Grab the package from the first field, if any.
- for _, f := range t.Fields().Slice() {
- if f.Embedded != 0 {
- continue
- }
- pkg = f.Sym.Pkg
+ // All non-exported struct field names within a struct
+ // type must originate from a single package. By
+ // identifying and recording that package within the
+ // struct type descriptor, we can omit that
+ // information from the field descriptors.
+ var spkg *types.Pkg
+ for _, f := range t.Fields().Slice() {
+ if !exportname(f.Sym.Name) {
+ spkg = f.Sym.Pkg
break
}
}
- ot = dgopkgpath(lsym, ot, pkg)
+
+ ot = dcommontype(lsym, ot, t)
+ ot = dgopkgpath(lsym, ot, spkg)
ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
ot = duintptr(lsym, ot, uint64(n))
ot = duintptr(lsym, ot, uint64(n))
for _, f := range t.Fields().Slice() {
// ../../../../runtime/type.go:/structField
- ot = dnameField(lsym, ot, pkg, f)
+ ot = dnameField(lsym, ot, spkg, f)
ot = dsymptr(lsym, ot, dtypesym(f.Type).Linksym(), 0)
offsetAnon := uint64(f.Offset) << 1
if offsetAnon>>1 != uint64(f.Offset) {
}
}
+func TestCanSetField(t *testing.T) {
+ type embed struct{ x, X int }
+ type Embed struct{ x, X int }
+ type S1 struct {
+ embed
+ x, X int
+ }
+ type S2 struct {
+ *embed
+ x, X int
+ }
+ type S3 struct {
+ Embed
+ x, X int
+ }
+ type S4 struct {
+ *Embed
+ x, X int
+ }
+
+ type testCase struct {
+ index []int
+ canSet bool
+ }
+ tests := []struct {
+ val Value
+ cases []testCase
+ }{{
+ val: ValueOf(&S1{}),
+ cases: []testCase{
+ {[]int{0}, false},
+ {[]int{0, 0}, false},
+ {[]int{0, 1}, true},
+ {[]int{1}, false},
+ {[]int{2}, true},
+ },
+ }, {
+ val: ValueOf(&S2{embed: &embed{}}),
+ cases: []testCase{
+ {[]int{0}, false},
+ {[]int{0, 0}, false},
+ {[]int{0, 1}, true},
+ {[]int{1}, false},
+ {[]int{2}, true},
+ },
+ }, {
+ val: ValueOf(&S3{}),
+ cases: []testCase{
+ {[]int{0}, true},
+ {[]int{0, 0}, false},
+ {[]int{0, 1}, true},
+ {[]int{1}, false},
+ {[]int{2}, true},
+ },
+ }, {
+ val: ValueOf(&S4{Embed: &Embed{}}),
+ cases: []testCase{
+ {[]int{0}, true},
+ {[]int{0, 0}, false},
+ {[]int{0, 1}, true},
+ {[]int{1}, false},
+ {[]int{2}, true},
+ },
+ }}
+
+ for _, tt := range tests {
+ t.Run(tt.val.Type().Name(), func(t *testing.T) {
+ for _, tc := range tt.cases {
+ f := tt.val
+ for _, i := range tc.index {
+ if f.Kind() == Ptr {
+ f = f.Elem()
+ }
+ f = f.Field(i)
+ }
+ if got := f.CanSet(); got != tc.canSet {
+ t.Errorf("CanSet() = %v, want %v", got, tc.canSet)
+ }
+ }
+ })
+ }
+}
+
var _i = 7
var valueToStringTests = []pair{
}
func TestFieldPkgPath(t *testing.T) {
+ type x int
typ := TypeOf(struct {
Exported string
unexported string
OtherPkgFields
+ int // issue 21702
+ *x // issue 21122
}{})
type pkgpathTest struct {
{[]int{2}, "", true}, // OtherPkgFields
{[]int{2, 0}, "", false}, // OtherExported
{[]int{2, 1}, "reflect", false}, // otherUnexported
+ {[]int{3}, "reflect_test", true}, // int
+ {[]int{4}, "reflect_test", true}, // *x
})
type localOtherPkgFields OtherPkgFields
f.Name = p.name.name()
f.Anonymous = p.anon()
if !p.name.isExported() {
- f.PkgPath = p.name.pkgPath()
- if f.PkgPath == "" {
- f.PkgPath = t.pkgPath.name()
- }
+ f.PkgPath = t.pkgPath.name()
}
if tag := p.name.tag(); tag != "" {
f.Tag = StructTag(tag)
if len(t.fields) != len(v.fields) {
return false
}
+ if t.pkgPath.name() != v.pkgPath.name() {
+ return false
+ }
for i := range t.fields {
tf := &t.fields[i]
vf := &v.fields[i]
if tf.offsetAnon != vf.offsetAnon {
return false
}
- if !tf.name.isExported() {
- tp := tf.name.pkgPath()
- if tp == "" {
- tp = t.pkgPath.name()
- }
- vp := vf.name.pkgPath()
- if vp == "" {
- vp = v.pkgPath.name()
- }
- if tp != vp {
- return false
- }
- }
}
return true
}