Skip to content

Commit fc1260e

Browse files
committed
govet: implement analyzers config
1 parent fc8d614 commit fc1260e

File tree

5 files changed

+144
-8
lines changed

5 files changed

+144
-8
lines changed

.golangci.example.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ linters-settings:
9595
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
9696
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
9797
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
98+
99+
# enable or disable analyzers by name
100+
enable:
101+
- atomicalign
102+
enable-all: false
103+
disable:
104+
- shadow
105+
disable-all: false
98106
golint:
99107
# minimal confidence for issues, default is 0.8
100108
min-confidence: 0.8

pkg/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ type LintersSettings struct {
183183
type GovetSettings struct {
184184
CheckShadowing bool `mapstructure:"check-shadowing"`
185185
Settings map[string]map[string]interface{}
186+
187+
Enable []string
188+
Disable []string
189+
EnableAll bool `mapstructure:"enable-all"`
190+
DisableAll bool `mapstructure:"disable-all"`
186191
}
187192

188193
type ErrcheckSettings struct {

pkg/golinters/govet.go

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"golang.org/x/tools/go/analysis/passes/asmdecl"
1212
"golang.org/x/tools/go/analysis/passes/assign"
1313
"golang.org/x/tools/go/analysis/passes/atomic"
14+
"golang.org/x/tools/go/analysis/passes/atomicalign"
1415
"golang.org/x/tools/go/analysis/passes/bools"
1516
"golang.org/x/tools/go/analysis/passes/buildtag"
1617
"golang.org/x/tools/go/analysis/passes/cgocall"
@@ -33,9 +34,37 @@ import (
3334
"golang.org/x/tools/go/analysis/passes/unusedresult"
3435
)
3536

36-
func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter {
37-
analyzers := []*analysis.Analyzer{
38-
// the traditional vet suite:
37+
func getAllAnalyzers() []*analysis.Analyzer {
38+
return []*analysis.Analyzer{
39+
asmdecl.Analyzer,
40+
assign.Analyzer,
41+
atomic.Analyzer,
42+
atomicalign.Analyzer,
43+
bools.Analyzer,
44+
buildtag.Analyzer,
45+
cgocall.Analyzer,
46+
composite.Analyzer,
47+
copylock.Analyzer,
48+
errorsas.Analyzer,
49+
httpresponse.Analyzer,
50+
loopclosure.Analyzer,
51+
lostcancel.Analyzer,
52+
nilfunc.Analyzer,
53+
printf.Analyzer,
54+
shadow.Analyzer,
55+
shift.Analyzer,
56+
stdmethods.Analyzer,
57+
structtag.Analyzer,
58+
tests.Analyzer,
59+
unmarshal.Analyzer,
60+
unreachable.Analyzer,
61+
unsafeptr.Analyzer,
62+
unusedresult.Analyzer,
63+
}
64+
}
65+
66+
func getDefaultAnalyzers() []*analysis.Analyzer {
67+
return []*analysis.Analyzer{
3968
asmdecl.Analyzer,
4069
assign.Analyzer,
4170
atomic.Analyzer,
@@ -59,20 +88,64 @@ func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter {
5988
unsafeptr.Analyzer,
6089
unusedresult.Analyzer,
6190
}
91+
}
92+
93+
func isAnalyzerEnabled(name string, cfg *config.GovetSettings, defaultAnalyzers []*analysis.Analyzer) bool {
94+
if cfg.EnableAll {
95+
return true
96+
}
97+
// Raw for loops should be OK on small slice lengths.
98+
for _, n := range cfg.Enable {
99+
if n == name {
100+
return true
101+
}
102+
}
103+
for _, n := range cfg.Disable {
104+
if n == name {
105+
return true
106+
}
107+
}
108+
if cfg.DisableAll {
109+
return false
110+
}
111+
for _, a := range defaultAnalyzers {
112+
if a.Name == name {
113+
return true
114+
}
115+
}
116+
return false
117+
}
118+
119+
func analyzersFromConfig(cfg *config.GovetSettings) []*analysis.Analyzer {
120+
if cfg == nil {
121+
return getDefaultAnalyzers()
122+
}
123+
if cfg.CheckShadowing {
124+
// Keeping for backward compatibility.
125+
cfg.Enable = append(cfg.Enable, shadow.Analyzer.Name)
126+
}
127+
128+
var enabledAnalyzers []*analysis.Analyzer
129+
defaultAnalyzers := getDefaultAnalyzers()
130+
for _, a := range getAllAnalyzers() {
131+
if isAnalyzerEnabled(a.Name, cfg, defaultAnalyzers) {
132+
enabledAnalyzers = append(enabledAnalyzers, a)
133+
}
134+
}
135+
136+
return enabledAnalyzers
137+
}
62138

139+
func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter {
63140
var settings map[string]map[string]interface{}
64141
if cfg != nil {
65-
if cfg.CheckShadowing {
66-
analyzers = append(analyzers, shadow.Analyzer)
67-
}
68142
settings = cfg.Settings
69143
}
70-
71144
return goanalysis.NewLinter(
72145
"govet",
73146
"Vet examines Go source code and reports suspicious constructs, "+
74147
"such as Printf calls whose arguments do not align with the format string",
75-
analyzers,
148+
analyzersFromConfig(cfg),
76149
settings,
77150
)
78151
}

pkg/golinters/govet_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package golinters
2+
3+
import (
4+
"sort"
5+
"testing"
6+
7+
"golang.org/x/tools/go/analysis"
8+
"golang.org/x/tools/go/analysis/passes/shadow"
9+
)
10+
11+
func TestGovet(t *testing.T) {
12+
// Checking that every default analyzer is in "all analyzers" list.
13+
allAnalyzers := getAllAnalyzers()
14+
checkList := append(getDefaultAnalyzers(),
15+
shadow.Analyzer, // special case, used in analyzersFromConfig
16+
)
17+
for _, defaultAnalyzer := range checkList {
18+
found := false
19+
for _, a := range allAnalyzers {
20+
if a.Name == defaultAnalyzer.Name {
21+
found = true
22+
break
23+
}
24+
}
25+
if !found {
26+
t.Errorf("%s is not in allAnalyzers", defaultAnalyzer.Name)
27+
}
28+
}
29+
}
30+
31+
type sortedAnalyzers []*analysis.Analyzer
32+
33+
func (p sortedAnalyzers) Len() int { return len(p) }
34+
func (p sortedAnalyzers) Less(i, j int) bool { return p[i].Name < p[j].Name }
35+
func (p sortedAnalyzers) Swap(i, j int) { p[i].Name, p[j].Name = p[j].Name, p[i].Name }
36+
37+
func TestGovetSorted(t *testing.T) {
38+
// Keeping analyzers sorted so their order match the import order.
39+
t.Run("All", func(t *testing.T) {
40+
if !sort.IsSorted(sortedAnalyzers(getAllAnalyzers())) {
41+
t.Error("please keep all analyzers list sorted by name")
42+
}
43+
})
44+
t.Run("Default", func(t *testing.T) {
45+
if !sort.IsSorted(sortedAnalyzers(getDefaultAnalyzers())) {
46+
t.Error("please keep default analyzers list sorted by name")
47+
}
48+
})
49+
}

vendor/modules.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ golang.org/x/tools/go/analysis
207207
golang.org/x/tools/go/analysis/passes/asmdecl
208208
golang.org/x/tools/go/analysis/passes/assign
209209
golang.org/x/tools/go/analysis/passes/atomic
210+
golang.org/x/tools/go/analysis/passes/atomicalign
210211
golang.org/x/tools/go/analysis/passes/bools
211212
golang.org/x/tools/go/analysis/passes/buildssa
212213
golang.org/x/tools/go/analysis/passes/buildtag

0 commit comments

Comments
 (0)