mirror of
https://github.com/mgechev/revive.git
synced 2025-11-23 22:04:49 +02:00
feature: struct-tag warns on (useless) options on ignored fields (#1487)
This commit is contained in:
@@ -180,6 +180,10 @@ func (w lintStructTagRule) checkTaggedField(checkCtx *checkContext, f *ast.Field
|
|||||||
w.addFailureWithTagKey(f.Tag, msg, tag.Key)
|
w.addFailureWithTagKey(f.Tag, msg, tag.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if msg, ok := checkOptionsOnIgnoredField(tag); !ok {
|
||||||
|
w.addFailureWithTagKey(f.Tag, msg, tag.Key)
|
||||||
|
}
|
||||||
|
|
||||||
checker, ok := w.tagCheckers[tagKey(tag.Key)]
|
checker, ok := w.tagCheckers[tagKey(tag.Key)]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue // we don't have a checker for the tag
|
continue // we don't have a checker for the tag
|
||||||
@@ -561,13 +565,6 @@ func checkYAMLTag(checkCtx *checkContext, tag *structtag.Tag, _ ast.Expr) (messa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkSpannerTag(checkCtx *checkContext, tag *structtag.Tag, _ ast.Expr) (message string, succeeded bool) {
|
func checkSpannerTag(checkCtx *checkContext, tag *structtag.Tag, _ ast.Expr) (message string, succeeded bool) {
|
||||||
if tag.Name == "-" {
|
|
||||||
if len(tag.Options) > 0 {
|
|
||||||
return fmt.Sprintf("useless option(s) %s for ignored field", strings.Join(tag.Options, ",")), false
|
|
||||||
}
|
|
||||||
return "", true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, opt := range tag.Options {
|
for _, opt := range tag.Options {
|
||||||
if !checkCtx.isUserDefined(keySpanner, opt) {
|
if !checkCtx.isUserDefined(keySpanner, opt) {
|
||||||
return fmt.Sprintf(msgUnknownOption, opt), false
|
return fmt.Sprintf(msgUnknownOption, opt), false
|
||||||
@@ -577,6 +574,28 @@ func checkSpannerTag(checkCtx *checkContext, tag *structtag.Tag, _ ast.Expr) (me
|
|||||||
return "", true
|
return "", true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkOptionsOnIgnoredField checks if an ignored struct field (tag name "-") has any options specified.
|
||||||
|
// It returns a message and false if there are useless options present, or an empty message and true if valid.
|
||||||
|
func checkOptionsOnIgnoredField(tag *structtag.Tag) (message string, succeeded bool) {
|
||||||
|
if tag.Name != "-" {
|
||||||
|
return "", true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch len(tag.Options) {
|
||||||
|
case 0:
|
||||||
|
return "", true
|
||||||
|
case 1:
|
||||||
|
opt := strings.TrimSpace(tag.Options[0])
|
||||||
|
if opt == "" {
|
||||||
|
return "", true // accept "-," as options
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("useless option %s for ignored field", opt), false
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("useless options %s for ignored field", strings.Join(tag.Options, ",")), false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkValidateOptionsAlternatives(checkCtx *checkContext, alternatives []string) (message string, succeeded bool) {
|
func checkValidateOptionsAlternatives(checkCtx *checkContext, alternatives []string) (message string, succeeded bool) {
|
||||||
for _, alternative := range alternatives {
|
for _, alternative := range alternatives {
|
||||||
alternative := strings.TrimSpace(alternative)
|
alternative := strings.TrimSpace(alternative)
|
||||||
|
|||||||
6
testdata/struct_tag.go
vendored
6
testdata/struct_tag.go
vendored
@@ -192,7 +192,7 @@ type PropertiesTags struct {
|
|||||||
type SpannerUser struct {
|
type SpannerUser struct {
|
||||||
ID int `spanner:"user_id"`
|
ID int `spanner:"user_id"`
|
||||||
Name string `spanner:"full_name"`
|
Name string `spanner:"full_name"`
|
||||||
Email string `spanner:"-"` // Valid: ignore field
|
Email string `spanner:"-"` // Valid: ignore field
|
||||||
CreatedAt time.Time `spanner:"created_at"`
|
CreatedAt time.Time `spanner:"created_at"`
|
||||||
UpdatedAt time.Time `spanner:"updated_at,unknown"` // MATCH /unknown option "unknown" in spanner tag/
|
UpdatedAt time.Time `spanner:"updated_at,unknown"` // MATCH /unknown option "unknown" in spanner tag/
|
||||||
}
|
}
|
||||||
|
|||||||
47
testdata/struct_tag_user_options.go
vendored
47
testdata/struct_tag_user_options.go
vendored
@@ -1,5 +1,7 @@
|
|||||||
package fixtures
|
package fixtures
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type RangeAllocation struct {
|
type RangeAllocation struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
@@ -49,6 +51,49 @@ type TomlUser struct {
|
|||||||
|
|
||||||
type SpannerUserOptions struct {
|
type SpannerUserOptions struct {
|
||||||
ID int `spanner:"user_id,mySpannerOption"`
|
ID int `spanner:"user_id,mySpannerOption"`
|
||||||
A int `spanner:"-,mySpannerOption"` // MATCH /useless option(s) mySpannerOption for ignored field in spanner tag/
|
A int `spanner:"-,mySpannerOption"` // MATCH /useless option mySpannerOption for ignored field in spanner tag/
|
||||||
Name string `spanner:"full_name,unknownOption"` // MATCH /unknown option "unknownOption" in spanner tag/
|
Name string `spanner:"full_name,unknownOption"` // MATCH /unknown option "unknownOption" in spanner tag/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type uselessOptions struct {
|
||||||
|
A int `bson:"-,"`
|
||||||
|
B int `bson:"-,omitempty"` // MATCH /useless option omitempty for ignored field in bson tag/
|
||||||
|
C int `bson:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in bson tag/
|
||||||
|
D int `datastore:"-,"`
|
||||||
|
E int `datastore:"-,omitempty"` // MATCH /useless option omitempty for ignored field in datastore tag/
|
||||||
|
F int `datastore:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in datastore tag/
|
||||||
|
G int `json:"-,"`
|
||||||
|
H int `json:"-,omitempty"` // MATCH /useless option omitempty for ignored field in json tag/
|
||||||
|
I int `json:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in json tag/
|
||||||
|
J int `mapstructure:"-,"`
|
||||||
|
K int `mapstructure:"-,squash"` // MATCH /useless option squash for ignored field in mapstructure tag/
|
||||||
|
L int `mapstructure:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in mapstructure tag/
|
||||||
|
M int `properties:"-,"`
|
||||||
|
N int `properties:"-,default=15"` // MATCH /useless option default=15 for ignored field in properties tag/
|
||||||
|
O time.Time `properties:"-,layout=2006-01-02,default=2006-01-02"` // MATCH /useless options layout=2006-01-02,default=2006-01-02 for ignored field in properties tag/
|
||||||
|
P int `spanner:"-,"`
|
||||||
|
Q int `spanner:"-,mySpannerOption"` // MATCH /useless option mySpannerOption for ignored field in spanner tag/
|
||||||
|
R int `spanner:"-,mySpannerOption,mySpannerOption"` // MATCH /useless options mySpannerOption,mySpannerOption for ignored field in spanner tag/
|
||||||
|
S int `toml:"-,"`
|
||||||
|
T int `toml:"-,omitempty"` // MATCH /useless option omitempty for ignored field in toml tag/
|
||||||
|
U int `toml:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in toml tag/
|
||||||
|
V int `url:"-,"`
|
||||||
|
W int `url:"-,omitempty"` // MATCH /useless option omitempty for ignored field in url tag/
|
||||||
|
X int `url:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in url tag/
|
||||||
|
Y int `xml:"-,"`
|
||||||
|
Z int `xml:"-,omitempty"` // MATCH /useless option omitempty for ignored field in xml tag/
|
||||||
|
Aa int `xml:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in xml tag/
|
||||||
|
Ba int `yaml:"-,"`
|
||||||
|
Ca int `yaml:"-,omitempty"` // MATCH /useless option omitempty for ignored field in yaml tag/
|
||||||
|
Da int `yaml:"-,omitempty,omitempty"` // MATCH /useless options omitempty,omitempty for ignored field in yaml tag/
|
||||||
|
|
||||||
|
// MATCH:59 /unknown option "" in bson tag/
|
||||||
|
// MATCH:62 /unknown option "" in datastore tag/
|
||||||
|
// MATCH:68 /unknown option "" in mapstructure tag/
|
||||||
|
// MATCH:71 /unknown or malformed option "" in properties tag/
|
||||||
|
// MATCH:74 /unknown option "" in spanner tag/
|
||||||
|
// MATCH:77 /unknown option "" in toml tag/
|
||||||
|
// MATCH:80 /unknown option "" in url tag/
|
||||||
|
// MATCH:83 /unknown option "" in xml tag/
|
||||||
|
// MATCH:86 /unknown option "" in yaml tag/
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user