fix(os/gstructs): strip tag options in TagPriorityName to avoid field name pollution (#4681)

## Summary
- Fix `TagPriorityName()` to strip comma-separated tag options (e.g.,
`omitempty`) from tag values
- Before: `json:"user_name,omitempty"` → field name =
`user_name,omitempty`
- After: `json:"user_name,omitempty"` → field name = `user_name`
- Aligns with `structcache.genPriorityTagAndFieldName()` which already
handles this correctly
- When tag name is empty (e.g., `gconv:",omitempty"`), continues to next
priority tag instead of breaking

## Test plan
- [x] Reproduced bug: `RuleFuncInput.Field` was `user_name,omitempty`
instead of `user_name`
- [x] Verified fix: field name correctly extracted as `user_name`
- [x] Verified fallthrough: `gconv:",omitempty"` + `json:"name"` → uses
`name`
- [x] Existing `Test_Fields_TagPriorityName` passes
- [x] Full `os/gstructs` test suite passes
- [x] Full `util/gvalid` test suite passes
- [x] Full `util/gconv` test suite passes

closes #4665
This commit is contained in:
Jack Ling
2026-02-27 16:14:26 +08:00
committed by GitHub
parent 612e545ae2
commit 0e1cb15dc0
2 changed files with 34 additions and 2 deletions

View File

@ -101,8 +101,12 @@ func (f *Field) TagPriorityName() string {
name := f.Name()
for _, tagName := range gtag.StructTagPriority {
if tagValue := f.Tag(tagName); tagValue != "" {
name = tagValue
break
// Strip tag options after comma, e.g., json:"name,omitempty" -> "name".
tagValue = strings.Split(tagValue, ",")[0]
if tagValue != "" {
name = tagValue
break
}
}
}
return name

View File

@ -546,4 +546,32 @@ func Test_Fields_TagPriorityName(t *testing.T) {
t.Assert(fields[2].TagPriorityName(), "pass_json")
t.Assert(fields[3].TagPriorityName(), "IsMen")
})
// Tag with omitempty option should return name only, not "name,omitempty".
gtest.C(t, func(t *gtest.T) {
type User struct {
Name string `json:"user_name,omitempty"`
Age uint `gconv:"age,string" json:"age_json"`
}
var user *User
fields, _ := gstructs.Fields(gstructs.FieldsInput{
Pointer: user,
RecursiveOption: 0,
})
t.Assert(fields[0].TagPriorityName(), "user_name")
t.Assert(fields[1].TagPriorityName(), "age")
})
// Empty tag name with options (e.g., gconv:",omitempty") should fallthrough to next priority tag.
gtest.C(t, func(t *gtest.T) {
type User struct {
Name string `gconv:",omitempty" json:"name_json"`
Age uint `gconv:",string" param:",omitempty" json:"age_json"`
}
var user *User
fields, _ := gstructs.Fields(gstructs.FieldsInput{
Pointer: user,
RecursiveOption: 0,
})
t.Assert(fields[0].TagPriorityName(), "name_json")
t.Assert(fields[1].TagPriorityName(), "age_json")
})
}