Skip to content

Commit 64492b5

Browse files
authored
feat: disable copyloopvar and intrange on Go < 1.22 (#4397)
1 parent c65868c commit 64492b5

File tree

12 files changed

+148
-32
lines changed

12 files changed

+148
-32
lines changed

pkg/commands/executor.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,18 @@ func NewExecutor(buildInfo BuildInfo) *Executor {
116116
e.log.Fatalf("Can't read config: %s", err)
117117
}
118118

119-
if (commandLineCfg == nil || commandLineCfg.Run.Go == "") && e.cfg != nil && e.cfg.Run.Go == "" {
119+
if commandLineCfg != nil && commandLineCfg.Run.Go != "" {
120+
// This hack allow to have the right Run information at least for the Go version (because the default value of the "go" flag is empty).
121+
// If you put a log for `m.cfg.Run.Go` inside `GetAllSupportedLinterConfigs`,
122+
// you will observe that at end (without this hack) the value will have the right value but too late,
123+
// the linters are already running with the previous uncompleted configuration.
124+
// TODO(ldez) there is a major problem with the executor:
125+
// the parsing of the configuration and the timing to load the configuration and linters are creating unmanageable situations.
126+
// There is no simple solution because it's spaghetti code.
127+
// I need to completely rewrite the command line system and the executor because it's extremely time consuming to debug,
128+
// so it's unmaintainable.
129+
e.cfg.Run.Go = commandLineCfg.Run.Go
130+
} else if e.cfg.Run.Go == "" {
120131
e.cfg.Run.Go = config.DetectGoVersion()
121132
}
122133

pkg/config/config.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,18 @@ type Version struct {
4141
Debug bool `mapstructure:"debug"`
4242
}
4343

44-
func IsGreaterThanOrEqualGo122(v string) bool {
45-
v1, err := hcversion.NewVersion(strings.TrimPrefix(v, "go"))
44+
func IsGoGreaterThanOrEqual(current, limit string) bool {
45+
v1, err := hcversion.NewVersion(strings.TrimPrefix(current, "go"))
4646
if err != nil {
4747
return false
4848
}
4949

50-
limit, err := hcversion.NewVersion("1.22")
50+
l, err := hcversion.NewVersion(limit)
5151
if err != nil {
5252
return false
5353
}
5454

55-
return v1.GreaterThanOrEqual(limit)
55+
return v1.GreaterThanOrEqual(l)
5656
}
5757

5858
func DetectGoVersion() string {

pkg/config/config_test.go

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package config
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestIsGoGreaterThanOrEqual(t *testing.T) {
10+
testCases := []struct {
11+
desc string
12+
current string
13+
limit string
14+
assert assert.BoolAssertionFunc
15+
}{
16+
{
17+
desc: "current (with minor.major) lower than limit",
18+
current: "go1.21",
19+
limit: "1.22",
20+
assert: assert.False,
21+
},
22+
{
23+
desc: "current (with 0 patch) lower than limit",
24+
current: "go1.21.0",
25+
limit: "1.22",
26+
assert: assert.False,
27+
},
28+
{
29+
desc: "current (current with multiple patches) lower than limit",
30+
current: "go1.21.6",
31+
limit: "1.22",
32+
assert: assert.False,
33+
},
34+
{
35+
desc: "current lower than limit (with minor.major)",
36+
current: "go1.22",
37+
limit: "1.22",
38+
assert: assert.True,
39+
},
40+
{
41+
desc: "current lower than limit (with 0 patch)",
42+
current: "go1.22.0",
43+
limit: "1.22",
44+
assert: assert.True,
45+
},
46+
{
47+
desc: "current lower than limit (current with multiple patches)",
48+
current: "go1.22.6",
49+
limit: "1.22",
50+
assert: assert.True,
51+
},
52+
{
53+
desc: "current greater than limit",
54+
current: "go1.23.0",
55+
limit: "1.22",
56+
assert: assert.True,
57+
},
58+
{
59+
desc: "current with no prefix",
60+
current: "1.22",
61+
limit: "1.22",
62+
assert: assert.True,
63+
},
64+
{
65+
desc: "invalid current value",
66+
current: "go",
67+
limit: "1.22",
68+
assert: assert.False,
69+
},
70+
{
71+
desc: "invalid limit value",
72+
current: "go1.22",
73+
limit: "go",
74+
assert: assert.False,
75+
},
76+
}
77+
78+
for _, test := range testCases {
79+
test := test
80+
t.Run(test.desc, func(t *testing.T) {
81+
t.Parallel()
82+
83+
test.assert(t, IsGoGreaterThanOrEqual(test.current, test.limit))
84+
})
85+
}
86+
}

pkg/golinters/govet.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func analyzersFromConfig(settings *config.GovetSettings) []*analysis.Analyzer {
173173

174174
func isAnalyzerEnabled(name string, cfg *config.GovetSettings, defaultAnalyzers []*analysis.Analyzer) bool {
175175
// TODO(ldez) remove loopclosure when go1.23
176-
if name == loopclosure.Analyzer.Name && config.IsGreaterThanOrEqualGo122(cfg.Go) {
176+
if name == loopclosure.Analyzer.Name && config.IsGoGreaterThanOrEqual(cfg.Go, "1.22") {
177177
return false
178178
}
179179

pkg/golinters/paralleltest.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func NewParallelTest(settings *config.ParallelTestSettings) *goanalysis.Linter {
1818
"ignoremissingsubtests": settings.IgnoreMissingSubtests,
1919
}
2020

21-
if config.IsGreaterThanOrEqualGo122(settings.Go) {
21+
if config.IsGoGreaterThanOrEqual(settings.Go, "1.22") {
2222
d["ignoreloopVar"] = true
2323
}
2424

pkg/lint/linter/config.go

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package linter
22

33
import (
4-
"golang.org/x/tools/go/analysis"
4+
"fmt"
5+
56
"golang.org/x/tools/go/packages"
67

78
"github.com/golangci/golangci-lint/pkg/config"
@@ -133,23 +134,27 @@ func (lc *Config) Name() string {
133134
return lc.Linter.Name()
134135
}
135136

136-
func (lc *Config) WithNoopFallback(cfg *config.Config) *Config {
137-
if cfg != nil && config.IsGreaterThanOrEqualGo122(cfg.Run.Go) {
138-
lc.Linter = &Noop{
139-
name: lc.Linter.Name(),
140-
desc: lc.Linter.Desc(),
141-
run: func(_ *analysis.Pass) (any, error) {
142-
return nil, nil
143-
},
144-
}
145-
137+
func (lc *Config) WithNoopFallback(cfg *config.Config, cond func(cfg *config.Config) error) *Config {
138+
if err := cond(cfg); err != nil {
139+
lc.Linter = NewNoop(lc.Linter, err.Error())
146140
lc.LoadMode = 0
141+
147142
return lc.WithLoadFiles()
148143
}
149144

150145
return lc
151146
}
152147

148+
func IsGoLowerThanGo122() func(cfg *config.Config) error {
149+
return func(cfg *config.Config) error {
150+
if cfg == nil || config.IsGoGreaterThanOrEqual(cfg.Run.Go, "1.22") {
151+
return nil
152+
}
153+
154+
return fmt.Errorf("this linter is disabled because the Go version (%s) of your project is lower than Go 1.22", cfg.Run.Go)
155+
}
156+
}
157+
153158
func NewConfig(linter Linter) *Config {
154159
lc := &Config{
155160
Linter: linter,

pkg/lint/linter/linter.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package linter
33
import (
44
"context"
55

6-
"golang.org/x/tools/go/analysis"
7-
86
"github.com/golangci/golangci-lint/pkg/result"
97
)
108

@@ -15,14 +13,23 @@ type Linter interface {
1513
}
1614

1715
type Noop struct {
18-
name string
19-
desc string
20-
run func(pass *analysis.Pass) (any, error)
16+
name string
17+
desc string
18+
reason string
19+
}
20+
21+
func NewNoop(l Linter, reason string) Noop {
22+
return Noop{
23+
name: l.Name(),
24+
desc: l.Desc(),
25+
reason: reason,
26+
}
2127
}
2228

2329
func (n Noop) Run(_ context.Context, lintCtx *Context) ([]result.Issue, error) {
24-
lintCtx.Log.Warnf("%s is disabled because of generics."+
25-
" You can track the evolution of the generics support by following the https://github.com/golangci/golangci-lint/issues/2649.", n.name)
30+
if n.reason != "" {
31+
lintCtx.Log.Warnf("%s: %s", n.name, n.reason)
32+
}
2633
return nil, nil
2734
}
2835

pkg/lint/lintersdb/manager.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
303303
linter.NewConfig(golinters.NewCopyLoopVar()).
304304
WithSince("v1.57.0").
305305
WithPresets(linter.PresetStyle).
306-
WithURL("https://github.com/karamaru-alpha/copyloopvar"),
306+
WithURL("https://github.com/karamaru-alpha/copyloopvar").
307+
WithNoopFallback(m.cfg, linter.IsGoLowerThanGo122()),
307308

308309
linter.NewConfig(golinters.NewCyclop(cyclopCfg)).
309310
WithSince("v1.37.0").
@@ -617,7 +618,8 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
617618

618619
linter.NewConfig(golinters.NewIntrange()).
619620
WithSince("v1.57.0").
620-
WithURL("https://github.com/ckaznocha/intrange"),
621+
WithURL("https://github.com/ckaznocha/intrange").
622+
WithNoopFallback(m.cfg, linter.IsGoLowerThanGo122()),
621623

622624
linter.NewConfig(golinters.NewIreturn(ireturnCfg)).
623625
WithSince("v1.43.0").

test/linters_test.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func testOneSource(t *testing.T, log *logutils.StderrLog, binPath, sourcePath st
8484
}
8585

8686
args := []string{
87-
"--allow-parallel-runners",
87+
"--go=1.22", // TODO(ldez) remove this line when we will run go1.23 on the CI. (related to intrange, copyloopvar)
8888
"--disable-all",
8989
"--out-format=json",
9090
"--max-same-issues=100",
@@ -99,7 +99,6 @@ func testOneSource(t *testing.T, log *logutils.StderrLog, binPath, sourcePath st
9999

100100
cmd := testshared.NewRunnerBuilder(t).
101101
WithBinPath(binPath).
102-
WithNoParallelRunners().
103102
WithArgs(caseArgs...).
104103
WithRunContext(rc).
105104
WithTargetPath(sourcePath).

test/run_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ func TestTestsAreLintedByDefault(t *testing.T) {
133133
func TestCgoOk(t *testing.T) {
134134
testshared.NewRunnerBuilder(t).
135135
WithNoConfig().
136-
WithArgs(
137-
"--timeout=3m",
136+
WithArgs("--timeout=3m",
138137
"--enable-all",
139138
"-D",
140-
"nosnakecase,gci",
139+
"nosnakecase",
141140
).
141+
WithArgs("--go=1.22"). // TODO(ldez) remove this line when we will run go1.23 on the CI. (related to intrange, copyloopvar)
142142
WithTargetPath(testdataDir, "cgo").
143143
Runner().
144144
Install().
@@ -356,6 +356,7 @@ func TestUnsafeOk(t *testing.T) {
356356
testshared.NewRunnerBuilder(t).
357357
WithNoConfig().
358358
WithArgs("--enable-all").
359+
WithArgs("--go=1.22"). // TODO(ldez) remove this line when we will run go1.23 on the CI. (related to intrange, copyloopvar)
359360
WithTargetPath(testdataDir, "unsafe").
360361
Runner().
361362
Install().
@@ -514,6 +515,7 @@ func TestEnableAllFastAndEnableCanCoexist(t *testing.T) {
514515
testshared.NewRunnerBuilder(t).
515516
WithNoConfig().
516517
WithArgs(test.args...).
518+
WithArgs("--go=1.22"). // TODO(ldez) remove this line when we will run go1.23 on the CI. (related to intrange, copyloopvar)
517519
WithTargetPath(testdataDir, minimalPkg).
518520
Runner().
519521
Run().

test/testdata/copyloopvar.go

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build go1.22
2+
13
//golangcitest:args -Ecopyloopvar
24
package testdata
35

test/testdata/intrange.go

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build go1.22
2+
13
//golangcitest:args -Eintrange
24
package testdata
35

0 commit comments

Comments
 (0)