Commit 8458a387 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: make fmt_test work on entire compiler

- process all directories recursively

Change-Id: I27a737013d17fd3c2cc8ae9de4722dcbe989e6e5
Reviewed-on: https://go-review.googlesource.com/28789Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 8ff42607
...@@ -3,30 +3,33 @@ ...@@ -3,30 +3,33 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// This file implements TestFormats; a test that verifies // This file implements TestFormats; a test that verifies
// all format strings in the compiler. // format strings in the compiler (this directory and all
// subdirectories, recursively).
// //
// TestFormats finds potential (Printf, etc.) format strings. // TestFormats finds potential (Printf, etc.) format strings.
// If they are used in a call, the format verbs are verified // If they are used in a call, the format verbs are verified
// based on the matching argument type against a precomputed // based on the matching argument type against a precomputed
// table of valid formats (formatMapping, below). The table // table of valid formats. The knownFormats table can be used
// can be used to automatically rewrite format strings with // to automatically rewrite format strings with the -u flag.
// the -u flag.
// //
// Run as: go test -run Formats [-u] // A new knownFormats table based on the found formats is printed
//
// A formatMapping based on the existing formats is printed
// when the test is run in verbose mode (-v flag). The table // when the test is run in verbose mode (-v flag). The table
// needs to be updated whenever a new (type, format) combination // needs to be updated whenever a new (type, format) combination
// is found and the format verb is not 'v' (as in "%v"). // is found and the format verb is not 'v' (as in "%v").
// //
// Run as: go test -run Formats [-u][-v]
//
// Known bugs: // Known bugs:
// - indexed format strings ("%[2]s", etc.) are not supported // - indexed format strings ("%[2]s", etc.) are not supported
// (the test will fail) // (the test will fail)
// - format strings that are not simple string literals cannot // - format strings that are not simple string literals cannot
// be updated automatically // be updated automatically
// (the test will fail with respective warnings) // (the test will fail with respective warnings)
// - format strings in _test packages outside the current
// package are not processed
// (the test will report those files)
// //
package gc_test package main_test
import ( import (
"bytes" "bytes"
...@@ -43,6 +46,8 @@ import ( ...@@ -43,6 +46,8 @@ import (
"internal/testenv" "internal/testenv"
"io/ioutil" "io/ioutil"
"log" "log"
"os"
"path/filepath"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
...@@ -52,116 +57,70 @@ import ( ...@@ -52,116 +57,70 @@ import (
var update = flag.Bool("u", false, "update format strings") var update = flag.Bool("u", false, "update format strings")
var fset = token.NewFileSet() // file set for all processed files // The following variables collect information across all processed files.
var typedPkg *types.Package // the package we are type-checking var (
fset = token.NewFileSet()
formatStrings = make(map[*ast.BasicLit]bool) // set of all potential format strings found
foundFormats = make(map[string]bool) // set of all formats found
callSites = make(map[*ast.CallExpr]*callSite) // set of all calls using format strings
)
// A CallSite describes a function call that appears to contain // A File is a corresponding (filename, ast) pair.
// a format string. type File struct {
type CallSite struct { name string
file int // buildPkg.GoFiles index ast *ast.File
call *ast.CallExpr // call containing the format string
arg ast.Expr // format argument (string literal or constant)
str string // unquoted format string
types []string // argument types
} }
func TestFormats(t *testing.T) { func TestFormats(t *testing.T) {
testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
// determine .go files // process all directories
buildPkg, err := build.ImportDir(".", 0) filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil { if info.IsDir() {
t.Fatal(err) if info.Name() == "testdata" {
} return filepath.SkipDir
// parse all files
files := make([]*ast.File, len(buildPkg.GoFiles))
for i, filename := range buildPkg.GoFiles {
f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
files[i] = f
}
// typecheck package
conf := types.Config{Importer: importer.Default()}
etypes := make(map[ast.Expr]types.TypeAndValue)
typedPkg, err = conf.Check("some_path", fset, files, &types.Info{Types: etypes})
if err != nil {
t.Fatal(err)
}
// collect all potential format strings (for extra verification later)
potentialFormats := make(map[*ast.BasicLit]bool)
for _, file := range files {
ast.Inspect(file, func(n ast.Node) bool {
if s, ok := stringLit(n); ok && isFormat(s) {
potentialFormats[n.(*ast.BasicLit)] = true
} }
return true
})
}
// collect all formats/arguments of calls with format strings importPath := filepath.Join("cmd/compile", path)
var callSites []*CallSite pkg, err := build.Import(importPath, path, 0)
for index, file := range files { if err != nil {
ast.Inspect(file, func(n ast.Node) bool { if _, ok := err.(*build.NoGoError); ok {
if call, ok := n.(*ast.CallExpr); ok { return nil // nothing to do here
// ignore blackisted functions
if functionBlacklisted[nodeString(call.Fun)] {
return true
}
// look for an arguments that might be a format string
for i, arg := range call.Args {
if s, ok := stringVal(etypes[arg]); ok && isFormat(s) {
// make sure we have enough arguments
n := formatArgs(s)
if i+1+n > len(call.Args) {
t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
break // ignore this call
}
// assume last n arguments are to be formatted;
// determine their types
argTypes := make([]string, n)
for i, arg := range call.Args[len(call.Args)-n:] {
if tv, ok := etypes[arg]; ok {
argTypes[i] = typeString(tv.Type)
}
}
// collect call site
callSites = append(callSites, &CallSite{
file: index,
call: call,
arg: arg,
str: s,
types: argTypes,
})
break // at most one format per argument list
}
} }
t.Fatal(err)
} }
return true collectPkgFormats(t, pkg)
}) }
} return nil
})
// test and rewrite formats // test and rewrite formats
keys := make(map[string]bool) updatedFiles := make(map[string]File) // files that were rewritten
dirty := false // dirty means some files have been modified
dirtyFiles := make([]bool, len(files)) // dirtyFiles[i] means file i has been modified
for _, p := range callSites { for _, p := range callSites {
// test current format literal and determine updated one // test current format literal and determine updated one
out := formatReplace(p.str, func(index int, in string) string { out := formatReplace(p.str, func(index int, in string) string {
if in == "*" { if in == "*" {
return in return in // cannot rewrite '*' (as in "%*d")
} }
// in != '*'
typ := p.types[index] typ := p.types[index]
key := typ + " " + in // e.g., "*Node %n" format := typ + " " + in // e.g., "*Node %n"
keys[key] = true
out, found := formatMapping[key] // check if format is known
if !found && in != "%v" { // always accept simple "%v" out, known := knownFormats[format]
// record format if not yet found
_, found := foundFormats[format]
if !found {
foundFormats[format] = true
}
// report an error if the format is unknown and this is the first
// time we see it; ignore "%v" which is always considered valid
if !known && !found && in != "%v" {
t.Errorf("%s: unknown format %q for %s argument", posString(p.arg), in, typ) t.Errorf("%s: unknown format %q for %s argument", posString(p.arg), in, typ)
} }
if out == "" { if out == "" {
out = in out = in
} }
...@@ -170,9 +129,18 @@ func TestFormats(t *testing.T) { ...@@ -170,9 +129,18 @@ func TestFormats(t *testing.T) {
// replace existing format literal if it changed // replace existing format literal if it changed
if out != p.str { if out != p.str {
// we cannot replace the argument if it's not a string literal for now
// (e.g., it may be "foo" + "bar")
lit, ok := p.arg.(*ast.BasicLit)
if !ok {
delete(callSites, p.call) // treat as if we hadn't found this site
continue
}
if testing.Verbose() { if testing.Verbose() {
fmt.Printf("%s:\n\t %q\n\t=> %q\n", posString(p.arg), p.str, out) fmt.Printf("%s:\n\t- %q\n\t+ %q\n", posString(p.arg), p.str, out)
} }
// find argument index of format argument // find argument index of format argument
index := -1 index := -1
for i, arg := range p.call.Args { for i, arg := range p.call.Args {
...@@ -182,39 +150,34 @@ func TestFormats(t *testing.T) { ...@@ -182,39 +150,34 @@ func TestFormats(t *testing.T) {
} }
} }
if index < 0 { if index < 0 {
// we may have processed the same call site twice,
// but that shouldn't happen
panic("internal error: matching argument not found") panic("internal error: matching argument not found")
} }
// we cannot replace the argument if it's not a string literal for now
// (e.g., it may be "foo" + "bar") // replace literal
lit, ok := p.arg.(*ast.BasicLit)
if !ok {
continue // we issue a warning about missed format strings at the end
}
new := *lit // make a copy new := *lit // make a copy
new.Value = strconv.Quote(out) // this may introduce "-quotes where there were `-quotes new.Value = strconv.Quote(out) // this may introduce "-quotes where there were `-quotes
p.call.Args[index] = &new p.call.Args[index] = &new
dirty = true updatedFiles[p.file.name] = p.file
dirtyFiles[p.file] = true // mark file as changed
} }
} }
// write dirty files back // write dirty files back
if dirty && *update { var filesUpdated bool
for i, d := range dirtyFiles { if len(updatedFiles) > 0 && *update {
if !d { for _, file := range updatedFiles {
continue
}
filename := buildPkg.GoFiles[i]
var buf bytes.Buffer var buf bytes.Buffer
if err := format.Node(&buf, fset, files[i]); err != nil { if err := format.Node(&buf, fset, file.ast); err != nil {
t.Errorf("WARNING: formatting %s failed: %v", filename, err) t.Errorf("WARNING: formatting %s failed: %v", file.name, err)
continue continue
} }
if err := ioutil.WriteFile(filename, buf.Bytes(), 0x666); err != nil { if err := ioutil.WriteFile(file.name, buf.Bytes(), 0x666); err != nil {
t.Errorf("WARNING: writing %s failed: %v", filename, err) t.Errorf("WARNING: writing %s failed: %v", file.name, err)
continue continue
} }
fmt.Println(filename) fmt.Printf("updated %s\n", file.name)
filesUpdated = true
} }
} }
...@@ -232,23 +195,23 @@ func TestFormats(t *testing.T) { ...@@ -232,23 +195,23 @@ func TestFormats(t *testing.T) {
printList(list) printList(list)
} }
// report all keys found // report all formats found
if len(keys) > 0 && testing.Verbose() { if len(foundFormats) > 0 && testing.Verbose() {
var list []string var list []string
for s := range keys { for s := range foundFormats {
list = append(list, fmt.Sprintf("%q: \"\",", s)) list = append(list, fmt.Sprintf("%q: \"\",", s))
} }
fmt.Println("\nvar formatMapping = map[string]string{") fmt.Println("\nvar knownFormats = map[string]string{")
printList(list) printList(list)
fmt.Println("}") fmt.Println("}")
} }
// all format literals must in the potentialFormats set (self-verification) // all format strings of calls must be in the formatStrings set (self-verification)
for _, p := range callSites { for _, p := range callSites {
if lit, ok := p.arg.(*ast.BasicLit); ok && lit.Kind == token.STRING { if lit, ok := p.arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
if potentialFormats[lit] { if formatStrings[lit] {
// ok // ok
delete(potentialFormats, lit) delete(formatStrings, lit)
} else { } else {
// this should never happen // this should never happen
panic(fmt.Sprintf("internal error: format string not found (%s)", posString(lit))) panic(fmt.Sprintf("internal error: format string not found (%s)", posString(lit)))
...@@ -257,15 +220,119 @@ func TestFormats(t *testing.T) { ...@@ -257,15 +220,119 @@ func TestFormats(t *testing.T) {
} }
// if we have any strings left, we may need to update them manually // if we have any strings left, we may need to update them manually
if len(potentialFormats) > 0 && dirty && *update { if len(formatStrings) > 0 && filesUpdated {
var list []string var list []string
for lit := range potentialFormats { for lit := range formatStrings {
list = append(list, fmt.Sprintf("%s: %s", posString(lit), nodeString(lit))) list = append(list, fmt.Sprintf("%s: %s", posString(lit), nodeString(lit)))
} }
fmt.Println("\nWARNING: Potentially missed format strings") fmt.Println("\nWARNING: Potentially missed format strings")
printList(list) printList(list)
t.Fail() t.Fail()
} }
fmt.Println()
}
// A callSite describes a function call that appears to contain
// a format string.
type callSite struct {
file File
call *ast.CallExpr // call containing the format string
arg ast.Expr // format argument (string literal or constant)
str string // unquoted format string
types []string // argument types
}
func collectPkgFormats(t *testing.T, pkg *build.Package) {
// collect all files
var filenames []string
filenames = append(filenames, pkg.GoFiles...)
filenames = append(filenames, pkg.CgoFiles...)
filenames = append(filenames, pkg.TestGoFiles...)
// TODO(gri) verify _test files outside package
for _, name := range pkg.XTestGoFiles {
// don't process this test itself
if name != "fmt_test.go" && testing.Verbose() {
fmt.Printf("WARNING: %s not processed\n", filepath.Join(pkg.Dir, name))
}
}
// make filenames relative to .
for i, name := range filenames {
filenames[i] = filepath.Join(pkg.Dir, name)
}
// parse all files
files := make([]*ast.File, len(filenames))
for i, filename := range filenames {
f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
files[i] = f
}
// typecheck package
conf := types.Config{Importer: importer.Default()}
etypes := make(map[ast.Expr]types.TypeAndValue)
if _, err := conf.Check(pkg.ImportPath, fset, files, &types.Info{Types: etypes}); err != nil {
t.Fatal(err)
}
// collect all potential format strings (for extra verification later)
for _, file := range files {
ast.Inspect(file, func(n ast.Node) bool {
if s, ok := stringLit(n); ok && isFormat(s) {
formatStrings[n.(*ast.BasicLit)] = true
}
return true
})
}
// collect all formats/arguments of calls with format strings
for index, file := range files {
ast.Inspect(file, func(n ast.Node) bool {
if call, ok := n.(*ast.CallExpr); ok {
// ignore blacklisted functions
if functionBlacklisted[nodeString(call.Fun)] {
return true
}
// look for an arguments that might be a format string
for i, arg := range call.Args {
if s, ok := stringVal(etypes[arg]); ok && isFormat(s) {
// make sure we have enough arguments
n := numFormatArgs(s)
if i+1+n > len(call.Args) {
t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
break // ignore this call
}
// assume last n arguments are to be formatted;
// determine their types
argTypes := make([]string, n)
for i, arg := range call.Args[len(call.Args)-n:] {
if tv, ok := etypes[arg]; ok {
argTypes[i] = typeString(tv.Type)
}
}
// collect call site
if callSites[call] != nil {
panic("internal error: file processed twice?")
}
callSites[call] = &callSite{
file: File{filenames[index], file},
call: call,
arg: arg,
str: s,
types: argTypes,
}
break // at most one format per argument list
}
}
}
return true
})
}
} }
// printList prints list in sorted order. // printList prints list in sorted order.
...@@ -294,15 +361,14 @@ func nodeString(n ast.Node) string { ...@@ -294,15 +361,14 @@ func nodeString(n ast.Node) string {
return buf.String() return buf.String()
} }
// typeString returns a string representation of t. // typeString returns a string representation of n.
func typeString(t types.Type) string { func typeString(typ types.Type) string {
return types.TypeString(t, func(pkg *types.Package) string { s := typ.String()
// don't qualify type names of the typed package // canonicalize path separators
if pkg == typedPkg { if filepath.Separator != '/' {
return "" s = strings.Replace(s, string(filepath.Separator), "/", -1)
} }
return pkg.Path() return s
})
} }
// stringLit returns the unquoted string value and true if // stringLit returns the unquoted string value and true if
...@@ -415,8 +481,8 @@ func oneFormat(s string) (yes bool) { ...@@ -415,8 +481,8 @@ func oneFormat(s string) (yes bool) {
return return
} }
// formatArgs counts the number of format specifiers in s. // numFormatArgs returns the number of format specifiers in s.
func formatArgs(s string) int { func numFormatArgs(s string) int {
count := 0 count := 0
formatIter(s, func(i, j int) int { formatIter(s, func(i, j int) int {
count++ count++
...@@ -443,158 +509,272 @@ func formatReplace(in string, f func(i int, s string) string) string { ...@@ -443,158 +509,272 @@ func formatReplace(in string, f func(i int, s string) string) string {
return string(append(buf, in[i0:]...)) return string(append(buf, in[i0:]...))
} }
// functionBlacklisted is the set of functions which may have
// format-like arguments but which don't do any formatting and
// thus may be ignored.
var functionBlacklisted = map[string]bool{
"len": true,
"strings.ContainsRune": true,
"w.WriteString": true,
}
func init() { func init() {
// verify that formatMapping entries are correctly formatted // verify that knownFormats entries are correctly formatted
for key, val := range formatMapping { for key, val := range knownFormats {
// key must be "typename format" (format may be "*") // key must be "typename format", and format starts with a '%'
i := strings.Index(key, " ") // (formats containing '*' alone are not collected in this table)
if i < 0 || key[i+1:] != "*" && !oneFormat(key[i+1:]) { i := strings.Index(key, "%")
log.Fatalf("incorrect formatMapping key: %q", key) if i < 0 || !oneFormat(key[i:]) {
log.Fatalf("incorrect knownFormats key: %q", key)
} }
// val must be "format" or "" // val must be "format" or ""
if val != "" && !oneFormat(val) { if val != "" && !oneFormat(val) {
log.Fatalf("incorrect formatMapping key: %q", key) log.Fatalf("incorrect knownFormats value: %q (key = %q)", val, key)
} }
} }
} }
// functionBlacklisted is the set of functions which are known to // knownFormats entries are of the form "typename oldformat" -> "newformat".
// have format-like arguments but which don't do any formatting // An absent entry means that the format is not recognized as valid.
// and thus can be ignored.
var functionBlacklisted = map[string]bool{
"len": true,
"strings.ContainsRune": true,
}
// formatMapping entries are of the form "typename oldformat" -> "newformat".
// An absent entry means that the format is not recognized as correct in test
// mode.
// An empty new format means that the existing format should remain unchanged. // An empty new format means that the existing format should remain unchanged.
// To generate a new table, run: go test -run Formats -v. // To print out a new table, run: go test -run Formats -v.
var formatMapping = map[string]string{ var knownFormats = map[string]string{
"*Bits %v": "", "**cmd/compile/internal/big.Rat %v": "",
"*Field %p": "", "*bytes.Buffer %s": "",
"*Field %v": "", "*cmd/compile/internal/big.Float %5s": "",
"*Mpflt %v": "", "*cmd/compile/internal/big.Float %s": "",
"*Mpint %v": "", "*cmd/compile/internal/big.Float %v": "",
"*Node %#v": "", "*cmd/compile/internal/big.Int %#x": "",
"*Node %+1v": "", "*cmd/compile/internal/big.Int %d": "",
"*Node %+v": "", "*cmd/compile/internal/big.Int %s": "",
"*Node %0j": "", "*cmd/compile/internal/big.Int %v": "",
"*Node %1v": "", "*cmd/compile/internal/big.Int %x": "",
"*Node %2v": "", "*cmd/compile/internal/big.Rat %p": "",
"*Node %j": "", "*cmd/compile/internal/big.Rat %s": "",
"*Node %p": "", "*cmd/compile/internal/big.Rat %v": "",
"*Node %s": "", "*cmd/compile/internal/big.matrix %s": "",
"*Node %v": "", "*cmd/compile/internal/gc.Bits %v": "",
"*Sym % v": "", "*cmd/compile/internal/gc.Field %p": "",
"*Sym %+v": "", "*cmd/compile/internal/gc.Field %v": "",
"*Sym %-v": "", "*cmd/compile/internal/gc.Mpflt %v": "",
"*Sym %01v": "", "*cmd/compile/internal/gc.Mpint %v": "",
"*Sym %1v": "", "*cmd/compile/internal/gc.Node %#v": "",
"*Sym %p": "", "*cmd/compile/internal/gc.Node %+1v": "",
"*Sym %s": "", "*cmd/compile/internal/gc.Node %+v": "",
"*Sym %v": "", "*cmd/compile/internal/gc.Node %0j": "",
"*Type % -v": "", "*cmd/compile/internal/gc.Node %1v": "",
"*Type %#v": "", "*cmd/compile/internal/gc.Node %2v": "",
"*Type %+v": "", "*cmd/compile/internal/gc.Node %j": "",
"*Type %- v": "", "*cmd/compile/internal/gc.Node %p": "",
"*Type %-1v": "", "*cmd/compile/internal/gc.Node %s": "",
"*Type %-v": "", "*cmd/compile/internal/gc.Node %v": "",
"*Type %01v": "", "*cmd/compile/internal/gc.Sym % v": "",
"*Type %1v": "", "*cmd/compile/internal/gc.Sym %+v": "",
"*Type %2v": "", "*cmd/compile/internal/gc.Sym %-v": "",
"*Type %p": "", "*cmd/compile/internal/gc.Sym %01v": "",
"*Type %s": "", "*cmd/compile/internal/gc.Sym %1v": "",
"*Type %v": "", "*cmd/compile/internal/gc.Sym %p": "",
"*cmd/compile/internal/big.Int %#x": "", "*cmd/compile/internal/gc.Sym %s": "",
"*cmd/compile/internal/ssa.Block %v": "", "*cmd/compile/internal/gc.Sym %v": "",
"*cmd/compile/internal/ssa.Func %s": "", "*cmd/compile/internal/gc.Type % -v": "",
"*cmd/compile/internal/ssa.Value %s": "", "*cmd/compile/internal/gc.Type %#v": "",
"*cmd/compile/internal/ssa.Value %v": "", "*cmd/compile/internal/gc.Type %+v": "",
"*cmd/internal/obj.Addr %v": "", "*cmd/compile/internal/gc.Type %- v": "",
"*cmd/internal/obj.Prog %p": "", "*cmd/compile/internal/gc.Type %-1v": "",
"*cmd/internal/obj.Prog %s": "", "*cmd/compile/internal/gc.Type %-v": "",
"*cmd/internal/obj.Prog %v": "", "*cmd/compile/internal/gc.Type %01v": "",
"Class %d": "", "*cmd/compile/internal/gc.Type %1v": "",
"Ctype %d": "", "*cmd/compile/internal/gc.Type %2v": "",
"Ctype %v": "", "*cmd/compile/internal/gc.Type %p": "",
"EType %d": "", "*cmd/compile/internal/gc.Type %s": "",
"EType %s": "", "*cmd/compile/internal/gc.Type %v": "",
"EType %v": "", "*cmd/compile/internal/ssa.Block %s": "",
"Level %d": "", "*cmd/compile/internal/ssa.Block %v": "",
"Level %v": "", "*cmd/compile/internal/ssa.Func %s": "",
"Nodes %#s": "", "*cmd/compile/internal/ssa.SparseTreeNode %v": "",
"Nodes %#v": "", "*cmd/compile/internal/ssa.Value %s": "",
"Nodes %+v": "", "*cmd/compile/internal/ssa.Value %v": "",
"Nodes %.v": "", "*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
"Nodes %v": "", "*cmd/internal/obj.Addr %v": "",
"Op %#v": "", "*cmd/internal/obj.Prog %p": "",
"Op %d": "", "*cmd/internal/obj.Prog %s": "",
"Op %s": "", "*cmd/internal/obj.Prog %v": "",
"Op %v": "", "[16]byte %x": "",
"Val %#v": "", "[]*cmd/compile/internal/big.Int %s": "",
"Val %s": "", "[]*cmd/compile/internal/big.Rat %s": "",
"Val %v": "", "[]*cmd/compile/internal/gc.Node %v": "",
"[16]byte %x": "", "[]*cmd/compile/internal/gc.Sig %#v": "",
"[]*Node %v": "", "[]*cmd/compile/internal/ssa.Value %v": "",
"[]byte %s": "", "[]byte %q": "",
"[]byte %x": "", "[]byte %s": "",
"bool %t": "", "[]byte %x": "",
"bool %v": "", "[]cmd/compile/internal/ssa.Edge %v": "",
"byte %02x": "", "[]cmd/compile/internal/ssa.ID %v": "",
"byte %c": "", "[]string %v": "",
"cmd/compile/internal/ssa.Location %v": "", "bool %t": "",
"cmd/compile/internal/ssa.Type %s": "", "bool %v": "",
"cmd/compile/internal/syntax.Expr %#v": "", "byte %02x": "",
"error %v": "", "byte %08b": "",
"float64 %.2f": "", "byte %c": "",
"float64 %.6g": "", "byte %d": "",
"float64 %g": "", "byte %q": "",
"fmt.Stringer %T": "", "cmd/compile/internal/arm.shift %d": "",
"initKind %d": "", "cmd/compile/internal/big.Accuracy %d": "",
"int %-12d": "", "cmd/compile/internal/big.Accuracy %s": "",
"int %-2d": "", "cmd/compile/internal/big.Bits %v": "",
"int %-6d": "", "cmd/compile/internal/big.ErrNaN %v": "",
"int %-8o": "", "cmd/compile/internal/big.Int %v": "",
"int %2d": "", "cmd/compile/internal/big.RoundingMode %d": "",
"int %6d": "", "cmd/compile/internal/big.RoundingMode %s": "",
"int %c": "", "cmd/compile/internal/big.RoundingMode %v": "",
"int %d": "", "cmd/compile/internal/big.Word %#x": "",
"int %v": "", "cmd/compile/internal/big.Word %d": "",
"int %x": "", "cmd/compile/internal/big.Word %x": "",
"int16 %2d": "", "cmd/compile/internal/big.argNN %+v": "",
"int16 %d": "", "cmd/compile/internal/big.argVV %+v": "",
"int32 %4d": "", "cmd/compile/internal/big.argVW %+v": "",
"int32 %5d": "", "cmd/compile/internal/big.argVWW %+v": "",
"int32 %d": "", "cmd/compile/internal/big.argWVW %+v": "",
"int32 %v": "", "cmd/compile/internal/big.argWW %+v": "",
"int64 %+d": "", "cmd/compile/internal/big.argZZ %+v": "",
"int64 %-10d": "", "cmd/compile/internal/big.decimal %v": "",
"int64 %d": "", "cmd/compile/internal/big.nat %v": "",
"int64 %v": "", "cmd/compile/internal/gc.Class %d": "",
"int8 %d": "", "cmd/compile/internal/gc.Ctype %d": "",
"interface{} %#v": "", "cmd/compile/internal/gc.Ctype %v": "",
"interface{} %T": "", "cmd/compile/internal/gc.EType %d": "",
"interface{} %v": "", "cmd/compile/internal/gc.EType %s": "",
"map[*Node]*cmd/compile/internal/ssa.Value %v": "", "cmd/compile/internal/gc.EType %v": "",
"reflect.Type %s": "", "cmd/compile/internal/gc.Level %d": "",
"rune %#U": "", "cmd/compile/internal/gc.Level %v": "",
"rune %c": "", "cmd/compile/internal/gc.Node %#v": "",
"rune %d": "", "cmd/compile/internal/gc.Nodes %#s": "",
"string %-16s": "", "cmd/compile/internal/gc.Nodes %#v": "",
"string %.*s": "", "cmd/compile/internal/gc.Nodes %+v": "",
"string %q": "", "cmd/compile/internal/gc.Nodes %.v": "",
"string %s": "", "cmd/compile/internal/gc.Nodes %v": "",
"string %v": "", "cmd/compile/internal/gc.Op %#v": "",
"time.Duration %d": "", "cmd/compile/internal/gc.Op %d": "",
"uint %.4d": "", "cmd/compile/internal/gc.Op %s": "",
"uint %04x": "", "cmd/compile/internal/gc.Op %v": "",
"uint16 %d": "", "cmd/compile/internal/gc.Val %#v": "",
"uint16 %v": "", "cmd/compile/internal/gc.Val %s": "",
"uint32 %#x": "", "cmd/compile/internal/gc.Val %v": "",
"uint32 %d": "", "cmd/compile/internal/gc.initKind %d": "",
"uint64 %#x": "", "cmd/compile/internal/ssa.BlockKind %s": "",
"uint64 %08x": "", "cmd/compile/internal/ssa.BranchPrediction %d": "",
"uint8 %d": "", "cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %s": "",
"cmd/compile/internal/ssa.ID %d": "",
"cmd/compile/internal/ssa.LocalSlot %s": "",
"cmd/compile/internal/ssa.Location %v": "",
"cmd/compile/internal/ssa.Op %s": "",
"cmd/compile/internal/ssa.Op %v": "",
"cmd/compile/internal/ssa.SizeAndAlign %s": "",
"cmd/compile/internal/ssa.Type %s": "",
"cmd/compile/internal/ssa.ValAndOff %s": "",
"cmd/compile/internal/ssa.markKind %d": "",
"cmd/compile/internal/ssa.rbrank %d": "",
"cmd/compile/internal/ssa.regMask %d": "",
"cmd/compile/internal/ssa.register %d": "",
"cmd/compile/internal/syntax.Expr %#v": "",
"cmd/compile/internal/syntax.Expr %s": "",
"cmd/compile/internal/syntax.Node %T": "",
"cmd/compile/internal/syntax.Operator %d": "",
"cmd/compile/internal/syntax.Operator %s": "",
"cmd/compile/internal/syntax.token %d": "",
"cmd/compile/internal/syntax.token %q": "",
"cmd/compile/internal/syntax.token %s": "",
"cmd/internal/obj.As %v": "",
"error %q": "",
"error %s": "",
"error %v": "",
"float32 %b": "",
"float32 %g": "",
"float64 %.2f": "",
"float64 %.3f": "",
"float64 %.5g": "",
"float64 %.6g": "",
"float64 %5g": "",
"float64 %b": "",
"float64 %g": "",
"float64 %v": "",
"fmt.Stringer %T": "",
"int %#x": "",
"int %-12d": "",
"int %-2d": "",
"int %-6d": "",
"int %-8o": "",
"int %2d": "",
"int %3d": "",
"int %5d": "",
"int %6d": "",
"int %c": "",
"int %d": "",
"int %v": "",
"int %x": "",
"int16 %2d": "",
"int16 %d": "",
"int16 %x": "",
"int32 %4d": "",
"int32 %5d": "",
"int32 %d": "",
"int32 %v": "",
"int32 %x": "",
"int64 %#x": "",
"int64 %+d": "",
"int64 %-10d": "",
"int64 %X": "",
"int64 %d": "",
"int64 %v": "",
"int64 %x": "",
"int8 %d": "",
"int8 %x": "",
"interface{} %#v": "",
"interface{} %T": "",
"interface{} %q": "",
"interface{} %s": "",
"interface{} %v": "",
"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
"reflect.Type %s": "",
"rune %#U": "",
"rune %c": "",
"rune %d": "",
"rune %q": "",
"string %-16s": "",
"string %.*s": "",
"string %q": "",
"string %s": "",
"string %v": "",
"struct{format string; value interface{}; want string} %v": "",
"struct{in string; out string; base int; val int64; ok bool} %v": "",
"struct{s string; base int; frac bool; x cmd/compile/internal/big.nat; b int; count int; ok bool; next rune} %+v": "",
"struct{x cmd/compile/internal/big.nat; b int; s string} %+v": "",
"struct{x float64; format byte; prec int; want string} %v": "",
"struct{x string; prec uint; format byte; digits int; want string} %v": "",
"time.Duration %10s": "",
"time.Duration %4d": "",
"time.Duration %d": "",
"time.Duration %v": "",
"uint %.4d": "",
"uint %04x": "",
"uint %d": "",
"uint %v": "",
"uint16 %d": "",
"uint16 %v": "",
"uint16 %x": "",
"uint32 %#08x": "",
"uint32 %#x": "",
"uint32 %08x": "",
"uint32 %d": "",
"uint32 %x": "",
"uint64 %#016x": "",
"uint64 %#x": "",
"uint64 %016x": "",
"uint64 %08x": "",
"uint64 %d": "",
"uint64 %x": "",
"uint8 %d": "",
"uint8 %x": "",
"uintptr %d": "",
} }
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