Skip to content

Commit a08eacd

Browse files
committed
Don't require a function to init non-configurable analyzers
1 parent 3e10ac2 commit a08eacd

File tree

28 files changed

+130
-206
lines changed

28 files changed

+130
-206
lines changed

docs/new-linter.md

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,10 @@ func init() {
3939
func Initializer() initializer.AnalyzerInitializer {
4040
return initializer.NewInitializer(
4141
name, // A constant containing the name of the linter. This should be lowercase.
42-
initAnalyzer, // A function that returns the initialized Analyzer.
42+
Analyzer, // An *analysis.Analyzer variable that is the linter.
4343
true, // Whether the linter is enabled by default.
4444
)
4545
}
46-
47-
// initAnalyzer returns the intialized Analyzer.
48-
func initAnalyzer(_ any) (*analysis.Analyzer, error) {
49-
return Analyzer, nil
50-
}
5146
```
5247

5348
This pattern allows the linter to be registered with the KAL registry, and allows the linter to be initialized.
@@ -60,7 +55,6 @@ Once imported, the analyzer will be included in the linter builds.
6055

6156
Where the linter requires configuration, a slightly different pattern is used in `initializer.go`.
6257
This time, use `NewConfigurableInitializer` instead of `NewInitializer` and pass in a function to validate the linter configuration.
63-
You will also need to pass a function to initialize a new pointer to the configuration struct for the linter.
6458

6559
```go
6660

@@ -75,23 +69,17 @@ func Initializer() initializer.AnalyzerInitializer {
7569
name, // A constant containing the name of the linter. This should be lowercase.
7670
initAnalyzer, // A function that returns the initialized Analyzer.
7771
true, // Whether the linter is enabled by default.
78-
func() any { return &Config{} }, // A function that returns a new pointer to the configuration struct for the linter.
7972
validateLintersConfig, // A function that validates the linter configuration.
8073
)
8174
}
8275

8376
// initAnalyzer returns the intialized Analyzer.
84-
func initAnalyzer(cfg any) (*analysis.Analyzer, error) {
85-
cc, ok := cfg.(*ConditionsConfig)
86-
if !ok {
87-
return nil, fmt.Errorf("failed to initialize conditions analyzer: %w", initializer.NewIncorrectTypeError(cfg))
88-
}
89-
90-
return newAnalyzer(), nil
77+
func initAnalyzer(cfg *Config) (*analysis.Analyzer, error) {
78+
return newAnalyzer(cfg), nil
9179
}
9280

9381
// validateLintersConfig validates the linter configuration.
94-
func validateLintersConfig(cfg any, fldPath *field.Path) field.ErrorList {
82+
func validateLintersConfig(cfg *Config, fldPath *field.Path) field.ErrorList {
9583
... // Validate the linter configuration.
9684
}
9785
```

pkg/analysis/commentstart/initializer.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ limitations under the License.
1616
package commentstart
1717

1818
import (
19-
"golang.org/x/tools/go/analysis"
2019
kalanalysis "sigs.k8s.io/kube-api-linter/pkg/analysis"
2120
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2221
)
@@ -30,12 +29,7 @@ func init() {
3029
func Initializer() initializer.AnalyzerInitializer {
3130
return initializer.NewInitializer(
3231
name,
33-
initAnalyzer,
32+
Analyzer,
3433
true,
3534
)
3635
}
37-
38-
// Init returns the intialized Analyzer.
39-
func initAnalyzer(_ any) (*analysis.Analyzer, error) {
40-
return Analyzer, nil
41-
}

pkg/analysis/conditions/analyzer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ type analyzer struct {
6969

7070
// newAnalyzer creates a new analyzer.
7171
func newAnalyzer(cfg *ConditionsConfig) *analysis.Analyzer {
72+
if cfg == nil {
73+
cfg = &ConditionsConfig{}
74+
}
75+
7276
defaultConfig(cfg)
7377

7478
a := &analyzer{

pkg/analysis/conditions/initializer.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,18 @@ func Initializer() initializer.AnalyzerInitializer {
3535
name,
3636
initAnalyzer,
3737
true,
38-
func() any { return &ConditionsConfig{} },
3938
validateConfig,
4039
)
4140
}
4241

43-
func initAnalyzer(cfg any) (*analysis.Analyzer, error) {
44-
cc, ok := cfg.(*ConditionsConfig)
45-
if !ok {
46-
return nil, fmt.Errorf("failed to initialize conditions analyzer: %w", initializer.NewIncorrectTypeError(cfg))
47-
}
48-
42+
func initAnalyzer(cc *ConditionsConfig) (*analysis.Analyzer, error) {
4943
return newAnalyzer(cc), nil
5044
}
5145

5246
// validateConfig implements validation of the conditions linter config.
53-
func validateConfig(cfg any, fldPath *field.Path) field.ErrorList {
54-
cc, ok := cfg.(*ConditionsConfig)
55-
if !ok {
56-
return field.ErrorList{field.InternalError(fldPath, initializer.NewIncorrectTypeError(cfg))}
47+
func validateConfig(cc *ConditionsConfig, fldPath *field.Path) field.ErrorList {
48+
if cc == nil {
49+
return field.ErrorList{}
5750
}
5851

5952
fieldErrors := field.ErrorList{}

pkg/analysis/duplicatemarkers/initializer.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ limitations under the License.
1616
package duplicatemarkers
1717

1818
import (
19-
"golang.org/x/tools/go/analysis"
2019
kalanalysis "sigs.k8s.io/kube-api-linter/pkg/analysis"
2120
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2221
)
@@ -30,12 +29,7 @@ func init() {
3029
func Initializer() initializer.AnalyzerInitializer {
3130
return initializer.NewInitializer(
3231
name,
33-
initAnalyzer,
32+
Analyzer,
3433
true,
3534
)
3635
}
37-
38-
// initAnalyzer returns the intialized Analyzer.
39-
func initAnalyzer(_ any) (*analysis.Analyzer, error) {
40-
return Analyzer, nil
41-
}

pkg/analysis/initializer/initializer.go

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ limitations under the License.
1616
package initializer
1717

1818
import (
19+
"fmt"
20+
"reflect"
21+
1922
"golang.org/x/tools/go/analysis"
2023
"k8s.io/apimachinery/pkg/util/validation/field"
2124
)
2225

2326
// InitializerFunc is a function that initializes an Analyzer.
24-
type InitializerFunc func(any) (*analysis.Analyzer, error)
27+
type InitializerFunc[T any] func(T) (*analysis.Analyzer, error)
2528

2629
// ValidateFunc is a function that validates the configuration for an Analyzer.
27-
type ValidateFunc func(any, *field.Path) field.ErrorList
30+
type ValidateFunc[T any] func(T, *field.Path) field.ErrorList
2831

2932
// AnalyzerInitializer is used to initialize analyzers.
3033
type AnalyzerInitializer interface {
@@ -54,67 +57,77 @@ type ConfigurableAnalyzerInitializer interface {
5457
}
5558

5659
// NewInitializer construct a new initializer for initializing an Analyzer.
57-
func NewInitializer(name string, initFunc InitializerFunc, isDefault bool) AnalyzerInitializer {
58-
return initializer{
60+
func NewInitializer(name string, analyzer *analysis.Analyzer, isDefault bool) AnalyzerInitializer {
61+
return initializer[any]{
5962
name: name,
60-
initFunc: initFunc,
63+
initFunc: func(any) (*analysis.Analyzer, error) { return analyzer, nil },
6164
isDefault: isDefault,
6265
}
6366
}
6467

6568
// NewConfigurableInitializer constructs a new initializer for intializing a
6669
// configurable Analyzer.
67-
func NewConfigurableInitializer(name string, initFunc InitializerFunc, isDefault bool, configType func() any, validateFunc ValidateFunc) ConfigurableAnalyzerInitializer {
68-
return configurableInitializer{
69-
initializer: initializer{
70+
func NewConfigurableInitializer[T any](name string, initFunc InitializerFunc[T], isDefault bool, validateFunc ValidateFunc[T]) ConfigurableAnalyzerInitializer {
71+
return configurableInitializer[T]{
72+
initializer: initializer[T]{
7073
name: name,
7174
initFunc: initFunc,
7275
isDefault: isDefault,
7376
},
74-
configTypeFunc: configType,
75-
validateFunc: validateFunc,
77+
validateFunc: validateFunc,
7678
}
7779
}
7880

79-
type initializer struct {
81+
type initializer[T any] struct {
8082
name string
81-
initFunc InitializerFunc
83+
initFunc InitializerFunc[T]
8284
isDefault bool
8385
}
8486

8587
// Name returns the name of the initializer.
86-
func (i initializer) Name() string {
88+
func (i initializer[T]) Name() string {
8789
return i.name
8890
}
8991

9092
// Init returns a newly initializr analyzer.
91-
func (i initializer) Init(_ any) (*analysis.Analyzer, error) {
92-
return i.initFunc(nil)
93+
func (i initializer[T]) Init(_ any) (*analysis.Analyzer, error) {
94+
var cfg T
95+
96+
return i.initFunc(cfg)
9397
}
9498

9599
// Default determines whether this initializer should be enabled by default or not.
96-
func (i initializer) Default() bool {
100+
func (i initializer[T]) Default() bool {
97101
return i.isDefault
98102
}
99103

100-
type configurableInitializer struct {
101-
initializer
104+
type configurableInitializer[T any] struct {
105+
initializer[T]
102106

103-
configTypeFunc func() any
104-
validateFunc ValidateFunc
107+
validateFunc ValidateFunc[T]
105108
}
106109

107110
// Init returns a newly initialized analyzer.
108-
func (i configurableInitializer) Init(cfg any) (*analysis.Analyzer, error) {
109-
return i.initFunc(cfg)
111+
func (i configurableInitializer[T]) Init(cfg any) (*analysis.Analyzer, error) {
112+
cfgT, ok := cfg.(T)
113+
if !ok {
114+
return nil, fmt.Errorf("failed to initialize analyzer: %w", NewIncorrectTypeError(cfg))
115+
}
116+
117+
return i.initFunc(cfgT)
110118
}
111119

112120
// ConfigType returns the type of the config for the linter.
113-
func (i configurableInitializer) ConfigType() any {
114-
return i.configTypeFunc()
121+
func (i configurableInitializer[T]) ConfigType() any {
122+
return reflect.New(reflect.TypeOf(*new(T)).Elem()).Interface()
115123
}
116124

117125
// ValidateConfig validates the configuration for the initializer.
118-
func (i configurableInitializer) ValidateConfig(cfg any, fld *field.Path) field.ErrorList {
119-
return i.validateFunc(cfg, fld)
126+
func (i configurableInitializer[T]) ValidateConfig(cfg any, fld *field.Path) field.ErrorList {
127+
cfgT, ok := cfg.(T)
128+
if !ok {
129+
return field.ErrorList{field.InternalError(fld, NewIncorrectTypeError(cfg))}
130+
}
131+
132+
return i.validateFunc(cfgT, fld)
120133
}

pkg/analysis/integers/initializer.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ limitations under the License.
1616
package integers
1717

1818
import (
19-
"golang.org/x/tools/go/analysis"
2019
kalanalysis "sigs.k8s.io/kube-api-linter/pkg/analysis"
2120
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2221
)
@@ -30,11 +29,7 @@ func init() {
3029
func Initializer() initializer.AnalyzerInitializer {
3130
return initializer.NewInitializer(
3231
name,
33-
initAnalyzer,
32+
Analyzer,
3433
true,
3534
)
3635
}
37-
38-
func initAnalyzer(_ any) (*analysis.Analyzer, error) {
39-
return Analyzer, nil
40-
}

pkg/analysis/jsontags/analyzer.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ type analyzer struct {
4242

4343
// newAnalyzer creates a new analyzer with the given json tag regex.
4444
func newAnalyzer(cfg *JSONTagsConfig) (*analysis.Analyzer, error) {
45+
if cfg == nil {
46+
cfg = &JSONTagsConfig{}
47+
}
48+
4549
defaultConfig(cfg)
4650

4751
jsonTagRegex, err := regexp.Compile(cfg.JSONTagRegex)

pkg/analysis/jsontags/initializer.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,18 @@ func Initializer() initializer.AnalyzerInitializer {
3636
name,
3737
initAnalyzer,
3838
true,
39-
func() any { return &JSONTagsConfig{} },
4039
validateConfig,
4140
)
4241
}
4342

44-
func initAnalyzer(cfg any) (*analysis.Analyzer, error) {
45-
jtc, ok := cfg.(*JSONTagsConfig)
46-
if !ok {
47-
return nil, fmt.Errorf("failed to initialize JSON tags analyzer: %w", initializer.NewIncorrectTypeError(cfg))
48-
}
49-
43+
func initAnalyzer(jtc *JSONTagsConfig) (*analysis.Analyzer, error) {
5044
return newAnalyzer(jtc)
5145
}
5246

5347
// validateConfig is used to validate the configuration in the config.JSONTagsConfig struct.
54-
func validateConfig(cfg any, fldPath *field.Path) field.ErrorList {
55-
jtc, ok := cfg.(*JSONTagsConfig)
56-
if !ok {
57-
return field.ErrorList{field.InternalError(fldPath, initializer.NewIncorrectTypeError(cfg))}
48+
func validateConfig(jtc *JSONTagsConfig, fldPath *field.Path) field.ErrorList {
49+
if jtc == nil {
50+
return field.ErrorList{}
5851
}
5952

6053
fieldErrors := field.ErrorList{}

pkg/analysis/maxlength/initializer.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ limitations under the License.
1616
package maxlength
1717

1818
import (
19-
"golang.org/x/tools/go/analysis"
2019
kalanalysis "sigs.k8s.io/kube-api-linter/pkg/analysis"
2120
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2221
)
@@ -30,11 +29,7 @@ func init() {
3029
func Initializer() initializer.AnalyzerInitializer {
3130
return initializer.NewInitializer(
3231
name,
33-
initAnalyzer,
32+
Analyzer,
3433
false, // For now, CRD only, and so not on by default.
3534
)
3635
}
37-
38-
func initAnalyzer(_ any) (*analysis.Analyzer, error) {
39-
return Analyzer, nil
40-
}

0 commit comments

Comments
 (0)