Skip to content

Commit 149a51e

Browse files
committed
Add base optionalfields linter
1 parent 00a5c0f commit 149a51e

File tree

10 files changed

+1119
-0
lines changed

10 files changed

+1119
-0
lines changed

pkg/analysis/helpers/markers/analyzer.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,13 @@ func (ms MarkerSet) HasWithExpressions(identifier string, expressions map[string
385385
return false
386386
}
387387

388+
// Get returns the markers associated with the given identifier.
389+
// If no markers are found, an empty slice is returned.
390+
// The returned slice may contain multiple markers with the same identifier.
391+
func (ms MarkerSet) Get(identifier string) []Marker {
392+
return ms[identifier]
393+
}
394+
388395
// UnsortedList returns a list of the markers, in no particular order.
389396
func (ms MarkerSet) UnsortedList() []Marker {
390397
markers := []Marker{}

pkg/analysis/optionalfields/analyzer.go

Lines changed: 434 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package optionalfields_test
2+
3+
import (
4+
"testing"
5+
6+
"golang.org/x/tools/go/analysis/analysistest"
7+
requiredfields "sigs.k8s.io/kube-api-linter/pkg/analysis/optionalfields"
8+
"sigs.k8s.io/kube-api-linter/pkg/config"
9+
)
10+
11+
func TestDefaultConfiguration(t *testing.T) {
12+
testdata := analysistest.TestData()
13+
14+
a, err := requiredfields.Initializer().Init(config.LintersConfig{})
15+
if err != nil {
16+
t.Fatal(err)
17+
}
18+
19+
analysistest.RunWithSuggestedFixes(t, testdata, a, "a")
20+
}
21+
22+
func TestWhenRequiredPreferenceConfiguration(t *testing.T) {
23+
testdata := analysistest.TestData()
24+
25+
a, err := requiredfields.Initializer().Init(config.LintersConfig{
26+
OptionalFields: config.OptionalFieldsConfig{
27+
Pointers: config.OptionalFieldsPointers{
28+
Preference: config.OptionalFieldsPointerPreferenceWhenRequired,
29+
},
30+
},
31+
})
32+
if err != nil {
33+
t.Fatal(err)
34+
}
35+
36+
analysistest.RunWithSuggestedFixes(t, testdata, a, "b")
37+
}

pkg/analysis/optionalfields/doc.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/*
2+
*/
3+
package optionalfields
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package optionalfields
2+
3+
import (
4+
"golang.org/x/tools/go/analysis"
5+
"sigs.k8s.io/kube-api-linter/pkg/config"
6+
)
7+
8+
// Initializer returns the AnalyzerInitializer for this
9+
// Analyzer so that it can be added to the registry.
10+
func Initializer() initializer {
11+
return initializer{}
12+
}
13+
14+
// intializer implements the AnalyzerInitializer interface.
15+
type initializer struct{}
16+
17+
// Name returns the name of the Analyzer.
18+
func (initializer) Name() string {
19+
return name
20+
}
21+
22+
// Init returns the intialized Analyzer.
23+
func (initializer) Init(cfg config.LintersConfig) (*analysis.Analyzer, error) {
24+
return newAnalyzer(cfg.OptionalFields), nil
25+
}
26+
27+
// Default determines whether this Analyzer is on by default, or not.
28+
func (initializer) Default() bool {
29+
return true
30+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package a
2+
3+
type A struct {
4+
// required field should not be picked up.
5+
// +required
6+
RequiredField string `json:"requiredField,omitempty"`
7+
8+
// pointerString is a pointer string field.
9+
// +optional
10+
PointerString *string `json:"pointerString,omitempty"`
11+
12+
// pointerInt is a pointer int field.
13+
// +optional
14+
PointerInt *int `json:"pointerInt,omitempty"`
15+
16+
// pointerStruct is a pointer struct field.
17+
// +optional
18+
PointerStruct *B `json:"pointerStruct,omitempty"`
19+
20+
// string is a string field.
21+
// +optional
22+
String string `json:"string,omitempty"` // want "field String is optional and should be a pointer"
23+
24+
// int is an int field.
25+
// +optional
26+
Int int `json:"int,omitempty"` // want "field Int is optional and should be a pointer"
27+
28+
// struct is a struct field.
29+
// +optional
30+
Struct B `json:"struct,omitempty"` // want "field Struct is optional and should be a pointer"
31+
32+
// slice is a slice field.
33+
// +optional
34+
Slice []string `json:"slice,omitempty"`
35+
36+
// map is a map field.
37+
// +optional
38+
Map map[string]string `json:"map,omitempty"`
39+
40+
// PointerSlice is a pointer slice field.
41+
// +optional
42+
PointerSlice *[]string `json:"pointerSlice,omitempty"` // want "field PointerSlice is a pointer type and should not be a pointer"
43+
44+
// PointerMap is a pointer map field.
45+
// +optional
46+
PointerMap *map[string]string `json:"pointerMap,omitempty"` // want "field PointerMap is a pointer type and should not be a pointer"
47+
48+
// PointerPointerString is a double pointer string field.
49+
// +optional
50+
DoublePointerString **string `json:"doublePointerString,omitempty"` // want "field DoublePointerString is a pointer type and should not be a pointer"
51+
}
52+
53+
type B struct {
54+
// pointerString is a pointer string field.
55+
// +optional
56+
PointerString *string `json:"pointerString,omitempty"`
57+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package a
2+
3+
type A struct {
4+
// required field should not be picked up.
5+
// +required
6+
RequiredField string `json:"requiredField,omitempty"`
7+
8+
// pointerString is a pointer string field.
9+
// +optional
10+
PointerString *string `json:"pointerString,omitempty"`
11+
12+
// pointerInt is a pointer int field.
13+
// +optional
14+
PointerInt *int `json:"pointerInt,omitempty"`
15+
16+
// pointerStruct is a pointer struct field.
17+
// +optional
18+
PointerStruct *B `json:"pointerStruct,omitempty"`
19+
20+
// string is a string field.
21+
// +optional
22+
String *string `json:"string,omitempty"` // want "field String is optional and should be a pointer"
23+
24+
// int is an int field.
25+
// +optional
26+
Int *int `json:"int,omitempty"` // want "field Int is optional and should be a pointer"
27+
28+
// struct is a struct field.
29+
// +optional
30+
Struct *B `json:"struct,omitempty"` // want "field Struct is optional and should be a pointer"
31+
32+
// slice is a slice field.
33+
// +optional
34+
Slice []string `json:"slice,omitempty"`
35+
36+
// map is a map field.
37+
// +optional
38+
Map map[string]string `json:"map,omitempty"`
39+
40+
// PointerSlice is a pointer slice field.
41+
// +optional
42+
PointerSlice []string `json:"pointerSlice,omitempty"` // want "field PointerSlice is a pointer type and should not be a pointer"
43+
44+
// PointerMap is a pointer map field.
45+
// +optional
46+
PointerMap map[string]string `json:"pointerMap,omitempty"` // want "field PointerMap is a pointer type and should not be a pointer"
47+
48+
// PointerPointerString is a double pointer string field.
49+
// +optional
50+
DoublePointerString *string `json:"doublePointerString,omitempty"` // want "field DoublePointerString is a pointer type and should not be a pointer"
51+
}
52+
53+
type B struct {
54+
// pointerString is a pointer string field.
55+
// +optional
56+
PointerString *string `json:"pointerString,omitempty"`
57+
}

0 commit comments

Comments
 (0)