From 3cc63731178bb15ebf9d645f93e5f8428db11aa7 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 21 Jan 2023 16:36:35 +0400 Subject: [PATCH] feat: add musttag linter (#3386) Co-authored-by: Fernandez Ludovic --- .golangci.reference.yml | 13 +++++++++++++ go.mod | 1 + go.sum | 2 ++ pkg/config/linters_settings.go | 9 +++++++++ pkg/golinters/musttag.go | 29 +++++++++++++++++++++++++++++ pkg/lint/lintersdb/manager.go | 8 ++++++++ test/testdata/configs/musttag.yml | 9 +++++++++ test/testdata/musttag.go | 27 +++++++++++++++++++++++++++ test/testdata/musttag_custom.go | 28 ++++++++++++++++++++++++++++ 9 files changed, 126 insertions(+) create mode 100644 pkg/golinters/musttag.go create mode 100644 test/testdata/configs/musttag.yml create mode 100644 test/testdata/musttag.go create mode 100644 test/testdata/musttag_custom.go diff --git a/.golangci.reference.yml b/.golangci.reference.yml index fda48cce..bc30cd62 100644 --- a/.golangci.reference.yml +++ b/.golangci.reference.yml @@ -1209,6 +1209,17 @@ linters-settings: ignore-words: - someword + musttag: + # A set of custom functions to check in addition to the builtin ones. + # Default: json, xml, gopkg.in/yaml.v3, BurntSushi/toml, mitchellh/mapstructure + functions: + # The full name of the function, including the package. + - name: github.com/jmoiron/sqlx.Get + # The struct tag whose presence should be ensured. + tag: db + # The position of the argument to check. + arg-pos: 1 + nakedret: # Make an issue if func has more lines of code than this setting, and it has naked returns. # Default: 30 @@ -2037,6 +2048,7 @@ linters: - makezero - maligned - misspell + - musttag - nakedret - nestif - nilerr @@ -2145,6 +2157,7 @@ linters: - makezero - maligned - misspell + - musttag - nakedret - nestif - nilerr diff --git a/go.mod b/go.mod index 47dd406f..4848f9bc 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( github.com/jingyugao/rowserrcheck v1.1.1 github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af github.com/julz/importas v0.1.0 + github.com/junk1tm/musttag v0.4.1 github.com/kisielk/errcheck v1.6.3 github.com/kkHAIKE/contextcheck v1.1.3 github.com/kulti/thelper v0.6.3 diff --git a/go.sum b/go.sum index 6ee4c629..76332121 100644 --- a/go.sum +++ b/go.sum @@ -308,6 +308,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/junk1tm/musttag v0.4.1 h1:RepN7vE8xObm/AC3WiynRcpFBt8paQR7ztgi09xhTsU= +github.com/junk1tm/musttag v0.4.1/go.mod h1:XkcL/9O6RmD88JBXb+I15nYRl9W4ExhgQeCBEhfMC8U= github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8= github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= diff --git a/pkg/config/linters_settings.go b/pkg/config/linters_settings.go index dfc0dc8b..76a16b87 100644 --- a/pkg/config/linters_settings.go +++ b/pkg/config/linters_settings.go @@ -179,6 +179,7 @@ type LintersSettings struct { Makezero MakezeroSettings Maligned MalignedSettings Misspell MisspellSettings + MustTag MustTagSettings Nakedret NakedretSettings Nestif NestifSettings NilNil NilNilSettings @@ -538,6 +539,14 @@ type MisspellSettings struct { IgnoreWords []string `mapstructure:"ignore-words"` } +type MustTagSettings struct { + Functions []struct { + Name string `mapstructure:"name"` + Tag string `mapstructure:"tag"` + ArgPos int `mapstructure:"arg-pos"` + } `mapstructure:"functions"` +} + type NakedretSettings struct { MaxFuncLines int `mapstructure:"max-func-lines"` } diff --git a/pkg/golinters/musttag.go b/pkg/golinters/musttag.go new file mode 100644 index 00000000..75500b5a --- /dev/null +++ b/pkg/golinters/musttag.go @@ -0,0 +1,29 @@ +package golinters + +import ( + "github.com/junk1tm/musttag" + "golang.org/x/tools/go/analysis" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters/goanalysis" +) + +func NewMustTag(setting *config.MustTagSettings) *goanalysis.Linter { + var funcs []musttag.Func + + if setting != nil { + for _, fn := range setting.Functions { + funcs = append(funcs, musttag.Func{ + Name: fn.Name, + Tag: fn.Tag, + ArgPos: fn.ArgPos, + }) + } + } + + a := musttag.New(funcs...) + + return goanalysis. + NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil). + WithLoadMode(goanalysis.LoadModeTypesInfo) +} diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index ab8f1835..6ea531b8 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -147,6 +147,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { makezeroCfg *config.MakezeroSettings malignedCfg *config.MalignedSettings misspellCfg *config.MisspellSettings + musttagCfg *config.MustTagSettings nakedretCfg *config.NakedretSettings nestifCfg *config.NestifSettings nilNilCfg *config.NilNilSettings @@ -224,6 +225,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { makezeroCfg = &m.cfg.LintersSettings.Makezero malignedCfg = &m.cfg.LintersSettings.Maligned misspellCfg = &m.cfg.LintersSettings.Misspell + musttagCfg = &m.cfg.LintersSettings.MustTag nakedretCfg = &m.cfg.LintersSettings.Nakedret nestifCfg = &m.cfg.LintersSettings.Nestif nilNilCfg = &m.cfg.LintersSettings.NilNil @@ -632,6 +634,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithAutoFix(). WithURL("https://github.com/client9/misspell"), + linter.NewConfig(golinters.NewMustTag(musttagCfg)). + WithSince("v1.51.0"). + WithLoadForGoAnalysis(). + WithPresets(linter.PresetStyle, linter.PresetBugs). + WithURL("https://github.com/junk1tm/musttag"), + linter.NewConfig(golinters.NewNakedret(nakedretCfg)). WithSince("v1.19.0"). WithPresets(linter.PresetStyle). diff --git a/test/testdata/configs/musttag.yml b/test/testdata/configs/musttag.yml new file mode 100644 index 00000000..399e236b --- /dev/null +++ b/test/testdata/configs/musttag.yml @@ -0,0 +1,9 @@ +linters-settings: + musttag: + functions: + - name: encoding/asn1.Marshal + tag: asn1 + arg-pos: 0 + - name: encoding/asn1.Unmarshal + tag: asn1 + arg-pos: 1 diff --git a/test/testdata/musttag.go b/test/testdata/musttag.go new file mode 100644 index 00000000..daf84298 --- /dev/null +++ b/test/testdata/musttag.go @@ -0,0 +1,27 @@ +//golangcitest:args -Emusttag +package testdata + +import ( + "encoding/asn1" + "encoding/json" +) + +// builtin functions: +func musttagJSON() { + var user struct { // want `exported fields should be annotated with the "json" tag` + Name string + Email string `json:"email"` + } + json.Marshal(user) + json.Unmarshal(nil, &user) +} + +// custom functions from config: +func musttagASN1() { + var user struct { + Name string + Email string `asn1:"email"` + } + asn1.Marshal(user) + asn1.Unmarshal(nil, &user) +} diff --git a/test/testdata/musttag_custom.go b/test/testdata/musttag_custom.go new file mode 100644 index 00000000..42bdea3f --- /dev/null +++ b/test/testdata/musttag_custom.go @@ -0,0 +1,28 @@ +//golangcitest:args -Emusttag +//golangcitest:config_path testdata/configs/musttag.yml +package testdata + +import ( + "encoding/asn1" + "encoding/json" +) + +// builtin functions: +func musttagJSONCustom() { + var user struct { // want `exported fields should be annotated with the "json" tag` + Name string + Email string `json:"email"` + } + json.Marshal(user) + json.Unmarshal(nil, &user) +} + +// custom functions from config: +func musttagASN1Custom() { + var user struct { // want `exported fields should be annotated with the "asn1" tag` + Name string + Email string `asn1:"email"` + } + asn1.Marshal(user) + asn1.Unmarshal(nil, &user) +}