]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go/internal/test: pass only analysis flags to vet
authorZvonimir Pavlinovic <zpavlinovic@google.com>
Wed, 11 Aug 2021 20:47:07 +0000 (13:47 -0700)
committerZvonimir Pavlinovic <zpavlinovic@google.com>
Wed, 22 Sep 2021 22:55:16 +0000 (22:55 +0000)
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>
src/cmd/go/internal/test/flagdefs.go
src/cmd/go/internal/test/flagdefs_test.go
src/cmd/go/internal/test/genflags.go
src/cmd/go/internal/test/internal/genflags/vetflag.go [new file with mode: 0644]
src/cmd/go/internal/test/testflag.go
src/cmd/go/testdata/script/test_vet.txt

index 3148074d57441513e74db77b52216b1dd406aa14..1b79314eff365889fa9b4b1cb9b221e91abfbd49 100644 (file)
@@ -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,
+}
index f238fc7d335e639a55e3dd466d927a9e87ed27b2..40dc558e9080c01bf1ae8ea0208d07775b2f30dd 100644 (file)
@@ -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.)")
+       }
+}
index 645aae68b17d7ec25d67de3b8991eca79e02d8eb..cba366062fcaa7c229631e6f12ecad847533dda5 100644 (file)
@@ -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 }}
 }
diff --git a/src/cmd/go/internal/test/internal/genflags/vetflag.go b/src/cmd/go/internal/test/internal/genflags/vetflag.go
new file mode 100644 (file)
index 0000000..2195cc3
--- /dev/null
@@ -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
+}
index cb3543884a4a3ce394048dff4d5aad0b1955d799..b9d1ec91ff7552aba0e1667d96f16d55349931a5 100644 (file)
@@ -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)
index 2e0ae1956a00f124653f4a7021bca93da2eea2b0..687d4851de10e9dc76276678787da9b1a97c3a66 100644 (file)
@@ -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