go/analysis/passes/structtag: split out from vet
Change-Id: Ib3c4c783e4bca2bf2b3c76bea8f19959b7e39539 Reviewed-on: https://go-review.googlesource.com/c/142097 Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
parent
8919434dde
commit
d777022dd8
|
@ -1,60 +1,70 @@
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// This file contains the test for canonical struct tags.
|
package structtag
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
"golang.org/x/tools/go/analysis/passes/inspect"
|
||||||
|
"golang.org/x/tools/go/ast/inspector"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
var Analyzer = &analysis.Analyzer{
|
||||||
register("structtags",
|
Name: "structtag",
|
||||||
"check that struct field tags have canonical format and apply to exported fields as needed",
|
Doc: `check that struct field tags conform to reflect.StructTag.Get
|
||||||
checkStructFieldTags,
|
|
||||||
structType)
|
Also report certain struct tags (json, xml) used with unexported fields.`,
|
||||||
|
Requires: []*analysis.Analyzer{inspect.Analyzer},
|
||||||
|
RunDespiteErrors: true,
|
||||||
|
Run: run,
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkStructFieldTags checks all the field tags of a struct, including checking for duplicates.
|
func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
func checkStructFieldTags(f *File, node ast.Node) {
|
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
|
||||||
astType := node.(*ast.StructType)
|
|
||||||
typ := f.pkg.types[astType].Type.(*types.Struct)
|
nodeFilter := []ast.Node{
|
||||||
var seen map[[2]string]token.Pos
|
(*ast.StructType)(nil),
|
||||||
for i := 0; i < typ.NumFields(); i++ {
|
|
||||||
field := typ.Field(i)
|
|
||||||
tag := typ.Tag(i)
|
|
||||||
checkCanonicalFieldTag(f, astType, field, tag, &seen)
|
|
||||||
}
|
}
|
||||||
|
inspect.Preorder(nodeFilter, func(n ast.Node) {
|
||||||
|
styp := pass.TypesInfo.Types[n.(*ast.StructType)].Type.(*types.Struct)
|
||||||
|
var seen map[[2]string]token.Pos
|
||||||
|
for i := 0; i < styp.NumFields(); i++ {
|
||||||
|
field := styp.Field(i)
|
||||||
|
tag := styp.Tag(i)
|
||||||
|
checkCanonicalFieldTag(pass, field, tag, &seen)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var checkTagDups = []string{"json", "xml"}
|
var checkTagDups = []string{"json", "xml"}
|
||||||
var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true}
|
var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true}
|
||||||
|
|
||||||
// checkCanonicalFieldTag checks a single struct field tag.
|
// checkCanonicalFieldTag checks a single struct field tag.
|
||||||
// top is the top-level struct type that is currently being checked.
|
func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, seen *map[[2]string]token.Pos) {
|
||||||
func checkCanonicalFieldTag(f *File, top *ast.StructType, field *types.Var, tag string, seen *map[[2]string]token.Pos) {
|
|
||||||
for _, key := range checkTagDups {
|
for _, key := range checkTagDups {
|
||||||
checkTagDuplicates(f, tag, key, field, field, seen)
|
checkTagDuplicates(pass, tag, key, field, field, seen)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateStructTag(tag); err != nil {
|
if err := validateStructTag(tag); err != nil {
|
||||||
f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", tag, err)
|
pass.Reportf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", tag, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for use of json or xml tags with unexported fields.
|
// Check for use of json or xml tags with unexported fields.
|
||||||
|
|
||||||
// Embedded struct. Nothing to do for now, but that
|
// Embedded struct. Nothing to do for now, but that
|
||||||
// may change, depending on what happens with issue 7363.
|
// may change, depending on what happens with issue 7363.
|
||||||
|
// TODO(adonovan): investigate, now that that issue is fixed.
|
||||||
if field.Anonymous() {
|
if field.Anonymous() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -65,7 +75,7 @@ func checkCanonicalFieldTag(f *File, top *ast.StructType, field *types.Var, tag
|
||||||
|
|
||||||
for _, enc := range [...]string{"json", "xml"} {
|
for _, enc := range [...]string{"json", "xml"} {
|
||||||
if reflect.StructTag(tag).Get(enc) != "" {
|
if reflect.StructTag(tag).Get(enc) != "" {
|
||||||
f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Name(), enc)
|
pass.Reportf(field.Pos(), "struct field %s has %s tag but is not exported", field.Name(), enc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +84,7 @@ func checkCanonicalFieldTag(f *File, top *ast.StructType, field *types.Var, tag
|
||||||
// checkTagDuplicates checks a single struct field tag to see if any tags are
|
// checkTagDuplicates checks a single struct field tag to see if any tags are
|
||||||
// duplicated. nearest is the field that's closest to the field being checked,
|
// duplicated. nearest is the field that's closest to the field being checked,
|
||||||
// while still being part of the top-level struct type.
|
// while still being part of the top-level struct type.
|
||||||
func checkTagDuplicates(f *File, tag, key string, nearest, field *types.Var, seen *map[[2]string]token.Pos) {
|
func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *types.Var, seen *map[[2]string]token.Pos) {
|
||||||
val := reflect.StructTag(tag).Get(key)
|
val := reflect.StructTag(tag).Get(key)
|
||||||
if val == "-" {
|
if val == "-" {
|
||||||
// Ignored, even if the field is anonymous.
|
// Ignored, even if the field is anonymous.
|
||||||
|
@ -92,7 +102,7 @@ func checkTagDuplicates(f *File, tag, key string, nearest, field *types.Var, see
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tag := typ.Tag(i)
|
tag := typ.Tag(i)
|
||||||
checkTagDuplicates(f, tag, key, nearest, field, seen)
|
checkTagDuplicates(pass, tag, key, nearest, field, seen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ignored if the field isn't anonymous.
|
// Ignored if the field isn't anonymous.
|
||||||
|
@ -122,7 +132,10 @@ func checkTagDuplicates(f *File, tag, key string, nearest, field *types.Var, see
|
||||||
*seen = map[[2]string]token.Pos{}
|
*seen = map[[2]string]token.Pos{}
|
||||||
}
|
}
|
||||||
if pos, ok := (*seen)[[2]string{key, val}]; ok {
|
if pos, ok := (*seen)[[2]string{key, val}]; ok {
|
||||||
f.Badf(nearest.Pos(), "struct field %s repeats %s tag %q also at %s", field.Name(), key, val, f.loc(pos))
|
posn := pass.Fset.Position(pos)
|
||||||
|
posn.Filename = filepath.Base(posn.Filename)
|
||||||
|
posn.Column = 0
|
||||||
|
pass.Reportf(nearest.Pos(), "struct field %s repeats %s tag %q also at %s", field.Name(), key, val, posn)
|
||||||
} else {
|
} else {
|
||||||
(*seen)[[2]string{key, val}] = field.Pos()
|
(*seen)[[2]string{key, val}] = field.Pos()
|
||||||
}
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package structtag_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/tools/go/analysis/analysistest"
|
||||||
|
"golang.org/x/tools/go/analysis/passes/structtag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFromFileSystem(t *testing.T) {
|
||||||
|
testdata := analysistest.TestData()
|
||||||
|
analysistest.Run(t, testdata, structtag.Analyzer, "a")
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file contains the test for canonical struct tags.
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
import "encoding/xml"
|
||||||
|
|
||||||
|
type StructTagTest struct {
|
||||||
|
A int "hello" // want "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
|
||||||
|
B int "\tx:\"y\"" // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
|
||||||
|
C int "x:\"y\"\tx:\"y\"" // want "not compatible with reflect.StructTag.Get"
|
||||||
|
D int "x:`y`" // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
|
||||||
|
E int "ct\brl:\"char\"" // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
|
||||||
|
F int `:"emptykey"` // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
|
||||||
|
G int `x:"noEndQuote` // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
|
||||||
|
H int `x:"trunc\x0"` // want "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
|
||||||
|
I int `x:"foo",y:"bar"` // want "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
|
||||||
|
J int `x:"foo"y:"bar"` // want "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
|
||||||
|
OK0 int `x:"y" u:"v" w:""`
|
||||||
|
OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
|
||||||
|
OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
|
||||||
|
OK3 int `under_scores:"and" CAPS:"ARE_OK"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnexportedEncodingTagTest struct {
|
||||||
|
x int `json:"xx"` // want "struct field x has json tag but is not exported"
|
||||||
|
y int `xml:"yy"` // want "struct field y has xml tag but is not exported"
|
||||||
|
z int
|
||||||
|
A int `json:"aa" xml:"bb"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type unexp struct{}
|
||||||
|
|
||||||
|
type JSONEmbeddedField struct {
|
||||||
|
UnexportedEncodingTagTest `is:"embedded"`
|
||||||
|
unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnonymousJSON struct{}
|
||||||
|
type AnonymousXML struct{}
|
||||||
|
|
||||||
|
type AnonymousJSONField struct {
|
||||||
|
DuplicateAnonJSON int `json:"a"`
|
||||||
|
|
||||||
|
A int "hello" // want "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
|
||||||
|
}
|
||||||
|
|
||||||
|
type DuplicateJSONFields struct {
|
||||||
|
JSON int `json:"a"`
|
||||||
|
DuplicateJSON int `json:"a"` // want "struct field DuplicateJSON repeats json tag .a. also at a.go:52"
|
||||||
|
IgnoredJSON int `json:"-"`
|
||||||
|
OtherIgnoredJSON int `json:"-"`
|
||||||
|
OmitJSON int `json:",omitempty"`
|
||||||
|
OtherOmitJSON int `json:",omitempty"`
|
||||||
|
DuplicateOmitJSON int `json:"a,omitempty"` // want "struct field DuplicateOmitJSON repeats json tag .a. also at a.go:52"
|
||||||
|
NonJSON int `foo:"a"`
|
||||||
|
DuplicateNonJSON int `foo:"a"`
|
||||||
|
Embedded struct {
|
||||||
|
DuplicateJSON int `json:"a"` // OK because it's not in the same struct type
|
||||||
|
}
|
||||||
|
AnonymousJSON `json:"a"` // want "struct field AnonymousJSON repeats json tag .a. also at a.go:52"
|
||||||
|
|
||||||
|
AnonymousJSONField // want "struct field DuplicateAnonJSON repeats json tag .a. also at a.go:52"
|
||||||
|
|
||||||
|
XML int `xml:"a"`
|
||||||
|
DuplicateXML int `xml:"a"` // want "struct field DuplicateXML repeats xml tag .a. also at a.go:68"
|
||||||
|
IgnoredXML int `xml:"-"`
|
||||||
|
OtherIgnoredXML int `xml:"-"`
|
||||||
|
OmitXML int `xml:",omitempty"`
|
||||||
|
OtherOmitXML int `xml:",omitempty"`
|
||||||
|
DuplicateOmitXML int `xml:"a,omitempty"` // want "struct field DuplicateOmitXML repeats xml tag .a. also at a.go:68"
|
||||||
|
NonXML int `foo:"a"`
|
||||||
|
DuplicateNonXML int `foo:"a"`
|
||||||
|
Embedded2 struct {
|
||||||
|
DuplicateXML int `xml:"a"` // OK because it's not in the same struct type
|
||||||
|
}
|
||||||
|
AnonymousXML `xml:"a"` // want "struct field AnonymousXML repeats xml tag .a. also at a.go:68"
|
||||||
|
Attribute struct {
|
||||||
|
XMLName xml.Name `xml:"b"`
|
||||||
|
NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct.
|
||||||
|
Attr int `xml:"b,attr"` // OK because <b b="0"><b>0</b></b> is valid.
|
||||||
|
DupAttr int `xml:"b,attr"` // want "struct field DupAttr repeats xml attribute tag .b. also at a.go:84"
|
||||||
|
DupOmitAttr int `xml:"b,omitempty,attr"` // want "struct field DupOmitAttr repeats xml attribute tag .b. also at a.go:84"
|
||||||
|
|
||||||
|
AnonymousXML `xml:"b,attr"` // want "struct field AnonymousXML repeats xml attribute tag .b. also at a.go:84"
|
||||||
|
}
|
||||||
|
|
||||||
|
AnonymousJSONField `json:"not_anon"` // ok; fields aren't embedded in JSON
|
||||||
|
AnonymousJSONField `json:"-"` // ok; entire field is ignored in JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnexpectedSpacetest struct {
|
||||||
|
A int `json:"a,omitempty"`
|
||||||
|
B int `json:"b, omitempty"` // want "suspicious space in struct tag value"
|
||||||
|
C int `json:"c ,omitempty"`
|
||||||
|
D int `json:"d,omitempty, string"` // want "suspicious space in struct tag value"
|
||||||
|
E int `xml:"e local"`
|
||||||
|
F int `xml:"f "` // want "suspicious space in struct tag value"
|
||||||
|
G int `xml:" g"` // want "suspicious space in struct tag value"
|
||||||
|
H int `xml:"h ,omitempty"` // want "suspicious space in struct tag value"
|
||||||
|
I int `xml:"i, omitempty"` // want "suspicious space in struct tag value"
|
||||||
|
J int `xml:"j local ,omitempty"` // want "suspicious space in struct tag value"
|
||||||
|
K int `xml:"k local, omitempty"` // want "suspicious space in struct tag value"
|
||||||
|
L int `xml:" l local,omitempty"` // want "suspicious space in struct tag value"
|
||||||
|
M int `xml:"m local,omitempty"` // want "suspicious space in struct tag value"
|
||||||
|
N int `xml:" "` // want "suspicious space in struct tag value"
|
||||||
|
O int `xml:""`
|
||||||
|
P int `xml:","`
|
||||||
|
Q int `foo:" doesn't care "`
|
||||||
|
}
|
|
@ -1,113 +0,0 @@
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// This file contains the test for canonical struct tags.
|
|
||||||
|
|
||||||
package testdata
|
|
||||||
|
|
||||||
import "encoding/xml"
|
|
||||||
|
|
||||||
type StructTagTest struct {
|
|
||||||
A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
|
|
||||||
B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
|
|
||||||
C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get"
|
|
||||||
D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
|
|
||||||
E int "ct\brl:\"char\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
|
|
||||||
F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
|
|
||||||
G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
|
|
||||||
H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
|
|
||||||
I int `x:"foo",y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
|
|
||||||
J int `x:"foo"y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
|
|
||||||
OK0 int `x:"y" u:"v" w:""`
|
|
||||||
OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
|
|
||||||
OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
|
|
||||||
OK3 int `under_scores:"and" CAPS:"ARE_OK"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnexportedEncodingTagTest struct {
|
|
||||||
x int `json:"xx"` // ERROR "struct field x has json tag but is not exported"
|
|
||||||
y int `xml:"yy"` // ERROR "struct field y has xml tag but is not exported"
|
|
||||||
z int
|
|
||||||
A int `json:"aa" xml:"bb"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type unexp struct{}
|
|
||||||
|
|
||||||
type JSONEmbeddedField struct {
|
|
||||||
UnexportedEncodingTagTest `is:"embedded"`
|
|
||||||
unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
|
|
||||||
}
|
|
||||||
|
|
||||||
type AnonymousJSON struct{}
|
|
||||||
type AnonymousXML struct{}
|
|
||||||
|
|
||||||
type AnonymousJSONField struct {
|
|
||||||
DuplicateAnonJSON int `json:"a"`
|
|
||||||
|
|
||||||
A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
|
|
||||||
}
|
|
||||||
|
|
||||||
type DuplicateJSONFields struct {
|
|
||||||
JSON int `json:"a"`
|
|
||||||
DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:52"
|
|
||||||
IgnoredJSON int `json:"-"`
|
|
||||||
OtherIgnoredJSON int `json:"-"`
|
|
||||||
OmitJSON int `json:",omitempty"`
|
|
||||||
OtherOmitJSON int `json:",omitempty"`
|
|
||||||
DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:52"
|
|
||||||
NonJSON int `foo:"a"`
|
|
||||||
DuplicateNonJSON int `foo:"a"`
|
|
||||||
Embedded struct {
|
|
||||||
DuplicateJSON int `json:"a"` // OK because its not in the same struct type
|
|
||||||
}
|
|
||||||
AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:52"
|
|
||||||
|
|
||||||
AnonymousJSONField // ERROR "struct field DuplicateAnonJSON repeats json tag .a. also at structtag.go:52"
|
|
||||||
|
|
||||||
XML int `xml:"a"`
|
|
||||||
DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:68"
|
|
||||||
IgnoredXML int `xml:"-"`
|
|
||||||
OtherIgnoredXML int `xml:"-"`
|
|
||||||
OmitXML int `xml:",omitempty"`
|
|
||||||
OtherOmitXML int `xml:",omitempty"`
|
|
||||||
DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:68"
|
|
||||||
NonXML int `foo:"a"`
|
|
||||||
DuplicateNonXML int `foo:"a"`
|
|
||||||
Embedded2 struct {
|
|
||||||
DuplicateXML int `xml:"a"` // OK because its not in the same struct type
|
|
||||||
}
|
|
||||||
AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:68"
|
|
||||||
Attribute struct {
|
|
||||||
XMLName xml.Name `xml:"b"`
|
|
||||||
NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct.
|
|
||||||
Attr int `xml:"b,attr"` // OK because <b b="0"><b>0</b></b> is valid.
|
|
||||||
DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:84"
|
|
||||||
DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:84"
|
|
||||||
|
|
||||||
AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:84"
|
|
||||||
}
|
|
||||||
|
|
||||||
AnonymousJSONField `json:"not_anon"` // ok; fields aren't embedded in JSON
|
|
||||||
AnonymousJSONField `json:"-"` // ok; entire field is ignored in JSON
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnexpectedSpacetest struct {
|
|
||||||
A int `json:"a,omitempty"`
|
|
||||||
B int `json:"b, omitempty"` // ERROR "suspicious space in struct tag value"
|
|
||||||
C int `json:"c ,omitempty"`
|
|
||||||
D int `json:"d,omitempty, string"` // ERROR "suspicious space in struct tag value"
|
|
||||||
E int `xml:"e local"`
|
|
||||||
F int `xml:"f "` // ERROR "suspicious space in struct tag value"
|
|
||||||
G int `xml:" g"` // ERROR "suspicious space in struct tag value"
|
|
||||||
H int `xml:"h ,omitempty"` // ERROR "suspicious space in struct tag value"
|
|
||||||
I int `xml:"i, omitempty"` // ERROR "suspicious space in struct tag value"
|
|
||||||
J int `xml:"j local ,omitempty"` // ERROR "suspicious space in struct tag value"
|
|
||||||
K int `xml:"k local, omitempty"` // ERROR "suspicious space in struct tag value"
|
|
||||||
L int `xml:" l local,omitempty"` // ERROR "suspicious space in struct tag value"
|
|
||||||
M int `xml:"m local,omitempty"` // ERROR "suspicious space in struct tag value"
|
|
||||||
N int `xml:" "` // ERROR "suspicious space in struct tag value"
|
|
||||||
O int `xml:""`
|
|
||||||
P int `xml:","`
|
|
||||||
Q int `foo:" doesn't care "`
|
|
||||||
}
|
|
Loading…
Reference in New Issue