Skip to content

Commit 15c57c1

Browse files
authored
fix: speed up "fast" linters (#4653)
1 parent a660182 commit 15c57c1

File tree

5 files changed

+112
-36
lines changed

5 files changed

+112
-36
lines changed

pkg/golinters/typecheck.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ func NewTypecheck() *goanalysis.Linter {
2020
"Like the front-end of a Go compiler, parses and type-checks Go code",
2121
[]*analysis.Analyzer{analyzer},
2222
nil,
23-
).WithLoadMode(goanalysis.LoadModeTypesInfo)
23+
).WithLoadMode(goanalysis.LoadModeNone)
2424
}

pkg/lint/lintersdb/builder_linter.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -752,10 +752,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
752752
linter.NewConfig(golinters.NewTypecheck()).
753753
WithInternal().
754754
WithEnabledByDefault().
755-
WithSince("v1.3.0").
756-
WithLoadForGoAnalysis().
757-
WithPresets(linter.PresetBugs).
758-
WithURL(""),
755+
WithSince("v1.3.0"),
759756

760757
linter.NewConfig(unconvert.New(&cfg.LintersSettings.Unconvert)).
761758
WithSince("v1.0.0").

pkg/lint/lintersdb/manager.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -204,21 +204,30 @@ func (m *Manager) build(enabledByDefaultLinters []*linter.Config) map[string]*li
204204
}
205205

206206
func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) {
207+
mlConfig := &linter.Config{}
208+
207209
var goanalysisLinters []*goanalysis.Linter
208-
goanalysisPresets := map[string]bool{}
210+
209211
for _, lc := range linters {
210212
lnt, ok := lc.Linter.(*goanalysis.Linter)
211213
if !ok {
212214
continue
213215
}
216+
214217
if lnt.LoadMode() == goanalysis.LoadModeWholeProgram {
215218
// It's ineffective by CPU and memory to run whole-program and incremental analyzers at once.
216219
continue
217220
}
218-
goanalysisLinters = append(goanalysisLinters, lnt)
219-
for _, p := range lc.InPresets {
220-
goanalysisPresets[p] = true
221+
222+
mlConfig.LoadMode |= lc.LoadMode
223+
224+
if lc.IsSlowLinter() {
225+
mlConfig.ConsiderSlow()
221226
}
227+
228+
mlConfig.InPresets = append(mlConfig.InPresets, lc.InPresets...)
229+
230+
goanalysisLinters = append(goanalysisLinters, lnt)
222231
}
223232

224233
if len(goanalysisLinters) <= 1 {
@@ -245,22 +254,13 @@ func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) {
245254
return a.Name() <= b.Name()
246255
})
247256

248-
ml := goanalysis.NewMetaLinter(goanalysisLinters)
257+
mlConfig.Linter = goanalysis.NewMetaLinter(goanalysisLinters)
249258

250-
presets := maps.Keys(goanalysisPresets)
251-
sort.Strings(presets)
252-
253-
mlConfig := &linter.Config{
254-
Linter: ml,
255-
EnabledByDefault: false,
256-
InPresets: presets,
257-
AlternativeNames: nil,
258-
OriginalURL: "",
259-
}
259+
sort.Strings(mlConfig.InPresets)
260+
mlConfig.InPresets = slices.Compact(mlConfig.InPresets)
260261

261-
mlConfig = mlConfig.WithLoadForGoAnalysis()
262+
linters[mlConfig.Linter.Name()] = mlConfig
262263

263-
linters[ml.Name()] = mlConfig
264264
m.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters))
265265
}
266266

pkg/lint/lintersdb/manager_test.go

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/stretchr/testify/assert"
77
"github.com/stretchr/testify/require"
8+
"golang.org/x/tools/go/packages"
89

910
"github.com/golangci/golangci-lint/pkg/config"
1011
"github.com/golangci/golangci-lint/pkg/goanalysis"
@@ -55,10 +56,10 @@ func TestManager_GetOptimizedLinters(t *testing.T) {
5556

5657
mlConfig := &linter.Config{
5758
Linter: goanalysis.NewMetaLinter(gaLinters),
58-
InPresets: []string{"bugs", "format"},
59+
InPresets: []string{"format"},
5960
}
6061

61-
expected := []*linter.Config{mlConfig.WithLoadForGoAnalysis()}
62+
expected := []*linter.Config{mlConfig.WithLoadFiles()}
6263

6364
assert.Equal(t, expected, optimizedLinters)
6465
}
@@ -176,8 +177,11 @@ func TestManager_combineGoAnalysisLinters(t *testing.T) {
176177
m, err := NewManager(nil, nil)
177178
require.NoError(t, err)
178179

179-
foo := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
180-
bar := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
180+
fooTyped := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
181+
barTyped := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
182+
183+
fooSyntax := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeSyntax)
184+
barSyntax := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeSyntax)
181185

182186
testCases := []struct {
183187
desc string
@@ -188,37 +192,112 @@ func TestManager_combineGoAnalysisLinters(t *testing.T) {
188192
desc: "no combined, one linter",
189193
linters: map[string]*linter.Config{
190194
"foo": {
191-
Linter: foo,
195+
Linter: fooTyped,
192196
InPresets: []string{"A"},
193197
},
194198
},
195199
expected: map[string]*linter.Config{
196200
"foo": {
197-
Linter: foo,
201+
Linter: fooTyped,
202+
InPresets: []string{"A"},
203+
},
204+
},
205+
},
206+
{
207+
desc: "combined, several linters (typed)",
208+
linters: map[string]*linter.Config{
209+
"foo": {
210+
Linter: fooTyped,
198211
InPresets: []string{"A"},
199212
},
213+
"bar": {
214+
Linter: barTyped,
215+
InPresets: []string{"B"},
216+
},
200217
},
218+
expected: func() map[string]*linter.Config {
219+
mlConfig := &linter.Config{
220+
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}),
221+
InPresets: []string{"A", "B"},
222+
}
223+
224+
return map[string]*linter.Config{
225+
"goanalysis_metalinter": mlConfig,
226+
}
227+
}(),
228+
},
229+
{
230+
desc: "combined, several linters (different LoadMode)",
231+
linters: map[string]*linter.Config{
232+
"foo": {
233+
Linter: fooTyped,
234+
InPresets: []string{"A"},
235+
LoadMode: packages.NeedName,
236+
},
237+
"bar": {
238+
Linter: barTyped,
239+
InPresets: []string{"B"},
240+
LoadMode: packages.NeedTypesSizes,
241+
},
242+
},
243+
expected: func() map[string]*linter.Config {
244+
mlConfig := &linter.Config{
245+
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}),
246+
InPresets: []string{"A", "B"},
247+
LoadMode: packages.NeedName | packages.NeedTypesSizes,
248+
}
249+
250+
return map[string]*linter.Config{
251+
"goanalysis_metalinter": mlConfig,
252+
}
253+
}(),
254+
},
255+
{
256+
desc: "combined, several linters (same LoadMode)",
257+
linters: map[string]*linter.Config{
258+
"foo": {
259+
Linter: fooTyped,
260+
InPresets: []string{"A"},
261+
LoadMode: packages.NeedName,
262+
},
263+
"bar": {
264+
Linter: barTyped,
265+
InPresets: []string{"B"},
266+
LoadMode: packages.NeedName,
267+
},
268+
},
269+
expected: func() map[string]*linter.Config {
270+
mlConfig := &linter.Config{
271+
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}),
272+
InPresets: []string{"A", "B"},
273+
LoadMode: packages.NeedName,
274+
}
275+
276+
return map[string]*linter.Config{
277+
"goanalysis_metalinter": mlConfig,
278+
}
279+
}(),
201280
},
202281
{
203-
desc: "combined, several linters",
282+
desc: "combined, several linters (syntax)",
204283
linters: map[string]*linter.Config{
205284
"foo": {
206-
Linter: foo,
285+
Linter: fooSyntax,
207286
InPresets: []string{"A"},
208287
},
209288
"bar": {
210-
Linter: bar,
289+
Linter: barSyntax,
211290
InPresets: []string{"B"},
212291
},
213292
},
214293
expected: func() map[string]*linter.Config {
215294
mlConfig := &linter.Config{
216-
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{bar, foo}),
295+
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barSyntax, fooSyntax}),
217296
InPresets: []string{"A", "B"},
218297
}
219298

220299
return map[string]*linter.Config{
221-
"goanalysis_metalinter": mlConfig.WithLoadForGoAnalysis(),
300+
"goanalysis_metalinter": mlConfig,
222301
}
223302
}(),
224303
},

test/enabled_linters_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func getEnabledByDefaultFastLintersExcept(t *testing.T, except ...string) []stri
148148
ebdl := m.GetAllEnabledByDefaultLinters()
149149
var ret []string
150150
for _, lc := range ebdl {
151-
if lc.IsSlowLinter() {
151+
if lc.IsSlowLinter() || lc.Internal {
152152
continue
153153
}
154154

@@ -169,7 +169,7 @@ func getAllFastLintersWith(t *testing.T, with ...string) []string {
169169
linters := dbManager.GetAllSupportedLinterConfigs()
170170
ret := append([]string{}, with...)
171171
for _, lc := range linters {
172-
if lc.IsSlowLinter() {
172+
if lc.IsSlowLinter() || lc.Internal {
173173
continue
174174
}
175175
ret = append(ret, lc.Name())
@@ -206,7 +206,7 @@ func getEnabledByDefaultFastLintersWith(t *testing.T, with ...string) []string {
206206
ebdl := dbManager.GetAllEnabledByDefaultLinters()
207207
ret := append([]string{}, with...)
208208
for _, lc := range ebdl {
209-
if lc.IsSlowLinter() {
209+
if lc.IsSlowLinter() || lc.Internal {
210210
continue
211211
}
212212

0 commit comments

Comments
 (0)