1
0
mirror of https://github.com/mgechev/revive.git synced 2025-11-25 22:12:38 +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
7 changed files with 83 additions and 31 deletions

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.