Skip to content

Commit

Permalink
cmd/vet: add stdversion analyzer
Browse files Browse the repository at this point in the history
+ release note, test

Fixes #46136

Change-Id: Ib157c5343dde379f8d6f67bdfa64b3f6a6432bab
Reviewed-on: https://go-review.googlesource.com/c/go/+/582556
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Michael Matloob <[email protected]>
  • Loading branch information
adonovan committed May 3, 2024
1 parent 344075d commit 6defff5
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 0 deletions.
14 changes: 14 additions & 0 deletions doc/next/3-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,19 @@ Distributions that install the `go` command to a location other than
`$GOROOT/bin/go` should install a symlink instead of relocating
or copying the `go` binary.

### Vet {#vet}

The `go vet` subcommand now includes the
[stdversion](https://beta.pkg.go.dev/golang.org/x/tools/go/analysis/passes/stdversion)
analyzer, which flags references to symbols that are too new for the version
of Go in effect in the referring file. (The effective version is determined
by the `go` directive in the file's enclosing `go.mod` file, and
by any [`//go:build` constraints](https://pkg.go.dev/cmd/go#hdr-Build_constraints)
in the file.)

For example, it will report a diagnostic for a reference to the
`reflect.TypeFor` function (introduced in go1.22) from a file in a
module whose go.mod file specifies `go 1.21`.

### Cgo {#cgo}

1 change: 1 addition & 0 deletions src/cmd/go/internal/test/flagdefs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/cmd/vet/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"golang.org/x/tools/go/analysis/passes/sigchanyzer"
"golang.org/x/tools/go/analysis/passes/slog"
"golang.org/x/tools/go/analysis/passes/stdmethods"
"golang.org/x/tools/go/analysis/passes/stdversion"
"golang.org/x/tools/go/analysis/passes/stringintconv"
"golang.org/x/tools/go/analysis/passes/structtag"
"golang.org/x/tools/go/analysis/passes/testinggoroutine"
Expand Down Expand Up @@ -70,6 +71,7 @@ func main() {
sigchanyzer.Analyzer,
slog.Analyzer,
stdmethods.Analyzer,
stdversion.Analyzer,
stringintconv.Analyzer,
structtag.Analyzer,
tests.Analyzer,
Expand Down
3 changes: 3 additions & 0 deletions src/cmd/vet/testdata/stdversion/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module stdversion

go 1.21
5 changes: 5 additions & 0 deletions src/cmd/vet/testdata/stdversion/stdversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package stdversion

import "reflect"

var _ = reflect.TypeFor[int]() // ERROR "reflect.TypeFor requires go1.22 or later \(module is go1.21\)"
31 changes: 31 additions & 0 deletions src/cmd/vet/vet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,37 @@ func TestVet(t *testing.T) {
t.Log("vet stderr:\n", cmd.Stderr)
}
})

// The stdversion analyzer requires a lower-than-tip go
// version in its go.mod file for it to report anything.
// So again we use a testdata go.mod file to "downgrade".
t.Run("stdversion", func(t *testing.T) {
cmd := testenv.Command(t, testenv.GoToolPath(t), "vet", "-vettool="+vetPath(t), ".")
cmd.Env = append(os.Environ(), "GOWORK=off")
cmd.Dir = "testdata/stdversion"
cmd.Stderr = new(strings.Builder) // all vet output goes to stderr
cmd.Run()
stderr := cmd.Stderr.(fmt.Stringer).String()

filename := filepath.FromSlash("testdata/stdversion/stdversion.go")

// Unlike the tests above, which runs vet in cmd/vet/, this one
// runs it in subdirectory, so the "full names" in the output
// are in fact short "./rangeloop.go".
// But we can't just pass "./rangeloop.go" as the "full name"
// argument to errorCheck as it does double duty as both a
// string that appears in the output, and as file name
// openable relative to the test directory, containing text
// expectations.
//
// So, we munge the file.
stderr = strings.ReplaceAll(stderr, filepath.FromSlash("./stdversion.go"), filename)

if err := errorCheck(stderr, false, filename, filepath.Base(filename)); err != nil {
t.Errorf("error check failed: %s", err)
t.Log("vet stderr:\n", cmd.Stderr)
}
})
}

func cgoEnabled(t *testing.T) bool {
Expand Down

0 comments on commit 6defff5

Please sign in to comment.