]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/vet: make vetx output deterministic
authorIan Lance Taylor <iant@golang.org>
Mon, 2 Jul 2018 23:45:49 +0000 (16:45 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 3 Jul 2018 00:42:50 +0000 (00:42 +0000)
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: Rob Pike <r@golang.org>
src/cmd/vet/main.go
src/cmd/vet/print.go

index 28da9e2d745f5d745e9964570061a15bd92e3177..c50d4885a078745ffa2bc10b2a7c59c5469507d9 100644 (file)
@@ -24,6 +24,7 @@ import (
        "io/ioutil"
        "os"
        "path/filepath"
+       "sort"
        "strconv"
        "strings"
 
@@ -163,6 +164,12 @@ var (
        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"
 // about package A to future invocations of vet
 // on packages importing A. If B imports A,
@@ -399,10 +406,17 @@ func doPackageCfg(cfgFile string) {
        mustTypecheck = true
        doPackage(vcfg.GoFiles, nil)
        if vcfg.VetxOutput != "" {
-               out := make(map[string]interface{})
+               out := make([]vetxExport, 0, len(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
                if err := gob.NewEncoder(&buf).Encode(out); err != nil {
                        errorf("encoding vet output: %v", err)
@@ -721,11 +735,15 @@ func readVetx(path, key string) interface{} {
                if err != nil {
                        return nil
                }
-               m = make(map[string]interface{})
-               err = gob.NewDecoder(bytes.NewReader(data)).Decode(&m)
+               var out []vetxExport
+               err = gob.NewDecoder(bytes.NewReader(data)).Decode(&out)
                if err != nil {
                        return nil
                }
+               m = make(map[string]interface{})
+               for _, x := range out {
+                       m[x.Name] = x.Data
+               }
                imported[path] = m
        }
        return m[key]
index 1edd3dd22881f33856a1a3daf4786f78f15349f1..ac1eb7997bbc7b08a63520429454e3460eb3e18e 100644 (file)
@@ -16,6 +16,7 @@ import (
        "go/token"
        "go/types"
        "regexp"
+       "sort"
        "strconv"
        "strings"
        "unicode/utf8"
@@ -30,7 +31,7 @@ func init() {
                funcDecl, callExpr)
        registerPkgCheck("printf", findPrintfLike)
        registerExport("printf", exportPrintfLike)
-       gob.Register(map[string]int(nil))
+       gob.Register([]printfExport(nil))
 }
 
 func initPrintFlags() {
@@ -57,6 +58,15 @@ func initPrintFlags() {
 
 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 {
        name       string
        fn         *ast.FuncDecl
@@ -241,7 +251,17 @@ func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int
 }
 
 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.
@@ -438,9 +458,18 @@ func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kin
 
        if pkgpath == "" {
                kind = localPrintfLike[name]
+       } else if m, ok := printfImported[pkgpath]; ok {
+               kind = m[name]
        } else {
-               printfLike, _ := readVetx(pkgpath, "printf").(map[string]int)
-               kind = printfLike[name]
+               var m map[string]int
+               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 {