1
0
mirror of https://github.com/mgechev/revive.git synced 2025-07-13 01:00:17 +02:00

fix: add-constant struct tags in anonymous struct literals false positive (#954)

* fix: add-constant struct tags in anonymous struct literals false positive
This commit is contained in:
Denis Voytyuk
2023-12-28 23:59:58 +01:00
committed by GitHub
parent 8d5724f746
commit f8e122f43d
2 changed files with 67 additions and 10 deletions

View File

@ -49,12 +49,13 @@ func (r *AddConstantRule) Apply(file *lint.File, arguments lint.Arguments) []lin
failures = append(failures, failure) failures = append(failures, failure)
} }
w := lintAddConstantRule{ w := &lintAddConstantRule{
onFailure: onFailure, onFailure: onFailure,
strLits: make(map[string]int), strLits: make(map[string]int),
strLitLimit: r.strLitLimit, strLitLimit: r.strLitLimit,
whiteLst: r.whiteList, whiteLst: r.whiteList,
ignoreFunctions: r.ignoreFunctions, ignoreFunctions: r.ignoreFunctions,
structTags: make(map[*ast.BasicLit]struct{}),
} }
ast.Walk(w, file.AST) ast.Walk(w, file.AST)
@ -73,9 +74,14 @@ type lintAddConstantRule struct {
strLitLimit int strLitLimit int
whiteLst whiteList whiteLst whiteList
ignoreFunctions []*regexp.Regexp ignoreFunctions []*regexp.Regexp
structTags map[*ast.BasicLit]struct{}
} }
func (w lintAddConstantRule) Visit(node ast.Node) ast.Visitor { func (w *lintAddConstantRule) Visit(node ast.Node) ast.Visitor {
if node == nil {
return nil
}
switch n := node.(type) { switch n := node.(type) {
case *ast.CallExpr: case *ast.CallExpr:
w.checkFunc(n) w.checkFunc(n)
@ -83,13 +89,23 @@ func (w lintAddConstantRule) Visit(node ast.Node) ast.Visitor {
case *ast.GenDecl: case *ast.GenDecl:
return nil // skip declarations return nil // skip declarations
case *ast.BasicLit: case *ast.BasicLit:
if !w.isStructTag(n) {
w.checkLit(n) w.checkLit(n)
} }
case *ast.StructType:
if n.Fields != nil {
for _, field := range n.Fields.List {
if field.Tag != nil {
w.structTags[field.Tag] = struct{}{}
}
}
}
}
return w return w
} }
func (w lintAddConstantRule) checkFunc(expr *ast.CallExpr) { func (w *lintAddConstantRule) checkFunc(expr *ast.CallExpr) {
fName := w.getFuncName(expr) fName := w.getFuncName(expr)
for _, arg := range expr.Args { for _, arg := range expr.Args {
@ -105,7 +121,7 @@ func (w lintAddConstantRule) checkFunc(expr *ast.CallExpr) {
} }
} }
func (lintAddConstantRule) getFuncName(expr *ast.CallExpr) string { func (*lintAddConstantRule) getFuncName(expr *ast.CallExpr) string {
switch f := expr.Fun.(type) { switch f := expr.Fun.(type) {
case *ast.SelectorExpr: case *ast.SelectorExpr:
switch prefix := f.X.(type) { switch prefix := f.X.(type) {
@ -119,7 +135,7 @@ func (lintAddConstantRule) getFuncName(expr *ast.CallExpr) string {
return "" return ""
} }
func (w lintAddConstantRule) checkLit(n *ast.BasicLit) { func (w *lintAddConstantRule) checkLit(n *ast.BasicLit) {
switch kind := n.Kind.String(); kind { switch kind := n.Kind.String(); kind {
case kindFLOAT, kindINT: case kindFLOAT, kindINT:
w.checkNumLit(kind, n) w.checkNumLit(kind, n)
@ -128,7 +144,7 @@ func (w lintAddConstantRule) checkLit(n *ast.BasicLit) {
} }
} }
func (w lintAddConstantRule) isIgnoredFunc(fName string) bool { func (w *lintAddConstantRule) isIgnoredFunc(fName string) bool {
for _, pattern := range w.ignoreFunctions { for _, pattern := range w.ignoreFunctions {
if pattern.MatchString(fName) { if pattern.MatchString(fName) {
return true return true
@ -138,7 +154,7 @@ func (w lintAddConstantRule) isIgnoredFunc(fName string) bool {
return false return false
} }
func (w lintAddConstantRule) checkStrLit(n *ast.BasicLit) { func (w *lintAddConstantRule) checkStrLit(n *ast.BasicLit) {
if w.whiteLst[kindSTRING][n.Value] { if w.whiteLst[kindSTRING][n.Value] {
return return
} }
@ -158,7 +174,7 @@ func (w lintAddConstantRule) checkStrLit(n *ast.BasicLit) {
} }
} }
func (w lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) { func (w *lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) {
if w.whiteLst[kind][n.Value] { if w.whiteLst[kind][n.Value] {
return return
} }
@ -171,6 +187,11 @@ func (w lintAddConstantRule) checkNumLit(kind string, n *ast.BasicLit) {
}) })
} }
func (w *lintAddConstantRule) isStructTag(n *ast.BasicLit) bool {
_, ok := w.structTags[n]
return ok
}
func (r *AddConstantRule) configure(arguments lint.Arguments) { func (r *AddConstantRule) configure(arguments lint.Arguments) {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()

View File

@ -5,7 +5,7 @@ import (
"os" "os"
) )
func foo(a, b, c, d int) { func foo(a float32, b string, c any, d int) {
a = 1.0 // ignore a = 1.0 // ignore
b = "ignore" b = "ignore"
c = 2 // ignore c = 2 // ignore
@ -51,3 +51,39 @@ func ignoredFunc(num int) int {
func notIgnoredFunc(num int) int { func notIgnoredFunc(num int) int {
return num return num
} }
func tagsInStructLiteralsShouldBeOK() {
a := struct {
X int `json:"x"`
}{}
b := struct {
X int `json:"x"`
}{}
c := struct {
X int `json:"x"`
}{}
d := struct {
X int `json:"x"`
Y int `json:"y"`
}{}
e := struct {
X int `json:"x"`
Y int `json:"y"`
}{}
var f struct {
X int `json:"x"`
Y int `json:"y"`
}
var g struct {
X int `json:"x"`
Y int `json:"y"`
}
_, _, _, _, _, _, _ = a, b, c, d, e, f, g
}