Skip to content

Commit f8e122f

Browse files
authored
fix: add-constant struct tags in anonymous struct literals false positive (#954)
* fix: add-constant struct tags in anonymous struct literals false positive
1 parent 8d5724f commit f8e122f

File tree

2 files changed

+67
-10
lines changed

2 files changed

+67
-10
lines changed

rule/add-constant.go

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lin
4949
failures = append(failures, failure)
5050
}
5151

52-
w := lintAddConstantRule{
52+
w := &lintAddConstantRule{
5353
onFailure: onFailure,
5454
strLits: make(map[string]int),
5555
strLitLimit: r.strLitLimit,
5656
whiteLst: r.whiteList,
5757
ignoreFunctions: r.ignoreFunctions,
58+
structTags: make(map[*ast.BasicLit]struct{}),
5859
}
5960

6061
ast.Walk(w, file.AST)
@@ -73,23 +74,38 @@ type lintAddConstantRule struct {
7374
strLitLimit int
7475
whiteLst whiteList
7576
ignoreFunctions []*regexp.Regexp
77+
structTags map[*ast.BasicLit]struct{}
7678
}
7779

78-
func (w lintAddConstantRule) Visit(node ast.Node) ast.Visitor {
80+
func (w *lintAddConstantRule) Visit(node ast.Node) ast.Visitor {
81+
if node == nil {
82+
return nil
83+
}
84+
7985
switch n := node.(type) {
8086
case *ast.CallExpr:
8187
w.checkFunc(n)
8288
return nil
8389
case *ast.GenDecl:
8490
return nil // skip declarations
8591
case *ast.BasicLit:
86-
w.checkLit(n)
92+
if !w.isStructTag(n) {
93+
w.checkLit(n)
94+
}
95+
case *ast.StructType:
96+
if n.Fields != nil {
97+
for _, field := range n.Fields.List {
98+
if field.Tag != nil {
99+
w.structTags[field.Tag] = struct{}{}
100+
}
101+
}
102+
}
87103
}
88104

89105
return w
90106
}
91107

92-
func (w lintAddConstantRule) checkFunc(expr *ast.CallExpr) {
108+
func (w *lintAddConstantRule) checkFunc(expr *ast.CallExpr) {
93109
fName := w.getFuncName(expr)
94110

95111
for _, arg := range expr.Args {
@@ -105,7 +121,7 @@ func (w lintAddConstantRule) checkFunc(expr *ast.CallExpr) {
105121
}
106122
}
107123

108-
func (lintAddConstantRule) getFuncName(expr *ast.CallExpr) string {
124+
func (*lintAddConstantRule) getFuncName(expr *ast.CallExpr) string {
109125
switch f := expr.Fun.(type) {
110126
case *ast.SelectorExpr:
111127
switch prefix := f.X.(type) {
@@ -119,7 +135,7 @@ func (lintAddConstantRule) getFuncName(expr *ast.CallExpr) string {
119135
return ""
120136
}
121137

122-
func (w lintAddConstantRule) checkLit(n *ast.BasicLit) {
138+
func (w *lintAddConstantRule) checkLit(n *ast.BasicLit) {
123139
switch kind := n.Kind.String(); kind {
124140
case kindFLOAT, kindINT:
125141
w.checkNumLit(kind, n)
@@ -128,7 +144,7 @@ func (w lintAddConstantRule) checkLit(n *ast.BasicLit) {
128144
}
129145
}
130146

131-
func (w lintAddConstantRule) isIgnoredFunc(fName string) bool {
147+
func (w *lintAddConstantRule) isIgnoredFunc(fName string) bool {
132148
for _, pattern := range w.ignoreFunctions {
133149
if pattern.MatchString(fName) {
134150
return true
@@ -138,7 +154,7 @@ func (w lintAddConstantRule) isIgnoredFunc(fName string) bool {
138154
return false
139155
}
140156

141-
func (w lintAddConstantRule) checkStrLit(n *ast.BasicLit) {
157+
func (w *lintAddConstantRule) checkStrLit(n *ast.BasicLit) {
142158
if w.whiteLst[kindSTRING][n.Value] {
143159
return
144160
}
@@ -158,7 +174,7 @@ func (w lintAddConstantRule) checkStrLit(n *ast.BasicLit) {
158174
}
159175
}
160176

161-
func (w lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) {
177+
func (w *lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) {
162178
if w.whiteLst[kind][n.Value] {
163179
return
164180
}
@@ -171,6 +187,11 @@ func (w lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) {
171187
})
172188
}
173189

190+
func (w *lintAddConstantRule) isStructTag(n *ast.BasicLit) bool {
191+
_, ok := w.structTags[n]
192+
return ok
193+
}
194+
174195
func (r *AddConstantRule) configure(arguments lint.Arguments) {
175196
r.Lock()
176197
defer r.Unlock()

testdata/add-constant.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"os"
66
)
77

8-
func foo(a, b, c, d int) {
8+
func foo(a float32, b string, c any, d int) {
99
a = 1.0 // ignore
1010
b = "ignore"
1111
c = 2 // ignore
@@ -51,3 +51,39 @@ func ignoredFunc(num int) int {
5151
func notIgnoredFunc(num int) int {
5252
return num
5353
}
54+
55+
func tagsInStructLiteralsShouldBeOK() {
56+
a := struct {
57+
X int `json:"x"`
58+
}{}
59+
60+
b := struct {
61+
X int `json:"x"`
62+
}{}
63+
64+
c := struct {
65+
X int `json:"x"`
66+
}{}
67+
68+
d := struct {
69+
X int `json:"x"`
70+
Y int `json:"y"`
71+
}{}
72+
73+
e := struct {
74+
X int `json:"x"`
75+
Y int `json:"y"`
76+
}{}
77+
78+
var f struct {
79+
X int `json:"x"`
80+
Y int `json:"y"`
81+
}
82+
83+
var g struct {
84+
X int `json:"x"`
85+
Y int `json:"y"`
86+
}
87+
88+
_, _, _, _, _, _, _ = a, b, c, d, e, f, g
89+
}

0 commit comments

Comments
 (0)