mirror of
https://github.com/golang/go
synced 2024-11-17 04:04:46 -07:00
cmd/go/internal/test: pass only analysis flags to vet
In go test vet=x, x should be off, all, or one of the analyses supported by vet. All other flags should not be passed to vet. This CL maintains a list of supported vet analyzers by running go tool vet -flags and parsing the flag info to figure out the names of the supported analyzers and their aliases. Fixes #47309 Change-Id: I16ade8024301ad4aee5ad45aa92cf63b63dbc2d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/341334 Trust: Zvonimir Pavlinovic <zpavlinovic@google.com> Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
parent
333f3de2a1
commit
1319b1476e
@ -36,3 +36,37 @@ var passFlagToTest = map[string]bool{
|
||||
"trace": true,
|
||||
"v": true,
|
||||
}
|
||||
|
||||
var passAnalyzersToVet = map[string]bool{
|
||||
"asmdecl": true,
|
||||
"assign": true,
|
||||
"atomic": true,
|
||||
"bool": true,
|
||||
"bools": true,
|
||||
"buildtag": true,
|
||||
"buildtags": true,
|
||||
"cgocall": true,
|
||||
"composites": true,
|
||||
"copylocks": true,
|
||||
"errorsas": true,
|
||||
"framepointer": true,
|
||||
"httpresponse": true,
|
||||
"ifaceassert": true,
|
||||
"loopclosure": true,
|
||||
"lostcancel": true,
|
||||
"methods": true,
|
||||
"nilfunc": true,
|
||||
"printf": true,
|
||||
"rangeloops": true,
|
||||
"shift": true,
|
||||
"sigchanyzer": true,
|
||||
"stdmethods": true,
|
||||
"stringintconv": true,
|
||||
"structtag": true,
|
||||
"testinggoroutine": true,
|
||||
"tests": true,
|
||||
"unmarshal": true,
|
||||
"unreachable": true,
|
||||
"unsafeptr": true,
|
||||
"unusedresult": true,
|
||||
}
|
||||
|
@ -5,7 +5,9 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"cmd/go/internal/test/internal/genflags"
|
||||
"flag"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@ -37,3 +39,20 @@ func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVetAnalyzersSetIsCorrect(t *testing.T) {
|
||||
vetAns, err := genflags.VetAnalyzers()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
want := make(map[string]bool)
|
||||
for _, a := range vetAns {
|
||||
want[a] = true
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(want, passAnalyzersToVet) {
|
||||
t.Errorf("stale vet analyzers: want %v; got %v", want, passAnalyzersToVet)
|
||||
t.Logf("(Run 'go generate cmd/go/internal/test' to refresh the set of analyzers.)")
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"cmd/go/internal/test/internal/genflags"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -25,9 +27,18 @@ func main() {
|
||||
}
|
||||
|
||||
func regenerate() error {
|
||||
vetAnalyzers, err := genflags.VetAnalyzers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t := template.Must(template.New("fileTemplate").Parse(fileTemplate))
|
||||
tData := map[string][]string{
|
||||
"testFlags": testFlags(),
|
||||
"vetAnalyzers": vetAnalyzers,
|
||||
}
|
||||
buf := bytes.NewBuffer(nil)
|
||||
if err := t.Execute(buf, testFlags()); err != nil {
|
||||
if err := t.Execute(buf, tData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -85,7 +96,13 @@ package test
|
||||
// passFlagToTest contains the flags that should be forwarded to
|
||||
// the test binary with the prefix "test.".
|
||||
var passFlagToTest = map[string]bool {
|
||||
{{- range .}}
|
||||
{{- range .testFlags}}
|
||||
"{{.}}": true,
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var passAnalyzersToVet = map[string]bool {
|
||||
{{- range .vetAnalyzers}}
|
||||
"{{.}}": true,
|
||||
{{- end }}
|
||||
}
|
||||
|
68
src/cmd/go/internal/test/internal/genflags/vetflag.go
Normal file
68
src/cmd/go/internal/test/internal/genflags/vetflag.go
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package genflags
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/go/internal/base"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"regexp"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// VetAnalyzers computes analyzers and their aliases supported by vet.
|
||||
func VetAnalyzers() ([]string, error) {
|
||||
// get supported vet flag information
|
||||
tool := base.Tool("vet")
|
||||
vetcmd := exec.Command(tool, "-flags")
|
||||
out := new(bytes.Buffer)
|
||||
vetcmd.Stdout = out
|
||||
if err := vetcmd.Run(); err != nil {
|
||||
return nil, fmt.Errorf("go vet: can't execute %s -flags: %v\n", tool, err)
|
||||
}
|
||||
var analysisFlags []struct {
|
||||
Name string
|
||||
Bool bool
|
||||
Usage string
|
||||
}
|
||||
if err := json.Unmarshal(out.Bytes(), &analysisFlags); err != nil {
|
||||
return nil, fmt.Errorf("go vet: can't unmarshal JSON from %s -flags: %v", tool, err)
|
||||
}
|
||||
|
||||
// parse the flags to figure out which ones stand for analyses
|
||||
analyzerSet := make(map[string]bool)
|
||||
rEnable := regexp.MustCompile("^enable .+ analysis$")
|
||||
for _, flag := range analysisFlags {
|
||||
if rEnable.MatchString(flag.Usage) {
|
||||
analyzerSet[flag.Name] = true
|
||||
}
|
||||
}
|
||||
|
||||
rDeprecated := regexp.MustCompile("^deprecated alias for -(?P<analyzer>(.+))$")
|
||||
// Returns the original value matched by rDeprecated on input value.
|
||||
// If there is no match, "" is returned.
|
||||
originalValue := func(value string) string {
|
||||
match := rDeprecated.FindStringSubmatch(value)
|
||||
if len(match) < 2 {
|
||||
return ""
|
||||
}
|
||||
return match[1]
|
||||
}
|
||||
// extract deprecated aliases for existing analyses
|
||||
for _, flag := range analysisFlags {
|
||||
if o := originalValue(flag.Usage); analyzerSet[o] {
|
||||
analyzerSet[flag.Name] = true
|
||||
}
|
||||
}
|
||||
|
||||
var analyzers []string
|
||||
for a := range analyzerSet {
|
||||
analyzers = append(analyzers, a)
|
||||
}
|
||||
sort.Strings(analyzers)
|
||||
return analyzers, nil
|
||||
}
|
@ -195,6 +195,7 @@ func (f *vetFlag) Set(value string) error {
|
||||
case strings.Contains(value, " "):
|
||||
return fmt.Errorf("-vet argument is comma-separated list, cannot contain spaces")
|
||||
}
|
||||
|
||||
*f = vetFlag{explicit: true}
|
||||
var single string
|
||||
for _, arg := range strings.Split(value, ",") {
|
||||
@ -212,8 +213,15 @@ func (f *vetFlag) Set(value string) error {
|
||||
off: true,
|
||||
}
|
||||
continue
|
||||
default:
|
||||
if _, ok := passAnalyzersToVet[arg]; !ok {
|
||||
return fmt.Errorf("-vet argument must be a supported analyzer or a distinguished value; found %s", arg)
|
||||
}
|
||||
f.flags = append(f.flags, "-"+arg)
|
||||
}
|
||||
f.flags = append(f.flags, "-"+arg)
|
||||
}
|
||||
if len(f.flags) > 1 && single != "" {
|
||||
return fmt.Errorf("-vet does not accept %q in a list with other analyzers", single)
|
||||
}
|
||||
if len(f.flags) > 1 && single != "" {
|
||||
return fmt.Errorf("-vet does not accept %q in a list with other analyzers", single)
|
||||
|
11
src/cmd/go/testdata/script/test_vet.txt
vendored
11
src/cmd/go/testdata/script/test_vet.txt
vendored
@ -20,6 +20,17 @@ stdout '\[no test files\]'
|
||||
! go test -vet=all ./vetall/...
|
||||
stderr 'using resp before checking for errors'
|
||||
|
||||
# Test issue #47309
|
||||
! go test -vet=bools,xyz ./vetall/...
|
||||
stderr '-vet argument must be a supported analyzer'
|
||||
|
||||
# Test with a list of analyzers
|
||||
! go test -vet=httpresponse ./vetall/...
|
||||
stderr 'using resp before checking for errors'
|
||||
|
||||
# Test with a single analyzer
|
||||
go test -vet=atomic,bools,nilfunc ./vetall/...
|
||||
stdout 'm/vetall.*\[no tests to run\]'
|
||||
|
||||
# Test issue #22890
|
||||
go test m/vetcycle
|
||||
|
Loading…
Reference in New Issue
Block a user