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:
parent
bbe5eb7414
commit
4242f24f4d
4
go.mod
4
go.mod
@ -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
27
go.sum
@ -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=
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user