@@ -25,30 +25,41 @@ import (
25
25
kalerrors "sigs.k8s.io/kube-api-linter/pkg/analysis/errors"
26
26
"sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/extractjsontags"
27
27
"sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/inspector"
28
- "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/markers"
28
+ markershelper "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/markers"
29
29
"sigs.k8s.io/kube-api-linter/pkg/config"
30
+ "sigs.k8s.io/kube-api-linter/pkg/markers"
30
31
31
32
"k8s.io/utils/ptr"
32
33
)
33
34
34
35
const (
35
36
name = "optionalfields"
36
37
37
- optionalMarker = "optional"
38
- requiredMarker = "required"
39
- kubebuilderOptinalMarker = "kubebuilder:validation:Optional"
40
- kubebuilderRequiredMarker = "kubebuilder:validation:Required"
38
+ optionalMarker = markers . OptionalMarker
39
+ requiredMarker = markers . RequiredMarker
40
+ kubebuilderOptionalMarker = markers . KubebuilderOptionalMarker
41
+ kubebuilderRequiredMarker = markers . KubebuilderRequiredMarker
41
42
42
- minItemsMarker = "kubebuilder:validation:MinItems"
43
- minLengthMarker = "kubebuilder:validation:MinLength"
44
- minPropertiesMarker = "kubebuilder:validation:MinProperties"
43
+ minItemsMarker = markers . KubebuilderMinItemsMarker
44
+ minLengthMarker = markers . KubebuilderMinLengthMarker
45
+ minPropertiesMarker = markers . KubebuilderMinPropertiesMarker
45
46
46
- minimumMarker = "kubebuilder:validation:Minimum"
47
- maximumMarker = "kubebuilder:validation:Maximum"
47
+ minimumMarker = markers . KubebuilderMinimumMarker
48
+ maximumMarker = markers . KubebuilderMaximumMarker
48
49
)
49
50
50
51
func init () {
51
- markers .DefaultRegistry ().Register (optionalMarker , kubebuilderOptinalMarker )
52
+ markershelper .DefaultRegistry ().Register (
53
+ optionalMarker ,
54
+ requiredMarker ,
55
+ kubebuilderOptionalMarker ,
56
+ kubebuilderRequiredMarker ,
57
+ minItemsMarker ,
58
+ minLengthMarker ,
59
+ minPropertiesMarker ,
60
+ minimumMarker ,
61
+ maximumMarker ,
62
+ )
52
63
}
53
64
54
65
var (
@@ -90,14 +101,14 @@ func (a *analyzer) run(pass *analysis.Pass) (any, error) {
90
101
return nil , kalerrors .ErrCouldNotGetInspector
91
102
}
92
103
93
- inspect .InspectFields (func (field * ast.Field , stack []ast.Node , jsonTagInfo extractjsontags.FieldTagInfo , markersAccess markers .Markers ) {
104
+ inspect .InspectFields (func (field * ast.Field , stack []ast.Node , jsonTagInfo extractjsontags.FieldTagInfo , markersAccess markershelper .Markers ) {
94
105
a .checkField (pass , field , markersAccess , jsonTagInfo )
95
106
})
96
107
97
108
return nil , nil //nolint:nilnil
98
109
}
99
110
100
- func (a * analyzer ) checkField (pass * analysis.Pass , field * ast.Field , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
111
+ func (a * analyzer ) checkField (pass * analysis.Pass , field * ast.Field , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
101
112
if field == nil || len (field .Names ) == 0 {
102
113
return
103
114
}
@@ -152,7 +163,7 @@ func (a *analyzer) checkFieldOmitEmpty(pass *analysis.Pass, field *ast.Field, fi
152
163
}
153
164
154
165
// checkFieldPointers is used to determine if a field should be a pointer, and advise on the correct action.
155
- func (a * analyzer ) checkFieldPointers (pass * analysis.Pass , field * ast.Field , fieldName string , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
166
+ func (a * analyzer ) checkFieldPointers (pass * analysis.Pass , field * ast.Field , fieldName string , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
156
167
isStarExpr , underlyingType := isStarExpr (field .Type )
157
168
158
169
if isPointerType (underlyingType ) {
@@ -173,7 +184,7 @@ func (a *analyzer) checkFieldPointers(pass *analysis.Pass, field *ast.Field, fie
173
184
// and ensures that they aren't pointered again (e.g. no *[]string).
174
185
// It will also check for the presence of non-zero min-properties and min-items
175
186
// when omitempty is missing, as this will.
176
- func (a * analyzer ) checkFieldPointersPointerTypes (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
187
+ func (a * analyzer ) checkFieldPointersPointerTypes (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
177
188
if a .omitEmptyPolicy == config .OptionalFieldsOmitEmptyPolicyIgnore && ! jsonTags .OmitEmpty {
178
189
a .checkFieldPointersPointerTypesWithoutOmitEmpty (pass , field , fieldName , markersAccess )
179
190
}
@@ -190,7 +201,7 @@ func (a *analyzer) checkFieldPointersPointerTypes(pass *analysis.Pass, field *as
190
201
// and does not have the omitempty tag.
191
202
// In both cases, the field should not have a minimum number of items or properties greater than 0.
192
203
// Without omitempty, empty json objects and arrays would be rendered ('{}' and '[]') and would breach the minimum properties/items.
193
- func (a * analyzer ) checkFieldPointersPointerTypesWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , markersAccess markers .Markers ) {
204
+ func (a * analyzer ) checkFieldPointersPointerTypesWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , markersAccess markershelper .Markers ) {
194
205
switch field .Type .(type ) {
195
206
case * ast.MapType :
196
207
reportShouldRemoveAllInstancesOfIntegerMarker (pass , field , markersAccess , minPropertiesMarker , fieldName , "field %s has a greater than zero minimum number of properties without omitempty. The minimum number of properties should be removed." )
@@ -213,7 +224,7 @@ func (a *analyzer) checkFieldPointersPreferenceAlways(pass *analysis.Pass, field
213
224
// For example, if it's an integer range that includes 0, then it should be a pointer.
214
225
// If the range doesn't include zero, and the field has omitempty, then the field doesn't need to be a pointer
215
226
// As `0` should never be committed to the API, and round trips would not be affected by the JSON library omitting the zero value when marshalling.
216
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequired (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , underlyingType ast.Expr , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
227
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequired (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , underlyingType ast.Expr , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
217
228
ident , ok := underlyingType .(* ast.Ident )
218
229
if ! ok {
219
230
// All fields should be idents, not sure when this would happen?
@@ -244,7 +255,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequired(pass *analysis.Pass,
244
255
}
245
256
}
246
257
247
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredIdentObj (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , decl * ast.TypeSpec , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
258
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredIdentObj (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , decl * ast.TypeSpec , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
248
259
switch t := decl .Type .(type ) {
249
260
case * ast.StructType :
250
261
a .checkFieldPointersPreferenceWhenRequiredStructType (pass , field , fieldName , isStarExpr , t , markersAccess , jsonTags )
@@ -260,7 +271,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredIdentObj(pass *analys
260
271
// Any struct that has a minimum number of properties, or has required fields, should be a pointer.
261
272
// Without a pointer, the JSON library cannot omit the field, and will always render a `{}`.
262
273
// A rendered empty object would then violate the minimum number of properties/required field checks.
263
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredStructType (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , typeExpr * ast.StructType , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
274
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredStructType (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , typeExpr * ast.StructType , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
264
275
hasRequiredFields := structContainsRequiredFields (typeExpr , markersAccess )
265
276
266
277
hasMinimumProperties , err := structHasGreaterThanZeroMinProperties (typeExpr , markersAccess .StructMarkers (typeExpr ))
@@ -297,7 +308,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredStructTypeWithOmitEmp
297
308
298
309
// checkFieldPointersPreferenceWhenRequiredStructTypeWithoutOmitEmpty recommends adding/removing pointers based on whether the struct
299
310
// has any required fields or minimum properties present, where the struct does not have omitempty as a tag.
300
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredStructTypeWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr , hasMinimumProperties , fieldHasMinimumProperties bool , markersAccess markers .Markers ) {
311
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredStructTypeWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr , hasMinimumProperties , fieldHasMinimumProperties bool , markersAccess markershelper .Markers ) {
301
312
switch {
302
313
case hasMinimumProperties && isStarExpr , fieldHasMinimumProperties && isStarExpr :
303
314
// The field is already a pointer and should be a pointer, so we don't need to do anything.
@@ -315,7 +326,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredStructTypeWithoutOmit
315
326
// Where the minimum allowable length is 0, the field should be a pointer.
316
327
// Where the minimum length is greater than 0, the field should not be a pointer.
317
328
// When the field does not have omitempty, it should not be a pointer, and should not have a minimum length marker.
318
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredString (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
329
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredString (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
319
330
if a .omitEmptyPolicy == config .OptionalFieldsOmitEmptyPolicyIgnore && ! jsonTags .OmitEmpty {
320
331
a .checkFieldPointersPreferenceWhenRequiredStringWithoutOmitEmpty (pass , field , fieldName , isStarExpr , markersAccess )
321
332
return
@@ -350,7 +361,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredString(pass *analysis
350
361
351
362
// checkFieldPointersPreferenceWhenRequiredStringWithoutOmitEmpty checks string fields for minimum length markers
352
363
// and pointers and suggests that both are removed.
353
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredStringWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markers .Markers ) {
364
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredStringWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markershelper .Markers ) {
354
365
reportShouldRemoveAllInstancesOfIntegerMarker (pass , field , markersAccess , minLengthMarker , fieldName , "field %s has a greater than zero minimum length without omitempty. The minimum length should be removed." )
355
366
356
367
// When non-omitempty, the string field should not be a pointer.
@@ -379,7 +390,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredBool(pass *analysis.P
379
390
}
380
391
381
392
//nolint:dupl
382
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredInteger (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
393
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredInteger (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
383
394
fieldMarkers := markersAccess .FieldMarkers (field )
384
395
385
396
minValue , err := getMarkerIntegerValueByName (fieldMarkers , minimumMarker )
@@ -439,7 +450,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredIntegerWithOmitEmpty(
439
450
// to determine whether or not 0 is a valid value for the integer.
440
451
// Where 0 is not a valid value, the field should either add omitempty, or remove the limits.
441
452
// We assume since there's no omitempty that the API author wants the zero value to be marshalled and as such, suggest to remove the limits.
442
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredIntegerWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , minValue , maxValue * int , isStarExpr bool , fieldMarkers markers .MarkerSet ) {
453
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredIntegerWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , minValue , maxValue * int , isStarExpr bool , fieldMarkers markershelper .MarkerSet ) {
443
454
switch {
444
455
case minValue != nil && * minValue > 0 :
445
456
reportShouldRemoveMarker (pass , field , fieldMarkers .Get (minimumMarker )[0 ], fieldName , "field %s has a greater than zero minimum value without omitempty. The minimum value should be removed." )
@@ -453,7 +464,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredIntegerWithoutOmitEmp
453
464
}
454
465
455
466
//nolint:dupl
456
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredFloat (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markers .Markers , jsonTags extractjsontags.FieldTagInfo ) {
467
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredFloat (pass * analysis.Pass , field * ast.Field , fieldName string , isStarExpr bool , markersAccess markershelper .Markers , jsonTags extractjsontags.FieldTagInfo ) {
457
468
fieldMarkers := markersAccess .FieldMarkers (field )
458
469
459
470
minValue , err := getMarkerFloatValueByName (fieldMarkers , minimumMarker )
@@ -513,7 +524,7 @@ func (a *analyzer) checkFieldPointersPreferenceWhenRequiredFloatWithOmitEmpty(pa
513
524
// to determine whether or not 0 is a valid value for the float.
514
525
// Where 0 is not a valid value, the field should either add omitempty, or remove the limits.
515
526
// We assume since there's no omitempty that the API author wants the zero value to be marshalled and as such, suggest to remove the limits.
516
- func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredFloatWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , minValue , maxValue * float64 , isStarExpr bool , fieldMarkers markers .MarkerSet ) {
527
+ func (a * analyzer ) checkFieldPointersPreferenceWhenRequiredFloatWithoutOmitEmpty (pass * analysis.Pass , field * ast.Field , fieldName string , minValue , maxValue * float64 , isStarExpr bool , fieldMarkers markershelper .MarkerSet ) {
517
528
switch {
518
529
case minValue != nil && * minValue > 0 :
519
530
reportShouldRemoveMarker (pass , field , fieldMarkers .Get (minimumMarker )[0 ], fieldName , "field %s has a greater than zero minimum value without omitempty. The minimum value should be removed." )
0 commit comments