Flag: -printf
-Suspicious calls to functions in the Printf family, including any functions
-with these names, disregarding case:
- Print Printf Println
- Fprint Fprintf Fprintln
- Sprint Sprintf Sprintln
- Error Errorf
- Fatal Fatalf
- Log Logf
- Panic Panicf Panicln
-The -printfuncs flag can be used to redefine this list.
-If the function name ends with an 'f', the function is assumed to take
-a format descriptor string in the manner of fmt.Printf. If not, vet
-complains about arguments that look like format descriptor strings.
-
-It also checks for errors such as using a Writer as the first argument of
-Printf.
+Suspicious calls to fmt.Print, fmt.Printf, and related functions.
+The check applies to known functions (for example, those in package fmt)
+as well as any detected wrappers of known functions.
+
+The -printfuncs flag specifies a comma-separated list of names of
+additional known formatting functions. Each name can be of the form
+pkg.Name or pkg.Type.Name, where pkg is a complete import path,
+or else can be a case-insensitive unqualified identifier like "errorf".
+If a listed name ends in f, the function is assumed to be Printf-like,
+taking a format string before the argument list. Otherwise it is
+assumed to be Print-like, taking a list of arguments with no format string.
Range loop variables
// Vet is a simple checker for static errors in Go source code.
// See doc.go for more information.
+
package main
import (
"bytes"
+ "encoding/gob"
"encoding/json"
"flag"
"fmt"
"path/filepath"
"strconv"
"strings"
+
+ "cmd/internal/objabi"
)
// Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go.
// checkers is a two-level map.
// The outer level is keyed by a nil pointer, one of the AST vars above.
// The inner level is keyed by checker name.
- checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+ checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+ pkgCheckers = make(map[string]func(*Package))
+ exporters = make(map[string]func() interface{})
)
+// Vet can provide its own "export information"
+// about package A to future invocations of vet
+// on packages importing A. If B imports A,
+// then running "go vet B" actually invokes vet twice:
+// first, it runs vet on A, in "vetx-only" mode, which
+// skips most checks and only computes export data
+// describing A. Then it runs vet on B, making A's vetx
+// data available for consultation. The vet of B
+// computes vetx data for B in addition to its
+// usual vet checks.
+
+// register registers the named check function,
+// to be called with AST nodes of the given types.
+// The registered functions are not called in vetx-only mode.
func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
report[name] = triStateFlag(name, unset, usage)
for _, typ := range types {
}
}
+// registerPkgCheck registers a package-level checking function,
+// to be invoked with the whole package being vetted
+// before any of the per-node handlers.
+// The registered function fn is called even in vetx-only mode
+// (see comment above), so fn must take care not to report
+// errors when vcfg.VetxOnly is true.
+func registerPkgCheck(name string, fn func(*Package)) {
+ pkgCheckers[name] = fn
+}
+
+// registerExport registers a function to return vetx export data
+// that should be saved and provided to future invocations of vet
+// when checking packages importing this one.
+// The value returned by fn should be nil or else valid to encode using gob.
+// Typically a registerExport call is paired with a call to gob.Register.
+func registerExport(name string, fn func() interface{}) {
+ exporters[name] = fn
+}
+
// Usage is a replacement usage function for the flags package.
func Usage() {
fmt.Fprintf(os.Stderr, "Usage of vet:\n")
}
func main() {
+ objabi.AddVersionFlag()
flag.Usage = Usage
flag.Parse()
ImportMap map[string]string
PackageFile map[string]string
Standard map[string]bool
+ PackageVetx map[string]string // map from import path to vetx data file
+ VetxOnly bool // only compute vetx output; don't run ordinary checks
+ VetxOutput string // file where vetx output should be written
SucceedOnTypecheckFailure bool
inittypes()
mustTypecheck = true
doPackage(vcfg.GoFiles, nil)
+ if vcfg.VetxOutput != "" {
+ out := make(map[string]interface{})
+ for name, fn := range exporters {
+ out[name] = fn()
+ }
+ var buf bytes.Buffer
+ if err := gob.NewEncoder(&buf).Encode(out); err != nil {
+ errorf("encoding vet output: %v", err)
+ return
+ }
+ if err := ioutil.WriteFile(vcfg.VetxOutput, buf.Bytes(), 0666); err != nil {
+ errorf("saving vet output: %v", err)
+ return
+ }
+ }
}
// doPackageDir analyzes the single package found in the directory, if there is one,
}
// Check.
+ for _, file := range files {
+ file.pkg = pkg
+ file.basePkg = basePkg
+ }
+ for name, fn := range pkgCheckers {
+ if vet(name) {
+ fn(pkg)
+ }
+ }
+ if vcfg.VetxOnly {
+ return pkg
+ }
+
chk := make(map[ast.Node][]func(*File, ast.Node))
for typ, set := range checkers {
for name, fn := range set {
}
}
for _, file := range files {
- file.pkg = pkg
- file.basePkg = basePkg
file.checkers = chk
if file.file != nil {
file.walkFile(file.name, file.file)
}
}
- asmCheck(pkg)
return pkg
}
printer.Fprint(&f.b, f.fset, x)
return f.b.String()
}
+
+// imported[path][key] is previously written export data.
+var imported = make(map[string]map[string]interface{})
+
+// readVetx reads export data written by a previous
+// invocation of vet on an imported package (path).
+// The key is the name passed to registerExport
+// when the data was originally generated.
+// readVetx returns nil if the data is unavailable.
+func readVetx(path, key string) interface{} {
+ if path == "unsafe" || vcfg.ImportPath == "" {
+ return nil
+ }
+ m := imported[path]
+ if m == nil {
+ file := vcfg.PackageVetx[path]
+ if file == "" {
+ return nil
+ }
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ return nil
+ }
+ m = make(map[string]interface{})
+ err = gob.NewDecoder(bytes.NewReader(data)).Decode(&m)
+ if err != nil {
+ return nil
+ }
+ imported[path] = m
+ }
+ return m[key]
+}