forked from golangci/golangci-lint
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathenabled_set.go
209 lines (174 loc) · 5.67 KB
/
enabled_set.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
package lintersdb
import (
"os"
"sort"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/logutils"
)
// EnvTestRun value: "1"
const EnvTestRun = "GL_TEST_RUN"
type EnabledSet struct {
m *Manager
v *Validator
log logutils.Log
cfg *config.Config
debugf logutils.DebugFunc
}
func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Config) *EnabledSet {
return &EnabledSet{
m: m,
v: v,
log: log,
cfg: cfg,
debugf: logutils.Debug(logutils.DebugKeyEnabledLinters),
}
}
func (es EnabledSet) build(lcfg *config.Linters, enabledByDefaultLinters []*linter.Config) map[string]*linter.Config {
es.debugf("Linters config: %#v", lcfg)
resultLintersSet := map[string]*linter.Config{}
switch {
case len(lcfg.Presets) != 0:
break // imply --disable-all
case lcfg.EnableAll:
resultLintersSet = linterConfigsToMap(es.m.GetAllSupportedLinterConfigs())
case lcfg.DisableAll:
break
default:
resultLintersSet = linterConfigsToMap(enabledByDefaultLinters)
}
// --presets can only add linters to default set
for _, p := range lcfg.Presets {
for _, lc := range es.m.GetAllLinterConfigsForPreset(p) {
lc := lc
resultLintersSet[lc.Name()] = lc
}
}
// --fast removes slow linters from current set.
// It should be after --presets to be able to run only fast linters in preset.
// It should be before --enable and --disable to be able to enable or disable specific linter.
if lcfg.Fast {
for name, lc := range resultLintersSet {
if lc.IsSlowLinter() {
delete(resultLintersSet, name)
}
}
}
for _, name := range lcfg.Enable {
for _, lc := range es.m.GetLinterConfigs(name) {
// it's important to use lc.Name() nor name because name can be alias
resultLintersSet[lc.Name()] = lc
}
}
for _, name := range lcfg.Disable {
for _, lc := range es.m.GetLinterConfigs(name) {
// it's important to use lc.Name() nor name because name can be alias
delete(resultLintersSet, lc.Name())
}
}
return resultLintersSet
}
func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error) {
if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil {
return nil, err
}
enabledLinters := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
if os.Getenv(EnvTestRun) == "1" {
es.verbosePrintLintersStatus(enabledLinters)
}
return enabledLinters, nil
}
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
// one metalinter for data reuse and speed up.
func (es EnabledSet) GetOptimizedLinters() ([]*linter.Config, error) {
if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil {
return nil, err
}
resultLintersSet := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
es.verbosePrintLintersStatus(resultLintersSet)
es.combineGoAnalysisLinters(resultLintersSet)
var resultLinters []*linter.Config
for _, lc := range resultLintersSet {
resultLinters = append(resultLinters, lc)
}
// Make order of execution of linters (go/analysis metalinter and unused) stable.
sort.Slice(resultLinters, func(i, j int) bool {
a, b := resultLinters[i], resultLinters[j]
if b.Name() == linter.LastLinter {
return true
}
if a.Name() == linter.LastLinter {
return false
}
if a.DoesChangeTypes != b.DoesChangeTypes {
return b.DoesChangeTypes // move type-changing linters to the end to optimize speed
}
return a.Name() < b.Name()
})
return resultLinters, nil
}
func (es EnabledSet) combineGoAnalysisLinters(linters map[string]*linter.Config) {
var goanalysisLinters []*goanalysis.Linter
goanalysisPresets := map[string]bool{}
for _, linter := range linters {
lnt, ok := linter.Linter.(*goanalysis.Linter)
if !ok {
continue
}
if lnt.LoadMode() == goanalysis.LoadModeWholeProgram {
// It's ineffective by CPU and memory to run whole-program and incremental analyzers at once.
continue
}
goanalysisLinters = append(goanalysisLinters, lnt)
for _, p := range linter.InPresets {
goanalysisPresets[p] = true
}
}
if len(goanalysisLinters) <= 1 {
es.debugf("Didn't combine go/analysis linters: got only %d linters", len(goanalysisLinters))
return
}
for _, lnt := range goanalysisLinters {
delete(linters, lnt.Name())
}
// Make order of execution of go/analysis analyzers stable.
sort.Slice(goanalysisLinters, func(i, j int) bool {
a, b := goanalysisLinters[i], goanalysisLinters[j]
if b.Name() == linter.LastLinter {
return true
}
if a.Name() == linter.LastLinter {
return false
}
return a.Name() <= b.Name()
})
ml := goanalysis.NewMetaLinter(goanalysisLinters)
var presets []string
for p := range goanalysisPresets {
presets = append(presets, p)
}
mlConfig := &linter.Config{
Linter: ml,
EnabledByDefault: false,
InPresets: presets,
AlternativeNames: nil,
OriginalURL: "",
}
mlConfig = mlConfig.WithLoadForGoAnalysis()
linters[ml.Name()] = mlConfig
es.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters))
}
func (es EnabledSet) verbosePrintLintersStatus(lcs map[string]*linter.Config) {
var linterNames []string
for _, lc := range lcs {
linterNames = append(linterNames, lc.Name())
}
sort.StringSlice(linterNames).Sort()
es.log.Infof("Active %d linters: %s", len(linterNames), linterNames)
if len(es.cfg.Linters.Presets) != 0 {
sort.StringSlice(es.cfg.Linters.Presets).Sort()
es.log.Infof("Active presets: %s", es.cfg.Linters.Presets)
}
}