Commit 4ba55273 authored by Ian Lance Taylor's avatar Ian Lance Taylor

cmd/vet: make vetx output deterministic

The vetx output file is a build output, and as such should be
deterministic. This CL changes it to not depend on map iteration order.

This avoids a pointless GODEBUG=gocacheverify=1 failure.

Updates #25666

Change-Id: Ic132bad134cb10938275f883c2c68432cb7c4409
Reviewed-on: https://go-review.googlesource.com/121941
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRob Pike <r@golang.org>
parent 3f54e853
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strconv" "strconv"
"strings" "strings"
...@@ -163,6 +164,12 @@ var ( ...@@ -163,6 +164,12 @@ var (
exporters = make(map[string]func() interface{}) exporters = make(map[string]func() interface{})
) )
// The exporters data as written to the vetx output file.
type vetxExport struct {
Name string
Data interface{}
}
// Vet can provide its own "export information" // Vet can provide its own "export information"
// about package A to future invocations of vet // about package A to future invocations of vet
// on packages importing A. If B imports A, // on packages importing A. If B imports A,
...@@ -399,10 +406,17 @@ func doPackageCfg(cfgFile string) { ...@@ -399,10 +406,17 @@ func doPackageCfg(cfgFile string) {
mustTypecheck = true mustTypecheck = true
doPackage(vcfg.GoFiles, nil) doPackage(vcfg.GoFiles, nil)
if vcfg.VetxOutput != "" { if vcfg.VetxOutput != "" {
out := make(map[string]interface{}) out := make([]vetxExport, 0, len(exporters))
for name, fn := range exporters { for name, fn := range exporters {
out[name] = fn() out = append(out, vetxExport{
Name: name,
Data: fn(),
})
} }
// Sort the data so that it is consistent across builds.
sort.Slice(out, func(i, j int) bool {
return out[i].Name < out[j].Name
})
var buf bytes.Buffer var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(out); err != nil { if err := gob.NewEncoder(&buf).Encode(out); err != nil {
errorf("encoding vet output: %v", err) errorf("encoding vet output: %v", err)
...@@ -721,11 +735,15 @@ func readVetx(path, key string) interface{} { ...@@ -721,11 +735,15 @@ func readVetx(path, key string) interface{} {
if err != nil { if err != nil {
return nil return nil
} }
m = make(map[string]interface{}) var out []vetxExport
err = gob.NewDecoder(bytes.NewReader(data)).Decode(&m) err = gob.NewDecoder(bytes.NewReader(data)).Decode(&out)
if err != nil { if err != nil {
return nil return nil
} }
m = make(map[string]interface{})
for _, x := range out {
m[x.Name] = x.Data
}
imported[path] = m imported[path] = m
} }
return m[key] return m[key]
......
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"regexp" "regexp"
"sort"
"strconv" "strconv"
"strings" "strings"
"unicode/utf8" "unicode/utf8"
...@@ -30,7 +31,7 @@ func init() { ...@@ -30,7 +31,7 @@ func init() {
funcDecl, callExpr) funcDecl, callExpr)
registerPkgCheck("printf", findPrintfLike) registerPkgCheck("printf", findPrintfLike)
registerExport("printf", exportPrintfLike) registerExport("printf", exportPrintfLike)
gob.Register(map[string]int(nil)) gob.Register([]printfExport(nil))
} }
func initPrintFlags() { func initPrintFlags() {
...@@ -57,6 +58,15 @@ func initPrintFlags() { ...@@ -57,6 +58,15 @@ func initPrintFlags() {
var localPrintfLike = make(map[string]int) var localPrintfLike = make(map[string]int)
type printfExport struct {
Name string
Kind int
}
// printfImported maps from package name to the printf vet data
// exported by that package.
var printfImported = make(map[string]map[string]int)
type printfWrapper struct { type printfWrapper struct {
name string name string
fn *ast.FuncDecl fn *ast.FuncDecl
...@@ -241,7 +251,17 @@ func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int ...@@ -241,7 +251,17 @@ func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int
} }
func exportPrintfLike() interface{} { func exportPrintfLike() interface{} {
return localPrintfLike out := make([]printfExport, 0, len(localPrintfLike))
for name, kind := range localPrintfLike {
out = append(out, printfExport{
Name: name,
Kind: kind,
})
}
sort.Slice(out, func(i, j int) bool {
return out[i].Name < out[j].Name
})
return out
} }
// isPrint records the print functions. // isPrint records the print functions.
...@@ -438,9 +458,18 @@ func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kin ...@@ -438,9 +458,18 @@ func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kin
if pkgpath == "" { if pkgpath == "" {
kind = localPrintfLike[name] kind = localPrintfLike[name]
} else if m, ok := printfImported[pkgpath]; ok {
kind = m[name]
} else { } else {
printfLike, _ := readVetx(pkgpath, "printf").(map[string]int) var m map[string]int
kind = printfLike[name] if out, ok := readVetx(pkgpath, "printf").([]printfExport); ok {
m = make(map[string]int)
for _, x := range out {
m[x.Name] = x.Kind
}
}
printfImported[pkgpath] = m
kind = m[name]
} }
if kind == 0 { if kind == 0 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment