Skip to content

Commit f003541

Browse files
ldezSeigeC
authored andcommitted
staticcheck: configuration for staticcheck, gosimple, stylecheck (golangci#2017)
1 parent 2891937 commit f003541

File tree

7 files changed

+186
-15
lines changed

7 files changed

+186
-15
lines changed

.golangci.example.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ linters-settings:
366366
gosimple:
367367
# Select the Go version to target. The default is '1.13'.
368368
go: "1.15"
369+
# https://staticcheck.io/docs/options#checks
370+
checks: [ "all" ]
369371

370372
govet:
371373
# report about shadowed variables
@@ -519,10 +521,21 @@ linters-settings:
519521
staticcheck:
520522
# Select the Go version to target. The default is '1.13'.
521523
go: "1.15"
524+
# https://staticcheck.io/docs/options#checks
525+
checks: [ "all" ]
522526

523527
stylecheck:
524528
# Select the Go version to target. The default is '1.13'.
525529
go: "1.15"
530+
# https://staticcheck.io/docs/options#checks
531+
checks: [ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022" ]
532+
# https://staticcheck.io/docs/options#dot_import_whitelist
533+
dot-import-whitelist:
534+
- fmt
535+
# https://staticcheck.io/docs/options#initialisms
536+
initialisms: [ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS" ]
537+
# https://staticcheck.io/docs/options#http_status_code_whitelist
538+
http-status-code-whitelist: [ "200", "400", "404", "500" ]
526539

527540
tagliatelle:
528541
# check the struck tag name case

pkg/config/linters_settings.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,15 @@ type RowsErrCheckSettings struct {
394394

395395
type StaticCheckSettings struct {
396396
GoVersion string `mapstructure:"go"`
397+
398+
Checks []string `mapstructure:"checks"`
399+
Initialisms []string `mapstructure:"initialisms"` // only for stylecheck
400+
DotImportWhitelist []string `mapstructure:"dot-import-whitelist"` // only for stylecheck
401+
HTTPStatusCodeWhitelist []string `mapstructure:"http-status-code-whitelist"` // only for stylecheck
402+
}
403+
404+
func (s *StaticCheckSettings) HasConfiguration() bool {
405+
return len(s.Initialisms) > 0 || len(s.HTTPStatusCodeWhitelist) > 0 || len(s.DotImportWhitelist) > 0 || len(s.Checks) > 0
397406
}
398407

399408
type StructCheckSettings struct {

pkg/golinters/gosimple.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import (
88
)
99

1010
func NewGosimple(settings *config.StaticCheckSettings) *goanalysis.Linter {
11-
analyzers := setupStaticCheckAnalyzers(simple.Analyzers, settings)
11+
cfg := staticCheckConfig(settings)
12+
13+
analyzers := setupStaticCheckAnalyzers(simple.Analyzers, getGoVersion(settings), cfg.Checks)
1214

1315
return goanalysis.NewLinter(
1416
"gosimple",

pkg/golinters/staticcheck.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import (
88
)
99

1010
func NewStaticcheck(settings *config.StaticCheckSettings) *goanalysis.Linter {
11-
analyzers := setupStaticCheckAnalyzers(staticcheck.Analyzers, settings)
11+
cfg := staticCheckConfig(settings)
12+
13+
analyzers := setupStaticCheckAnalyzers(staticcheck.Analyzers, getGoVersion(settings), cfg.Checks)
1214

1315
return goanalysis.NewLinter(
1416
"staticcheck",

pkg/golinters/staticcheck_common.go

Lines changed: 145 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,167 @@
11
package golinters
22

33
import (
4+
"strings"
5+
"unicode"
6+
47
"golang.org/x/tools/go/analysis"
8+
scconfig "honnef.co/go/tools/config"
59

610
"github.com/golangci/golangci-lint/pkg/config"
711
"github.com/golangci/golangci-lint/pkg/logutils"
812
)
913

1014
var debugf = logutils.Debug("megacheck")
1115

12-
func setupStaticCheckAnalyzers(m map[string]*analysis.Analyzer, settings *config.StaticCheckSettings) []*analysis.Analyzer {
13-
var ret []*analysis.Analyzer
14-
for _, v := range m {
15-
setAnalyzerGoVersion(v, settings)
16-
ret = append(ret, v)
16+
func getGoVersion(settings *config.StaticCheckSettings) string {
17+
var goVersion string
18+
if settings != nil {
19+
goVersion = settings.GoVersion
20+
}
21+
22+
if goVersion != "" {
23+
return goVersion
1724
}
18-
return ret
19-
}
2025

21-
func setAnalyzerGoVersion(a *analysis.Analyzer, settings *config.StaticCheckSettings) {
2226
// TODO: uses "1.13" for backward compatibility, but in the future (v2) must be set by using build.Default.ReleaseTags like staticcheck.
23-
goVersion := "1.13"
24-
if settings != nil && settings.GoVersion != "" {
25-
goVersion = settings.GoVersion
27+
return "1.13"
28+
}
29+
30+
func setupStaticCheckAnalyzers(src map[string]*analysis.Analyzer, goVersion string, checks []string) []*analysis.Analyzer {
31+
var names []string
32+
for name := range src {
33+
names = append(names, name)
34+
}
35+
36+
filter := filterAnalyzerNames(names, checks)
37+
38+
var ret []*analysis.Analyzer
39+
for name, a := range src {
40+
if filter[name] {
41+
setAnalyzerGoVersion(a, goVersion)
42+
ret = append(ret, a)
43+
}
2644
}
2745

46+
return ret
47+
}
48+
49+
func setAnalyzerGoVersion(a *analysis.Analyzer, goVersion string) {
2850
if v := a.Flags.Lookup("go"); v != nil {
2951
if err := v.Value.Set(goVersion); err != nil {
3052
debugf("Failed to set go version: %s", err)
3153
}
3254
}
3355
}
56+
57+
func staticCheckConfig(settings *config.StaticCheckSettings) *scconfig.Config {
58+
var cfg *scconfig.Config
59+
60+
if settings == nil || !settings.HasConfiguration() {
61+
return &scconfig.Config{
62+
Checks: []string{"*"}, // override for compatibility reason. Must drop in the next major version.
63+
Initialisms: scconfig.DefaultConfig.Initialisms,
64+
DotImportWhitelist: scconfig.DefaultConfig.DotImportWhitelist,
65+
HTTPStatusCodeWhitelist: scconfig.DefaultConfig.HTTPStatusCodeWhitelist,
66+
}
67+
}
68+
69+
cfg = &scconfig.Config{
70+
Checks: settings.Checks,
71+
Initialisms: settings.Initialisms,
72+
DotImportWhitelist: settings.DotImportWhitelist,
73+
HTTPStatusCodeWhitelist: settings.HTTPStatusCodeWhitelist,
74+
}
75+
76+
if len(cfg.Checks) == 0 {
77+
cfg.Checks = append(cfg.Checks, "*") // override for compatibility reason. Must drop in the next major version.
78+
}
79+
80+
if len(cfg.Initialisms) == 0 {
81+
cfg.Initialisms = append(cfg.Initialisms, scconfig.DefaultConfig.Initialisms...)
82+
}
83+
84+
if len(cfg.DotImportWhitelist) == 0 {
85+
cfg.DotImportWhitelist = append(cfg.DotImportWhitelist, scconfig.DefaultConfig.DotImportWhitelist...)
86+
}
87+
88+
if len(cfg.HTTPStatusCodeWhitelist) == 0 {
89+
cfg.HTTPStatusCodeWhitelist = append(cfg.HTTPStatusCodeWhitelist, scconfig.DefaultConfig.HTTPStatusCodeWhitelist...)
90+
}
91+
92+
cfg.Checks = normalizeList(cfg.Checks)
93+
cfg.Initialisms = normalizeList(cfg.Initialisms)
94+
cfg.DotImportWhitelist = normalizeList(cfg.DotImportWhitelist)
95+
cfg.HTTPStatusCodeWhitelist = normalizeList(cfg.HTTPStatusCodeWhitelist)
96+
97+
return cfg
98+
}
99+
100+
// https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/lintcmd/lint.go#L437-L477
101+
// nolint // Keep the original source code.
102+
func filterAnalyzerNames(analyzers []string, checks []string) map[string]bool {
103+
allowedChecks := map[string]bool{}
104+
105+
for _, check := range checks {
106+
b := true
107+
if len(check) > 1 && check[0] == '-' {
108+
b = false
109+
check = check[1:]
110+
}
111+
112+
if check == "*" || check == "all" {
113+
// Match all
114+
for _, c := range analyzers {
115+
allowedChecks[c] = b
116+
}
117+
} else if strings.HasSuffix(check, "*") {
118+
// Glob
119+
prefix := check[:len(check)-1]
120+
isCat := strings.IndexFunc(prefix, func(r rune) bool { return unicode.IsNumber(r) }) == -1
121+
122+
for _, a := range analyzers {
123+
idx := strings.IndexFunc(a, func(r rune) bool { return unicode.IsNumber(r) })
124+
if isCat {
125+
// Glob is S*, which should match S1000 but not SA1000
126+
cat := a[:idx]
127+
if prefix == cat {
128+
allowedChecks[a] = b
129+
}
130+
} else {
131+
// Glob is S1*
132+
if strings.HasPrefix(a, prefix) {
133+
allowedChecks[a] = b
134+
}
135+
}
136+
}
137+
} else {
138+
// Literal check name
139+
allowedChecks[check] = b
140+
}
141+
}
142+
return allowedChecks
143+
}
144+
145+
// https://github.com/dominikh/go-tools/blob/9bf17c0388a65710524ba04c2d821469e639fdc2/config/config.go#L95-L116
146+
func normalizeList(list []string) []string {
147+
if len(list) > 1 {
148+
nlist := make([]string, 0, len(list))
149+
nlist = append(nlist, list[0])
150+
for i, el := range list[1:] {
151+
if el != list[i] {
152+
nlist = append(nlist, el)
153+
}
154+
}
155+
list = nlist
156+
}
157+
158+
for _, el := range list {
159+
if el == "inherit" {
160+
// This should never happen, because the default config
161+
// should not use "inherit"
162+
panic(`unresolved "inherit"`)
163+
}
164+
}
165+
166+
return list
167+
}

pkg/golinters/stylecheck.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
package golinters
22

33
import (
4+
"golang.org/x/tools/go/analysis"
5+
scconfig "honnef.co/go/tools/config"
46
"honnef.co/go/tools/stylecheck"
57

68
"github.com/golangci/golangci-lint/pkg/config"
79
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
810
)
911

1012
func NewStylecheck(settings *config.StaticCheckSettings) *goanalysis.Linter {
11-
analyzers := setupStaticCheckAnalyzers(stylecheck.Analyzers, settings)
13+
cfg := staticCheckConfig(settings)
14+
15+
// `scconfig.Analyzer` is a singleton, then it's not possible to have more than one instance for all staticcheck "sub-linters".
16+
// When we will merge the 4 "sub-linters", the problem will disappear: https://github.com/golangci/golangci-lint/issues/357
17+
// Currently only stylecheck analyzer has a configuration in staticcheck.
18+
scconfig.Analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
19+
return cfg, nil
20+
}
21+
22+
analyzers := setupStaticCheckAnalyzers(stylecheck.Analyzers, getGoVersion(settings), cfg.Checks)
1223

1324
return goanalysis.NewLinter(
1425
"stylecheck",

pkg/golinters/unused.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func NewUnused(settings *config.StaticCheckSettings) *goanalysis.Linter {
5454
},
5555
}
5656

57-
setAnalyzerGoVersion(analyzer, settings)
57+
setAnalyzerGoVersion(analyzer, getGoVersion(settings))
5858

5959
lnt := goanalysis.NewLinter(
6060
name,

0 commit comments

Comments
 (0)