Skip to content

Commit e3324a4

Browse files
committed
cmd/vet: diagnose non-space-separated struct tag like json:"x",xml:"y"
This is not strictly illegal but it probably should be (too late) and doesn't mean what it looks like it means: the second key-value pair has the key ",xml". Fixes #14466. Change-Id: I174bccc23fd28affeb87f57f77c6591634ade641 Reviewed-on: https://go-review.googlesource.com/32031 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rob Pike <[email protected]> Reviewed-by: Quentin Smith <[email protected]>
1 parent 3202aa7 commit e3324a4

File tree

2 files changed

+15
-6
lines changed

2 files changed

+15
-6
lines changed

src/cmd/vet/structtag.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func checkCanonicalFieldTag(f *File, field *ast.Field, seen *map[[2]string]token
4646

4747
if err := validateStructTag(tag); err != nil {
4848
raw, _ := strconv.Unquote(field.Tag.Value) // field.Tag.Value is known to be a quoted string
49-
f.Badf(field.Pos(), "struct field tag %q not compatible with reflect.StructTag.Get: %s", raw, err)
49+
f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", raw, err)
5050
}
5151

5252
for _, key := range checkTagDups {
@@ -91,6 +91,7 @@ var (
9191
errTagSyntax = errors.New("bad syntax for struct tag pair")
9292
errTagKeySyntax = errors.New("bad syntax for struct tag key")
9393
errTagValueSyntax = errors.New("bad syntax for struct tag value")
94+
errTagSpace = errors.New("key:\"value\" pairs not separated by spaces")
9495
)
9596

9697
// validateStructTag parses the struct tag and returns an error if it is not
@@ -99,7 +100,13 @@ var (
99100
func validateStructTag(tag string) error {
100101
// This code is based on the StructTag.Get code in package reflect.
101102

102-
for tag != "" {
103+
n := 0
104+
for ; tag != ""; n++ {
105+
if n > 0 && tag != "" && tag[0] != ' ' {
106+
// More restrictive than reflect, but catches likely mistakes
107+
// like `x:"foo",y:"bar"`, which parses as `x:"foo" ,y:"bar"` with second key ",y".
108+
return errTagSpace
109+
}
103110
// Skip leading space.
104111
i := 0
105112
for i < len(tag) && tag[i] == ' ' {

src/cmd/vet/testdata/structtag.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ type StructTagTest struct {
1515
F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
1616
G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
1717
H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
18+
I int `x:"foo",y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
19+
J int `x:"foo"y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
1820
OK0 int `x:"y" u:"v" w:""`
1921
OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
2022
OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
@@ -37,25 +39,25 @@ type JSONEmbeddedField struct {
3739

3840
type DuplicateJSONFields struct {
3941
JSON int `json:"a"`
40-
DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:39"
42+
DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:41"
4143
IgnoredJSON int `json:"-"`
4244
OtherIgnoredJSON int `json:"-"`
4345
OmitJSON int `json:",omitempty"`
4446
OtherOmitJSON int `json:",omitempty"`
45-
DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:39"
47+
DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:41"
4648
NonJSON int `foo:"a"`
4749
DuplicateNonJSON int `foo:"a"`
4850
Embedded struct {
4951
DuplicateJSON int `json:"a"` // OK because its not in the same struct type
5052
}
5153

5254
XML int `xml:"a"`
53-
DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:52"
55+
DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:54"
5456
IgnoredXML int `xml:"-"`
5557
OtherIgnoredXML int `xml:"-"`
5658
OmitXML int `xml:",omitempty"`
5759
OtherOmitXML int `xml:",omitempty"`
58-
DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:52"
60+
DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:54"
5961
NonXML int `foo:"a"`
6062
DuplicateNonXML int `foo:"a"`
6163
Embedded struct {

0 commit comments

Comments
 (0)