@@ -16,40 +16,51 @@ limitations under the License.
1616package maxlength
1717
1818import (
19- "fmt"
20- "go/ast"
21-
22- "golang.org/x/tools/go/analysis"
23- kalerrors "sigs.k8s.io/kube-api-linter/pkg/analysis/errors"
24- "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/extractjsontags"
25- "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/inspector"
26- markershelper "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/markers"
27- "sigs.k8s.io/kube-api-linter/pkg/analysis/utils"
28- "sigs.k8s.io/kube-api-linter/pkg/markers"
19+ "fmt"
20+ "go/ast"
21+
22+ "golang.org/x/tools/go/analysis"
23+ kalerrors "sigs.k8s.io/kube-api-linter/pkg/analysis/errors"
24+ "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/extractjsontags"
25+ "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/inspector"
26+ markershelper "sigs.k8s.io/kube-api-linter/pkg/analysis/helpers/markers"
27+ "sigs.k8s.io/kube-api-linter/pkg/analysis/utils"
28+ "sigs.k8s.io/kube-api-linter/pkg/markers"
2929)
3030
3131func init () {
3232 markershelper .DefaultRegistry ().Register (
33- markers .KubebuilderMaxLengthMarker ,
34- markers .KubebuilderMaxItemsMarker ,
35- markers .KubebuilderItemsMaxLengthMarker ,
36- markers .KubebuilderEnumMarker ,
37- markers .KubebuilderItemsEnumMarker ,
38- markers .KubebuilderFormatMarker ,
39- markers .KubebuilderItemsFormatMarker ,
40- markers .K8sMaxLengthMarker ,
41- markers .K8sMaxItemsMarker ,
42- markers .K8sEnumMarker ,
43- )
33+ markers .KubebuilderMaxLengthMarker ,
34+ markers .KubebuilderMaxItemsMarker ,
35+ markers .KubebuilderItemsMaxLengthMarker ,
36+ markers .KubebuilderEnumMarker ,
37+ markers .KubebuilderItemsEnumMarker ,
38+ markers .KubebuilderFormatMarker ,
39+ markers .KubebuilderItemsFormatMarker ,
40+ markers .KubebuilderMaxPropertiesMarker ,
41+ markers .KubebuilderMaximumMarker ,
42+ markers .K8sMaxLengthMarker ,
43+ markers .K8sMaxItemsMarker ,
44+ markers .K8sEnumMarker ,
45+ markers .K8sMinLengthMarker ,
46+ markers .K8sMinItemsMarker ,
47+ markers .K8sMinimumMarker ,
48+ markers .K8sMaxPropertiesMarker ,
49+ markers .K8sMinPropertiesMarker ,
50+ markers .K8sMaximumMarker ,
51+ markers .K8sMaxBytesMarker ,
52+ )
4453}
4554
4655const (
47- name = "maxlength"
56+ name = "maxlength"
4857)
4958
5059type analyzer struct {
51- preferredMaxLengthMarker string
52- preferredMaxItemsMarker string
60+ preferredMaxLengthMarker string
61+ preferredMaxItemsMarker string
62+ preferredMaxPropertiesMarker string
63+ preferredMaximumMarker string
5364}
5465
5566// newAnalyzer creates a new analyzer with the given configuration.
@@ -61,8 +72,10 @@ func newAnalyzer(cfg *MaxLengthConfig) *analysis.Analyzer {
6172 defaultConfig (cfg )
6273
6374 a := & analyzer {
64- preferredMaxLengthMarker : cfg .PreferredMaxLengthMarker ,
65- preferredMaxItemsMarker : cfg .PreferredMaxItemsMarker ,
75+ preferredMaxLengthMarker : cfg .PreferredMaxLengthMarker ,
76+ preferredMaxItemsMarker : cfg .PreferredMaxItemsMarker ,
77+ preferredMaxPropertiesMarker : cfg .PreferredMaxPropertiesMarker ,
78+ preferredMaximumMarker : cfg .PreferredMaximumMarker ,
6679 }
6780
6881 return & analysis.Analyzer {
@@ -73,25 +86,15 @@ func newAnalyzer(cfg *MaxLengthConfig) *analysis.Analyzer {
7386 }
7487}
7588
76- func defaultConfig (cfg * MaxLengthConfig ) {
77- if cfg .PreferredMaxLengthMarker == "" {
78- cfg .PreferredMaxLengthMarker = markers .KubebuilderMaxLengthMarker
79- }
80-
81- if cfg .PreferredMaxItemsMarker == "" {
82- cfg .PreferredMaxItemsMarker = markers .KubebuilderMaxItemsMarker
83- }
84- }
85-
8689func (a * analyzer ) run (pass * analysis.Pass ) (any , error ) {
8790 inspect , ok := pass .ResultOf [inspector .Analyzer ].(inspector.Inspector )
8891 if ! ok {
8992 return nil , kalerrors .ErrCouldNotGetInspector
9093 }
9194
9295 inspect .InspectFields (func (field * ast.Field , _ extractjsontags.FieldTagInfo , markersAccess markershelper.Markers , qualifiedFieldName string ) {
93- a .checkField (pass , field , markersAccess , qualifiedFieldName )
94- })
96+ a .checkField (pass , field , markersAccess , qualifiedFieldName )
97+ })
9598
9699 return nil , nil //nolint:nilnil
97100}
@@ -104,7 +107,11 @@ func (a *analyzer) checkField(pass *analysis.Pass, field *ast.Field, markersAcce
104107
105108func (a * analyzer ) checkIdent (pass * analysis.Pass , ident * ast.Ident , node ast.Node , aliases []* ast.TypeSpec , markersAccess markershelper.Markers , prefix , marker string , needsMaxLength func (markershelper.MarkerSet ) bool ) {
106109 if utils .IsBasicType (pass , ident ) { // Built-in type
107- a .checkString (pass , ident , node , aliases , markersAccess , prefix , marker , needsMaxLength )
110+ if ident .Name == "string" {
111+ a .checkString (pass , ident , node , aliases , markersAccess , prefix , marker , needsMaxLength )
112+ } else if isNumericType (ident .Name ) {
113+ a .checkNumeric (pass , ident , node , aliases , markersAccess , prefix )
114+ }
108115
109116 return
110117 }
@@ -129,6 +136,14 @@ func (a *analyzer) checkString(pass *analysis.Pass, ident *ast.Ident, node ast.N
129136 }
130137}
131138
139+ func (a * analyzer ) checkNumeric (pass * analysis.Pass , ident * ast.Ident , node ast.Node , aliases []* ast.TypeSpec , markersAccess markershelper.Markers , prefix string ) {
140+ markerSet := getCombinedMarkers (markersAccess , node , aliases )
141+
142+ if needsMaximum (markerSet ) {
143+ pass .Reportf (node .Pos (), "%s must have a maximum value, add %s marker" , prefix , a .preferredMaximumMarker )
144+ }
145+ }
146+
132147func (a * analyzer ) checkTypeSpec (pass * analysis.Pass , tSpec * ast.TypeSpec , node ast.Node , aliases []* ast.TypeSpec , markersAccess markershelper.Markers , prefix , marker string , needsMaxLength func (markershelper.MarkerSet ) bool ) {
133148 if tSpec .Name == nil {
134149 return
@@ -148,6 +163,8 @@ func (a *analyzer) checkTypeExpr(pass *analysis.Pass, typeExpr ast.Expr, node as
148163 a .checkTypeExpr (pass , typ .X , node , aliases , markersAccess , prefix , marker , needsMaxLength )
149164 case * ast.ArrayType :
150165 a .checkArrayType (pass , typ , node , aliases , markersAccess , prefix )
166+ case * ast.MapType :
167+ a .checkMapType (pass , typ , node , aliases , markersAccess , prefix )
151168 }
152169}
153170
@@ -177,6 +194,14 @@ func (a *analyzer) checkArrayType(pass *analysis.Pass, arrayType *ast.ArrayType,
177194 }
178195}
179196
197+ func (a * analyzer ) checkMapType (pass * analysis.Pass , mapType * ast.MapType , node ast.Node , aliases []* ast.TypeSpec , markersAccess markershelper.Markers , prefix string ) {
198+ markerSet := getCombinedMarkers (markersAccess , node , aliases )
199+
200+ if needsMaxProperties (markerSet ) {
201+ pass .Reportf (node .Pos (), "%s must have a maximum number of properties, add %s marker" , prefix , a .preferredMaxPropertiesMarker )
202+ }
203+ }
204+
180205func (a * analyzer ) checkArrayElementIdent (pass * analysis.Pass , ident * ast.Ident , node ast.Node , aliases []* ast.TypeSpec , markersAccess markershelper.Markers , prefix string ) {
181206 if ident .Obj == nil { // Built-in type
182207 a .checkString (pass , ident , node , aliases , markersAccess , prefix , markers .KubebuilderItemsMaxLengthMarker , needsItemsMaxLength )
@@ -190,68 +215,100 @@ func (a *analyzer) checkArrayElementIdent(pass *analysis.Pass, ident *ast.Ident,
190215 }
191216
192217 // If the array element wasn't directly a string, allow a string alias to be used
193- // with either the items style markers or the on alias style markers.
194- a .checkTypeSpec (pass , tSpec , node , append (aliases , tSpec ), markersAccess , fmt .Sprintf ("%s type" , prefix ), a .preferredMaxLengthMarker , func (ms markershelper.MarkerSet ) bool {
195- return needsStringMaxLength (ms ) && needsItemsMaxLength (ms )
196- })
218+ // with either the items style markers or the on alias style markers.
219+ a .checkTypeSpec (pass , tSpec , node , append (aliases , tSpec ), markersAccess , fmt .Sprintf ("%s type" , prefix ), a .preferredMaxLengthMarker , func (ms markershelper.MarkerSet ) bool {
220+ return needsStringMaxLength (ms ) && needsItemsMaxLength (ms )
221+ })
197222}
198223
199224func getCombinedMarkers (markersAccess markershelper.Markers , node ast.Node , aliases []* ast.TypeSpec ) markershelper.MarkerSet {
200- base := markershelper .NewMarkerSet (getMarkers (markersAccess , node ).UnsortedList ()... )
225+ base := markershelper .NewMarkerSet (getMarkers (markersAccess , node ).UnsortedList ()... )
201226
202- for _ , a := range aliases {
203- base .Insert (getMarkers (markersAccess , a ).UnsortedList ()... )
204- }
227+ for _ , a := range aliases {
228+ base .Insert (getMarkers (markersAccess , a ).UnsortedList ()... )
229+ }
205230
206- return base
231+ return base
207232}
208233
209234func getMarkers (markersAccess markershelper.Markers , node ast.Node ) markershelper.MarkerSet {
210- switch t := node .(type ) {
211- case * ast.Field :
212- return markersAccess .FieldMarkers (t )
213- case * ast.TypeSpec :
214- return markersAccess .TypeMarkers (t )
215- }
235+ switch t := node .(type ) {
236+ case * ast.Field :
237+ return markersAccess .FieldMarkers (t )
238+ case * ast.TypeSpec :
239+ return markersAccess .TypeMarkers (t )
240+ }
216241
217- return nil
242+ return nil
218243}
219244
220- // needsMaxLength returns true if the field needs a maximum length.
245+ // needsStringMaxLength returns true if the field needs a maximum length.
221246// Fields do not need a maximum length if they are already marked with a maximum length,
222247// or if they are an enum, or if they are a date, date-time or duration.
223248func needsStringMaxLength (markerSet markershelper.MarkerSet ) bool {
224- switch {
225- case markerSet .Has (markers .KubebuilderMaxLengthMarker ),
226- markerSet .Has (markers .K8sMaxLengthMarker ),
227- markerSet .Has (markers .KubebuilderEnumMarker ),
228- markerSet .Has (markers .K8sEnumMarker ),
229- markerSet .HasWithValue (kubebuilderFormatWithValue ("date" )),
230- markerSet .HasWithValue (kubebuilderFormatWithValue ("date-time" )),
231- markerSet .HasWithValue (kubebuilderFormatWithValue ("duration" )):
232- return false
233- }
249+ switch {
250+ case markerSet .Has (markers .KubebuilderMaxLengthMarker ),
251+ markerSet .Has (markers .K8sMaxLengthMarker ),
252+ markerSet .Has (markers .K8sMaxBytesMarker ),
253+ markerSet .Has (markers .KubebuilderEnumMarker ),
254+ markerSet .Has (markers .K8sEnumMarker ),
255+ markerSet .HasWithValue (kubebuilderFormatWithValue ("date" )),
256+ markerSet .HasWithValue (kubebuilderFormatWithValue ("date-time" )),
257+ markerSet .HasWithValue (kubebuilderFormatWithValue ("duration" )):
258+ return false
259+ }
234260
235- return true
261+ return true
236262}
237263
238264func needsItemsMaxLength (markerSet markershelper.MarkerSet ) bool {
239- switch {
240- case markerSet .Has (markers .KubebuilderItemsMaxLengthMarker ),
241- markerSet .Has (markers .KubebuilderItemsEnumMarker ),
242- markerSet .HasWithValue (kubebuilderItemsFormatWithValue ("date" )),
243- markerSet .HasWithValue (kubebuilderItemsFormatWithValue ("date-time" )),
244- markerSet .HasWithValue (kubebuilderItemsFormatWithValue ("duration" )):
245- return false
265+ switch {
266+ case markerSet .Has (markers .KubebuilderItemsMaxLengthMarker ),
267+ markerSet .Has (markers .KubebuilderItemsEnumMarker ),
268+ markerSet .HasWithValue (kubebuilderItemsFormatWithValue ("date" )),
269+ markerSet .HasWithValue (kubebuilderItemsFormatWithValue ("date-time" )),
270+ markerSet .HasWithValue (kubebuilderItemsFormatWithValue ("duration" )):
271+ return false
272+ }
273+
274+ return true
246275}
247276
248- return true
277+ func needsMaxProperties (markerSet markershelper.MarkerSet ) bool {
278+ switch {
279+ case markerSet .Has (markers .KubebuilderMaxPropertiesMarker ),
280+ markerSet .Has (markers .K8sMaxPropertiesMarker ):
281+ return false
282+ }
283+
284+ return true
285+ }
286+
287+ func needsMaximum (markerSet markershelper.MarkerSet ) bool {
288+ switch {
289+ case markerSet .Has (markers .KubebuilderMaximumMarker ),
290+ markerSet .Has (markers .K8sMaximumMarker ):
291+ return false
292+ }
293+
294+ return true
249295}
250296
251297func kubebuilderFormatWithValue (value string ) string {
252- return fmt .Sprintf ("%s:=%s" , markers .KubebuilderFormatMarker , value )
298+ return fmt .Sprintf ("%s:=%s" , markers .KubebuilderFormatMarker , value )
253299}
254300
255301func kubebuilderItemsFormatWithValue (value string ) string {
256- return fmt .Sprintf ("%s:=%s" , markers .KubebuilderItemsFormatMarker , value )
302+ return fmt .Sprintf ("%s:=%s" , markers .KubebuilderItemsFormatMarker , value )
303+ }
304+
305+ func isNumericType (name string ) bool {
306+ switch name {
307+ case "int" , "int8" , "int16" , "int32" , "int64" ,
308+ "uint" , "uint8" , "uint16" , "uint32" , "uint64" ,
309+ "float32" , "float64" :
310+ return true
311+ }
312+
313+ return false
257314}
0 commit comments