fix: speed up "fast" linters (#4653)
This commit is contained in:
parent
a6601827b3
commit
15c57c176e
@ -20,5 +20,5 @@ func NewTypecheck() *goanalysis.Linter {
|
|||||||
"Like the front-end of a Go compiler, parses and type-checks Go code",
|
"Like the front-end of a Go compiler, parses and type-checks Go code",
|
||||||
[]*analysis.Analyzer{analyzer},
|
[]*analysis.Analyzer{analyzer},
|
||||||
nil,
|
nil,
|
||||||
).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
).WithLoadMode(goanalysis.LoadModeNone)
|
||||||
}
|
}
|
||||||
|
@ -752,10 +752,7 @@ func (LinterBuilder) Build(cfg *config.Config) ([]*linter.Config, error) {
|
|||||||
linter.NewConfig(golinters.NewTypecheck()).
|
linter.NewConfig(golinters.NewTypecheck()).
|
||||||
WithInternal().
|
WithInternal().
|
||||||
WithEnabledByDefault().
|
WithEnabledByDefault().
|
||||||
WithSince("v1.3.0").
|
WithSince("v1.3.0"),
|
||||||
WithLoadForGoAnalysis().
|
|
||||||
WithPresets(linter.PresetBugs).
|
|
||||||
WithURL(""),
|
|
||||||
|
|
||||||
linter.NewConfig(unconvert.New(&cfg.LintersSettings.Unconvert)).
|
linter.NewConfig(unconvert.New(&cfg.LintersSettings.Unconvert)).
|
||||||
WithSince("v1.0.0").
|
WithSince("v1.0.0").
|
||||||
|
@ -204,21 +204,30 @@ func (m *Manager) build(enabledByDefaultLinters []*linter.Config) map[string]*li
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) {
|
func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) {
|
||||||
|
mlConfig := &linter.Config{}
|
||||||
|
|
||||||
var goanalysisLinters []*goanalysis.Linter
|
var goanalysisLinters []*goanalysis.Linter
|
||||||
goanalysisPresets := map[string]bool{}
|
|
||||||
for _, lc := range linters {
|
for _, lc := range linters {
|
||||||
lnt, ok := lc.Linter.(*goanalysis.Linter)
|
lnt, ok := lc.Linter.(*goanalysis.Linter)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if lnt.LoadMode() == goanalysis.LoadModeWholeProgram {
|
if lnt.LoadMode() == goanalysis.LoadModeWholeProgram {
|
||||||
// It's ineffective by CPU and memory to run whole-program and incremental analyzers at once.
|
// It's ineffective by CPU and memory to run whole-program and incremental analyzers at once.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
goanalysisLinters = append(goanalysisLinters, lnt)
|
|
||||||
for _, p := range lc.InPresets {
|
mlConfig.LoadMode |= lc.LoadMode
|
||||||
goanalysisPresets[p] = true
|
|
||||||
|
if lc.IsSlowLinter() {
|
||||||
|
mlConfig.ConsiderSlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mlConfig.InPresets = append(mlConfig.InPresets, lc.InPresets...)
|
||||||
|
|
||||||
|
goanalysisLinters = append(goanalysisLinters, lnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(goanalysisLinters) <= 1 {
|
if len(goanalysisLinters) <= 1 {
|
||||||
@ -245,22 +254,13 @@ func (m *Manager) combineGoAnalysisLinters(linters map[string]*linter.Config) {
|
|||||||
return a.Name() <= b.Name()
|
return a.Name() <= b.Name()
|
||||||
})
|
})
|
||||||
|
|
||||||
ml := goanalysis.NewMetaLinter(goanalysisLinters)
|
mlConfig.Linter = goanalysis.NewMetaLinter(goanalysisLinters)
|
||||||
|
|
||||||
presets := maps.Keys(goanalysisPresets)
|
sort.Strings(mlConfig.InPresets)
|
||||||
sort.Strings(presets)
|
mlConfig.InPresets = slices.Compact(mlConfig.InPresets)
|
||||||
|
|
||||||
mlConfig := &linter.Config{
|
linters[mlConfig.Linter.Name()] = mlConfig
|
||||||
Linter: ml,
|
|
||||||
EnabledByDefault: false,
|
|
||||||
InPresets: presets,
|
|
||||||
AlternativeNames: nil,
|
|
||||||
OriginalURL: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
mlConfig = mlConfig.WithLoadForGoAnalysis()
|
|
||||||
|
|
||||||
linters[ml.Name()] = mlConfig
|
|
||||||
m.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters))
|
m.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
|
||||||
"github.com/golangci/golangci-lint/pkg/config"
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
"github.com/golangci/golangci-lint/pkg/goanalysis"
|
"github.com/golangci/golangci-lint/pkg/goanalysis"
|
||||||
@ -55,10 +56,10 @@ func TestManager_GetOptimizedLinters(t *testing.T) {
|
|||||||
|
|
||||||
mlConfig := &linter.Config{
|
mlConfig := &linter.Config{
|
||||||
Linter: goanalysis.NewMetaLinter(gaLinters),
|
Linter: goanalysis.NewMetaLinter(gaLinters),
|
||||||
InPresets: []string{"bugs", "format"},
|
InPresets: []string{"format"},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := []*linter.Config{mlConfig.WithLoadForGoAnalysis()}
|
expected := []*linter.Config{mlConfig.WithLoadFiles()}
|
||||||
|
|
||||||
assert.Equal(t, expected, optimizedLinters)
|
assert.Equal(t, expected, optimizedLinters)
|
||||||
}
|
}
|
||||||
@ -176,8 +177,11 @@ func TestManager_combineGoAnalysisLinters(t *testing.T) {
|
|||||||
m, err := NewManager(nil, nil)
|
m, err := NewManager(nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
foo := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
fooTyped := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||||
bar := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
barTyped := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||||
|
|
||||||
|
fooSyntax := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeSyntax)
|
||||||
|
barSyntax := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeSyntax)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
@ -188,37 +192,112 @@ func TestManager_combineGoAnalysisLinters(t *testing.T) {
|
|||||||
desc: "no combined, one linter",
|
desc: "no combined, one linter",
|
||||||
linters: map[string]*linter.Config{
|
linters: map[string]*linter.Config{
|
||||||
"foo": {
|
"foo": {
|
||||||
Linter: foo,
|
Linter: fooTyped,
|
||||||
InPresets: []string{"A"},
|
InPresets: []string{"A"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]*linter.Config{
|
expected: map[string]*linter.Config{
|
||||||
"foo": {
|
"foo": {
|
||||||
Linter: foo,
|
Linter: fooTyped,
|
||||||
InPresets: []string{"A"},
|
InPresets: []string{"A"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "combined, several linters",
|
desc: "combined, several linters (typed)",
|
||||||
linters: map[string]*linter.Config{
|
linters: map[string]*linter.Config{
|
||||||
"foo": {
|
"foo": {
|
||||||
Linter: foo,
|
Linter: fooTyped,
|
||||||
InPresets: []string{"A"},
|
InPresets: []string{"A"},
|
||||||
},
|
},
|
||||||
"bar": {
|
"bar": {
|
||||||
Linter: bar,
|
Linter: barTyped,
|
||||||
InPresets: []string{"B"},
|
InPresets: []string{"B"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: func() map[string]*linter.Config {
|
expected: func() map[string]*linter.Config {
|
||||||
mlConfig := &linter.Config{
|
mlConfig := &linter.Config{
|
||||||
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{bar, foo}),
|
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}),
|
||||||
InPresets: []string{"A", "B"},
|
InPresets: []string{"A", "B"},
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[string]*linter.Config{
|
return map[string]*linter.Config{
|
||||||
"goanalysis_metalinter": mlConfig.WithLoadForGoAnalysis(),
|
"goanalysis_metalinter": mlConfig,
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "combined, several linters (different LoadMode)",
|
||||||
|
linters: map[string]*linter.Config{
|
||||||
|
"foo": {
|
||||||
|
Linter: fooTyped,
|
||||||
|
InPresets: []string{"A"},
|
||||||
|
LoadMode: packages.NeedName,
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
Linter: barTyped,
|
||||||
|
InPresets: []string{"B"},
|
||||||
|
LoadMode: packages.NeedTypesSizes,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: func() map[string]*linter.Config {
|
||||||
|
mlConfig := &linter.Config{
|
||||||
|
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}),
|
||||||
|
InPresets: []string{"A", "B"},
|
||||||
|
LoadMode: packages.NeedName | packages.NeedTypesSizes,
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]*linter.Config{
|
||||||
|
"goanalysis_metalinter": mlConfig,
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "combined, several linters (same LoadMode)",
|
||||||
|
linters: map[string]*linter.Config{
|
||||||
|
"foo": {
|
||||||
|
Linter: fooTyped,
|
||||||
|
InPresets: []string{"A"},
|
||||||
|
LoadMode: packages.NeedName,
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
Linter: barTyped,
|
||||||
|
InPresets: []string{"B"},
|
||||||
|
LoadMode: packages.NeedName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: func() map[string]*linter.Config {
|
||||||
|
mlConfig := &linter.Config{
|
||||||
|
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barTyped, fooTyped}),
|
||||||
|
InPresets: []string{"A", "B"},
|
||||||
|
LoadMode: packages.NeedName,
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]*linter.Config{
|
||||||
|
"goanalysis_metalinter": mlConfig,
|
||||||
|
}
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "combined, several linters (syntax)",
|
||||||
|
linters: map[string]*linter.Config{
|
||||||
|
"foo": {
|
||||||
|
Linter: fooSyntax,
|
||||||
|
InPresets: []string{"A"},
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
Linter: barSyntax,
|
||||||
|
InPresets: []string{"B"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: func() map[string]*linter.Config {
|
||||||
|
mlConfig := &linter.Config{
|
||||||
|
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{barSyntax, fooSyntax}),
|
||||||
|
InPresets: []string{"A", "B"},
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]*linter.Config{
|
||||||
|
"goanalysis_metalinter": mlConfig,
|
||||||
}
|
}
|
||||||
}(),
|
}(),
|
||||||
},
|
},
|
||||||
|
@ -148,7 +148,7 @@ func getEnabledByDefaultFastLintersExcept(t *testing.T, except ...string) []stri
|
|||||||
ebdl := m.GetAllEnabledByDefaultLinters()
|
ebdl := m.GetAllEnabledByDefaultLinters()
|
||||||
var ret []string
|
var ret []string
|
||||||
for _, lc := range ebdl {
|
for _, lc := range ebdl {
|
||||||
if lc.IsSlowLinter() {
|
if lc.IsSlowLinter() || lc.Internal {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ func getAllFastLintersWith(t *testing.T, with ...string) []string {
|
|||||||
linters := dbManager.GetAllSupportedLinterConfigs()
|
linters := dbManager.GetAllSupportedLinterConfigs()
|
||||||
ret := append([]string{}, with...)
|
ret := append([]string{}, with...)
|
||||||
for _, lc := range linters {
|
for _, lc := range linters {
|
||||||
if lc.IsSlowLinter() {
|
if lc.IsSlowLinter() || lc.Internal {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ret = append(ret, lc.Name())
|
ret = append(ret, lc.Name())
|
||||||
@ -206,7 +206,7 @@ func getEnabledByDefaultFastLintersWith(t *testing.T, with ...string) []string {
|
|||||||
ebdl := dbManager.GetAllEnabledByDefaultLinters()
|
ebdl := dbManager.GetAllEnabledByDefaultLinters()
|
||||||
ret := append([]string{}, with...)
|
ret := append([]string{}, with...)
|
||||||
for _, lc := range ebdl {
|
for _, lc := range ebdl {
|
||||||
if lc.IsSlowLinter() {
|
if lc.IsSlowLinter() || lc.Internal {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user