/
C003.go
88 lines (73 loc) · 1.85 KB
/
C003.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package C003
import (
"go/ast"
"strings"
b "github.com/gibizer/operator-lint/pkg/base"
"golang.org/x/tools/go/analysis"
)
const (
Name = "C003"
Doc = "detects incompatible defaulting via `Optional` kubebuilder marker and `omitemty` golang tag"
)
var typeNameToDefaultValue = map[string]string{
"int32": "0",
"int": "0",
"string": "",
"bool": "false",
}
type Linter struct {
*b.BaseLinter
}
func NewAnalyzer() *analysis.Analyzer {
l := &Linter{}
l.BaseLinter = b.NewBaseLinter(Name, Doc, l)
return l.Analyzer
}
func (l *Linter) LintFile(file *ast.File) error {
ast.Inspect(file, func(node ast.Node) bool {
switch x := node.(type) {
case *ast.Field:
if x.Tag == nil {
return true
}
optional := b.HasDocComment(x, "+kubebuilder:validation:Optional")
default_ := b.HasDocComment(x, b.KubebuilderDefault)
if !(optional && default_) {
return true
}
omitempty := strings.Contains(x.Tag.Value, ",omitempty")
if !omitempty {
return true
}
if b.PointerType(x.Type) {
return true
}
typeName := l.TypeName(x)
golangDefault, ok := typeNameToDefaultValue[typeName]
if !ok {
l.Report(
x.Pos(),
"Field '%s' has both a 'Optional' kubebuilder marker with a default value "+
"and an 'omitempty' tag. Either remove the default value or remove 'omitempty' or change the "+
"field to a pointer type",
x.Names[0].Name)
return true
}
defaultValue, err := b.GetKubebuilderDefault(x)
if err != nil {
panic(err)
}
if defaultValue != golangDefault {
l.Report(
x.Pos(),
"Field '%s' has both a 'Optional' kubebuilder marker with a default value "+
"and an 'omitempty' tag. Either remove the default value or remove 'omitempty' or change the "+
"field to a pointer type",
x.Names[0].Name)
return true
}
}
return true
})
return nil
}