4
4
"errors"
5
5
"fmt"
6
6
"go/ast"
7
+ "go/token"
7
8
"regexp"
8
9
9
10
"github.com/JoelSpeed/kal/pkg/analysis/helpers/extractjsontags"
@@ -64,28 +65,42 @@ func (a *analyzer) run(pass *analysis.Pass) (interface{}, error) {
64
65
65
66
// Filter to fields so that we can iterate over fields in a struct.
66
67
nodeFilter := []ast.Node {
67
- (* ast .StructType )(nil ),
68
+ (* ast .Field )(nil ),
68
69
}
69
70
70
- inspect .Preorder (nodeFilter , func (n ast.Node ) {
71
- sTyp , ok := n .(* ast.StructType )
71
+ inspect .WithStack (nodeFilter , func (n ast.Node , push bool , stack []ast.Node ) (proceed bool ) {
72
+ if ! push {
73
+ return false
74
+ }
75
+
76
+ if len (stack ) < 2 {
77
+ return true
78
+ }
79
+
80
+ // The 0th node in the stack is the *ast.File.
81
+ // The 1st node in the stack is the *ast.GenDecl.
82
+ decl , ok := stack [1 ].(* ast.GenDecl )
72
83
if ! ok {
73
- return
84
+ return false
74
85
}
75
86
76
- if sTyp .Fields == nil {
77
- return
87
+ if decl .Tok != token .TYPE {
88
+ // Returning false here means we won't inspect non-type declarations (e.g. var, const, import).
89
+ return false
78
90
}
79
91
80
- for _ , field := range sTyp .Fields .List {
81
- a .checkField (pass , field , jsonTags )
92
+ field , ok := n .(* ast.Field )
93
+ if ! ok {
94
+ return true
82
95
}
96
+
97
+ return a .checkField (pass , field , jsonTags )
83
98
})
84
99
85
100
return nil , nil //nolint:nilnil
86
101
}
87
102
88
- func (a * analyzer ) checkField (pass * analysis.Pass , field * ast.Field , jsonTags extractjsontags.StructFieldTags ) {
103
+ func (a * analyzer ) checkField (pass * analysis.Pass , field * ast.Field , jsonTags extractjsontags.StructFieldTags ) ( proceed bool ) {
89
104
tagInfo := jsonTags .FieldTags (field )
90
105
91
106
var prefix string
@@ -97,26 +112,29 @@ func (a *analyzer) checkField(pass *analysis.Pass, field *ast.Field, jsonTags ex
97
112
98
113
if tagInfo .Missing {
99
114
pass .Reportf (field .Pos (), "%s is missing json tag" , prefix )
100
- return
115
+ return true
101
116
}
102
117
103
118
if tagInfo .Inline {
104
- return
119
+ return true
105
120
}
106
121
107
122
if tagInfo .Ignored {
108
- return
123
+ // Returning false here means we won't inspect the children of an ignored field.
124
+ return false
109
125
}
110
126
111
127
if tagInfo .Name == "" {
112
128
pass .Reportf (field .Pos (), "%s has empty json tag" , prefix )
113
- return
129
+ return true
114
130
}
115
131
116
132
matched := a .jsonTagRegex .Match ([]byte (tagInfo .Name ))
117
133
if ! matched {
118
134
pass .Reportf (field .Pos (), "%s json tag does not match pattern %q: %s" , prefix , a .jsonTagRegex .String (), tagInfo .Name )
119
135
}
136
+
137
+ return true
120
138
}
121
139
122
140
func defaultConfig (cfg * config.JSONTagsConfig ) {
0 commit comments