@@ -13,6 +13,7 @@ import (
13
13
"go/types"
14
14
"path/filepath"
15
15
"reflect"
16
+ "slices"
16
17
"strconv"
17
18
"strings"
18
19
@@ -83,8 +84,10 @@ func (s *namesSeen) Set(key, name string, level int, pos token.Pos) {
83
84
(* s )[uniqueName {key , name , level }] = pos
84
85
}
85
86
86
- var checkTagDups = []string {"json" , "xml" }
87
- var checkTagSpaces = map [string ]bool {"json" : true , "xml" : true , "asn1" : true }
87
+ var (
88
+ checkTagDups = []string {"json" , "xml" }
89
+ checkTagSpaces = map [string ]bool {"json" : true , "xml" : true , "asn1" : true }
90
+ )
88
91
89
92
// checkCanonicalFieldTag checks a single struct field tag.
90
93
func checkCanonicalFieldTag (pass * analysis.Pass , field * types.Var , tag string , seen * namesSeen ) {
@@ -103,6 +106,20 @@ func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, s
103
106
pass .Reportf (field .Pos (), "struct field tag %#q not compatible with reflect.StructTag.Get: %s" , tag , err )
104
107
}
105
108
109
+ // Check for use of json or xml omitempty tags with unsupported field types.
110
+ for _ , enc := range [... ]string {"json" , "xml" } {
111
+ typ := field .Type ()
112
+ switch typ .Underlying ().(type ) {
113
+ case * types.Basic , * types.Array , * types.Map , * types.Slice , * types.Interface , * types.Pointer :
114
+ continue
115
+ }
116
+
117
+ val := reflect .StructTag (tag ).Get (enc )
118
+ if slices .Contains (strings .Split (val , "," ), "omitempty" ) {
119
+ pass .Reportf (field .Pos (), "struct field %s has %s tag but underlying type %s is not an omittable type" , field .Name (), val , typ .String ())
120
+ }
121
+ }
122
+
106
123
// Check for use of json or xml tags with unexported fields.
107
124
108
125
// Embedded struct. Nothing to do for now, but that
0 commit comments