1
0
mirror of https://github.com/mgechev/revive.git synced 2025-03-17 20:57:58 +02:00

Add support for the new implementation of for loop variables in go 1.22. (#993)

* Add support for the new behaviour of for loops in go 1.22.

Go 1.22 has changed the behaviour of for loops. Every iteration
makes new loop variables. It is now safe to take their addresses
because they are guaranteed to be unique. Similarly, it is now
safe to capture loop variables in functions.

* adds documentation for public function

---------

Co-authored-by: chavacava <salvadorcavadini+github@gmail.com>
This commit is contained in:
dominiquelefevre 2024-06-02 12:55:26 +03:00 committed by GitHub
parent bbe5eb7414
commit 4242f24f4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 83 additions and 31 deletions

4
go.mod
View File

@ -1,12 +1,13 @@
module github.com/mgechev/revive
go 1.20
go 1.21
require (
github.com/BurntSushi/toml v1.4.0
github.com/chavacava/garif v0.1.0
github.com/fatih/color v1.17.0
github.com/fatih/structtag v1.2.0
github.com/hashicorp/go-version v1.7.0
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517
github.com/mitchellh/go-homedir v1.1.0
github.com/olekukonko/tablewriter v0.0.5
@ -19,6 +20,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/stretchr/testify v1.9.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

27
go.sum
View File

@ -1,5 +1,3 @@
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
@ -7,12 +5,12 @@ github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+U
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
@ -37,32 +35,15 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -3,12 +3,18 @@ package lint
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"go/token"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync"
goversion "github.com/hashicorp/go-version"
)
// ReadFile defines an abstraction for reading files.
@ -78,9 +84,19 @@ func (l *Linter) Lint(packages [][]string, ruleSet []Rule, config Config) (<-cha
}
func (l *Linter) lintPackage(filenames []string, ruleSet []Rule, config Config, failures chan Failure) error {
if len(filenames) == 0 {
return nil
}
goVersion, err := detectGoVersion(filepath.Dir(filenames[0]))
if err != nil {
return err
}
pkg := &Package{
fset: token.NewFileSet(),
files: map[string]*File{},
fset: token.NewFileSet(),
files: map[string]*File{},
goVersion: goVersion,
}
for _, filename := range filenames {
content, err := l.readFile(filename)
@ -108,6 +124,39 @@ func (l *Linter) lintPackage(filenames []string, ruleSet []Rule, config Config,
return nil
}
func detectGoVersion(dir string) (ver *goversion.Version, err error) {
// https://github.com/golang/go/issues/44753#issuecomment-790089020
cmd := exec.Command("go", "list", "-m", "-json")
cmd.Dir = dir
raw, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("command go list: %w", err)
}
var v struct {
GoMod string `json:"GoMod"`
GoVersion string `json:"GoVersion"`
}
if err = json.Unmarshal(raw, &v); err != nil {
return nil, fmt.Errorf("can't parse the output of go list: %w", err)
}
if v.GoMod == "" {
// this package is outside a module, so assume
// an old-style source directory
if v := os.Getenv("GOVERSION"); v != "" {
return goversion.NewVersion(strings.TrimPrefix(v, "go"))
}
// assume the last version that does not have generics
return goversion.Must(goversion.NewVersion("1.17")), nil
}
return goversion.NewVersion(strings.TrimPrefix(v.GoVersion, "go"))
}
// isGenerated reports whether the source file is generated code
// according the rules from https://golang.org/s/generatedcode.
// This is inherited from the original go lint.

View File

@ -7,13 +7,16 @@ import (
"go/types"
"sync"
goversion "github.com/hashicorp/go-version"
"github.com/mgechev/revive/internal/typeparams"
)
// Package represents a package in the project.
type Package struct {
fset *token.FileSet
files map[string]*File
fset *token.FileSet
files map[string]*File
goVersion *goversion.Version
typesPkg *types.Package
typesInfo *types.Info
@ -29,6 +32,8 @@ var (
trueValue = 1
falseValue = 2
notSet = 3
go122 = goversion.Must(goversion.NewVersion("1.22"))
)
// Files return package's files.
@ -188,3 +193,8 @@ func (p *Package) lint(rules []Rule, config Config, failures chan Failure) {
}
wg.Wait()
}
// IsAtLeastGo122 returns true if the Go version for this package is 1.22 or higher, false otherwise
func (p *Package) IsAtLeastGo122() bool {
return p.goVersion.GreaterThanOrEqual(go122)
}

View File

@ -16,7 +16,7 @@ func (*DataRaceRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
onFailure := func(failure lint.Failure) {
failures = append(failures, failure)
}
w := lintDataRaces{onFailure: onFailure}
w := lintDataRaces{onFailure: onFailure, go122for: file.Pkg.IsAtLeastGo122()}
ast.Walk(w, file.AST)
@ -30,6 +30,7 @@ func (*DataRaceRule) Name() string {
type lintDataRaces struct {
onFailure func(failure lint.Failure)
go122for bool
}
func (w lintDataRaces) Visit(n ast.Node) ast.Visitor {
@ -47,7 +48,7 @@ func (w lintDataRaces) Visit(n ast.Node) ast.Visitor {
if results != nil {
returnIDs = w.ExtractReturnIDs(results.List)
}
fl := &lintFunctionForDataRaces{onFailure: w.onFailure, returnIDs: returnIDs, rangeIDs: map[*ast.Object]struct{}{}}
fl := &lintFunctionForDataRaces{onFailure: w.onFailure, returnIDs: returnIDs, rangeIDs: map[*ast.Object]struct{}{}, go122for: w.go122for}
ast.Walk(fl, node.Body)
return nil
@ -69,6 +70,7 @@ type lintFunctionForDataRaces struct {
onFailure func(failure lint.Failure)
returnIDs map[*ast.Object]struct{}
rangeIDs map[*ast.Object]struct{}
go122for bool
}
func (w lintFunctionForDataRaces) Visit(node ast.Node) ast.Visitor {
@ -118,7 +120,7 @@ func (w lintFunctionForDataRaces) Visit(node ast.Node) ast.Visitor {
_, isReturnID := w.returnIDs[id.Obj]
switch {
case isRangeID:
case isRangeID && !w.go122for:
w.onFailure(lint.Failure{
Confidence: 1,
Node: id,

View File

@ -16,6 +16,10 @@ type RangeValAddress struct{}
func (*RangeValAddress) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
if file.Pkg.IsAtLeastGo122() {
return failures
}
walker := rangeValAddress{
file: file,
onFailure: func(failure lint.Failure) {

View File

@ -14,6 +14,10 @@ type RangeValInClosureRule struct{}
func (*RangeValInClosureRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
var failures []lint.Failure
if file.Pkg.IsAtLeastGo122() {
return failures
}
walker := rangeValInClosure{
onFailure: func(failure lint.Failure) {
failures = append(failures, failure)