go/analysis/passes/vet: delete
All the passes have been moved into their own packages.
The README file has been saved for the new cmd/analyze command,
which will shortly be renamed to vet.
Change-Id: I68c765a4da2f8d5a2b0161b462bd81483b5ceed5
Reviewed-on: https://go-review.googlesource.com/c/143301
Reviewed-by: Michael Matloob <matloob@golang.org>
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/go/analysis/passes/vet/README b/go/analysis/cmd/analyze/README
similarity index 100%
rename from go/analysis/passes/vet/README
rename to go/analysis/cmd/analyze/README
diff --git a/go/analysis/passes/vet/REVISION b/go/analysis/passes/vet/REVISION
deleted file mode 100644
index dbd98e1..0000000
--- a/go/analysis/passes/vet/REVISION
+++ /dev/null
@@ -1 +0,0 @@
-cmd/vet@31d19c0
\ No newline at end of file
diff --git a/go/analysis/passes/vet/doc.go b/go/analysis/passes/vet/doc.go
deleted file mode 100644
index 0b970d0..0000000
--- a/go/analysis/passes/vet/doc.go
+++ /dev/null
@@ -1,221 +0,0 @@
-// +build ignore
-
-// Copyright 2010 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.
-
-/*
-
-Vet examines Go source code and reports suspicious constructs, such as Printf
-calls whose arguments do not align with the format string. Vet uses heuristics
-that do not guarantee all reports are genuine problems, but it can find errors
-not caught by the compilers.
-
-Vet is normally invoked using the go command by running "go vet":
-
- go vet
-vets the package in the current directory.
-
- go vet package/path/name
-vets the package whose path is provided.
-
-Use "go help packages" to see other ways of specifying which packages to vet.
-
-Vet's exit code is 2 for erroneous invocation of the tool, 1 if a
-problem was reported, and 0 otherwise. Note that the tool does not
-check every possible problem and depends on unreliable heuristics
-so it should be used as guidance only, not as a firm indicator of
-program correctness.
-
-By default the -all flag is set so all checks are performed.
-If any flags are explicitly set to true, only those tests are run. Conversely, if
-any flag is explicitly set to false, only those tests are disabled. Thus -printf=true
-runs the printf check, -printf=false runs all checks except the printf check.
-
-By default vet uses the object files generated by 'go install some/pkg' to typecheck the code.
-If the -source flag is provided, vet uses only source code.
-
-Available checks:
-
-Assembly declarations
-
-Flag: -asmdecl
-
-Mismatches between assembly files and Go function declarations.
-
-Useless assignments
-
-Flag: -assign
-
-Check for useless assignments.
-
-Atomic mistakes
-
-Flag: -atomic
-
-Common mistaken usages of the sync/atomic package.
-
-Boolean conditions
-
-Flag: -bool
-
-Mistakes involving boolean operators.
-
-Build tags
-
-Flag: -buildtags
-
-Badly formed or misplaced +build tags.
-
-Invalid uses of cgo
-
-Flag: -cgocall
-
-Detect some violations of the cgo pointer passing rules.
-
-Unkeyed composite literals
-
-Flag: -composites
-
-Composite struct literals that do not use the field-keyed syntax.
-
-Copying locks
-
-Flag: -copylocks
-
-Locks that are erroneously passed by value.
-
-HTTP responses used incorrectly
-
-Flag: -httpresponse
-
-Mistakes deferring a function call on an HTTP response before
-checking whether the error returned with the response was nil.
-
-Failure to call the cancelation function returned by WithCancel
-
-Flag: -lostcancel
-
-The cancelation function returned by context.WithCancel, WithTimeout,
-and WithDeadline must be called or the new context will remain live
-until its parent context is cancelled.
-(The background context is never cancelled.)
-
-Methods
-
-Flag: -methods
-
-Non-standard signatures for methods with familiar names, including:
- Format GobEncode GobDecode MarshalJSON MarshalXML
- Peek ReadByte ReadFrom ReadRune Scan Seek
- UnmarshalJSON UnreadByte UnreadRune WriteByte
- WriteTo
-
-Nil function comparison
-
-Flag: -nilfunc
-
-Comparisons between functions and nil.
-
-Printf family
-
-Flag: -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
-
-Flag: -rangeloops
-
-Incorrect uses of range loop variables in closures.
-
-Shadowed variables
-
-Flag: -shadow=false (experimental; must be set explicitly)
-
-Variables that may have been unintentionally shadowed.
-
-Shifts
-
-Flag: -shift
-
-Shifts equal to or longer than the variable's length.
-
-Struct tags
-
-Flag: -structtags
-
-Struct tags that do not follow the format understood by reflect.StructTag.Get.
-Well-known encoding struct tags (json, xml) used with unexported fields.
-
-Tests and documentation examples
-
-Flag: -tests
-
-Mistakes involving tests including functions with incorrect names or signatures
-and example tests that document identifiers not in the package.
-
-Unreachable code
-
-Flag: -unreachable
-
-Unreachable code.
-
-Misuse of unsafe Pointers
-
-Flag: -unsafeptr
-
-Likely incorrect uses of unsafe.Pointer to convert integers to pointers.
-A conversion from uintptr to unsafe.Pointer is invalid if it implies that
-there is a uintptr-typed word in memory that holds a pointer value,
-because that word will be invisible to stack copying and to the garbage
-collector.
-
-Unused result of certain function calls
-
-Flag: -unusedresult
-
-Calls to well-known functions and methods that return a value that is
-discarded. By default, this includes functions like fmt.Errorf and
-fmt.Sprintf and methods like String and Error. The flags -unusedfuncs
-and -unusedstringmethods control the set.
-
-Other flags
-
-These flags configure the behavior of vet:
-
- -all (default true)
- Enable all non-experimental checks.
- -v
- Verbose mode
- -printfuncs
- A comma-separated list of print-like function names
- to supplement the standard list.
- For more information, see the discussion of the -printf flag.
- -shadowstrict
- Whether to be strict about shadowing; can be noisy.
-
-Using vet directly
-
-For testing and debugging vet can be run directly by invoking
-"go tool vet" or just running the binary. Run this way, vet might not
-have up to date information for imported packages.
-
- go tool vet source/directory/*.go
-vets the files named, all of which must be in the same package.
-
- go tool vet source/directory
-recursively descends the directory, vetting each package it finds.
-
-*/
-package main
diff --git a/go/analysis/passes/vet/main.go b/go/analysis/passes/vet/main.go
deleted file mode 100644
index 60114c5..0000000
--- a/go/analysis/passes/vet/main.go
+++ /dev/null
@@ -1,753 +0,0 @@
-// +build ignore
-
-// Copyright 2010 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.
-
-// 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"
- "go/ast"
- "go/build"
- "go/importer"
- "go/parser"
- "go/printer"
- "go/token"
- "go/types"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "sort"
- "strconv"
- "strings"
-
- "cmd/internal/objabi"
-)
-
-// Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go.
-
-var (
- verbose = flag.Bool("v", false, "verbose")
- source = flag.Bool("source", false, "import from source instead of compiled object files")
- tags = flag.String("tags", "", "space-separated list of build tags to apply when parsing")
- tagList = []string{} // exploded version of tags flag; set in main
-
- vcfg vetConfig
- mustTypecheck bool
-)
-
-var exitCode = 0
-
-// "-all" flag enables all non-experimental checks
-var all = triStateFlag("all", unset, "enable all non-experimental checks")
-
-// Flags to control which individual checks to perform.
-var report = map[string]*triState{
- // Only unusual checks are written here.
- // Most checks that operate during the AST walk are added by register.
- "asmdecl": triStateFlag("asmdecl", unset, "check assembly against Go declarations"),
- "buildtags": triStateFlag("buildtags", unset, "check that +build tags are valid"),
-}
-
-// experimental records the flags enabling experimental features. These must be
-// requested explicitly; they are not enabled by -all.
-var experimental = map[string]bool{}
-
-// setTrueCount record how many flags are explicitly set to true.
-var setTrueCount int
-
-// dirsRun and filesRun indicate whether the vet is applied to directory or
-// file targets. The distinction affects which checks are run.
-var dirsRun, filesRun bool
-
-// includesNonTest indicates whether the vet is applied to non-test targets.
-// Certain checks are relevant only if they touch both test and non-test files.
-var includesNonTest bool
-
-// A triState is a boolean that knows whether it has been set to either true or false.
-// It is used to identify if a flag appears; the standard boolean flag cannot
-// distinguish missing from unset. It also satisfies flag.Value.
-type triState int
-
-const (
- unset triState = iota
- setTrue
- setFalse
-)
-
-func triStateFlag(name string, value triState, usage string) *triState {
- flag.Var(&value, name, usage)
- return &value
-}
-
-// triState implements flag.Value, flag.Getter, and flag.boolFlag.
-// They work like boolean flags: we can say vet -printf as well as vet -printf=true
-func (ts *triState) Get() interface{} {
- return *ts == setTrue
-}
-
-func (ts triState) isTrue() bool {
- return ts == setTrue
-}
-
-func (ts *triState) Set(value string) error {
- b, err := strconv.ParseBool(value)
- if err != nil {
- return err
- }
- if b {
- *ts = setTrue
- setTrueCount++
- } else {
- *ts = setFalse
- }
- return nil
-}
-
-func (ts *triState) String() string {
- switch *ts {
- case unset:
- return "true" // An unset flag will be set by -all, so defaults to true.
- case setTrue:
- return "true"
- case setFalse:
- return "false"
- }
- panic("not reached")
-}
-
-func (ts triState) IsBoolFlag() bool {
- return true
-}
-
-// vet tells whether to report errors for the named check, a flag name.
-func vet(name string) bool {
- return report[name].isTrue()
-}
-
-// setExit sets the value for os.Exit when it is called, later. It
-// remembers the highest value.
-func setExit(err int) {
- if err > exitCode {
- exitCode = err
- }
-}
-
-var (
- // Each of these vars has a corresponding case in (*File).Visit.
- assignStmt *ast.AssignStmt
- binaryExpr *ast.BinaryExpr
- callExpr *ast.CallExpr
- compositeLit *ast.CompositeLit
- exprStmt *ast.ExprStmt
- forStmt *ast.ForStmt
- funcDecl *ast.FuncDecl
- funcLit *ast.FuncLit
- genDecl *ast.GenDecl
- interfaceType *ast.InterfaceType
- rangeStmt *ast.RangeStmt
- returnStmt *ast.ReturnStmt
- structType *ast.StructType
-
- // 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))
- pkgCheckers = make(map[string]func(*Package))
- 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,
-// 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 {
- m := checkers[typ]
- if m == nil {
- m = make(map[string]func(*File, ast.Node))
- checkers[typ] = m
- }
- m[name] = fn
- }
-}
-
-// 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")
- fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n")
- fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
- fmt.Fprintf(os.Stderr, "By default, -all is set and all non-experimental checks are run.\n")
- fmt.Fprintf(os.Stderr, "For more information run\n")
- fmt.Fprintf(os.Stderr, "\tgo doc cmd/vet\n\n")
- fmt.Fprintf(os.Stderr, "Flags:\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-// File is a wrapper for the state of a file used in the parser.
-// The parse tree walkers are all methods of this type.
-type File struct {
- pkg *Package
- fset *token.FileSet
- name string
- content []byte
- file *ast.File
- b bytes.Buffer // for use by methods
-
- // Parsed package "foo" when checking package "foo_test"
- basePkg *Package
-
- // The keys are the objects that are receivers of a "String()
- // string" method. The value reports whether the method has a
- // pointer receiver.
- // This is used by the recursiveStringer method in print.go.
- stringerPtrs map[*ast.Object]bool
-
- // Registered checkers to run.
- checkers map[ast.Node][]func(*File, ast.Node)
-
- // Unreachable nodes; can be ignored in shift check.
- dead map[ast.Node]bool
-}
-
-func main() {
- objabi.AddVersionFlag()
- flag.Usage = Usage
- flag.Parse()
-
- // If any flag is set, we run only those checks requested.
- // If all flag is set true or if no flags are set true, set all the non-experimental ones
- // not explicitly set (in effect, set the "-all" flag).
- if setTrueCount == 0 || *all == setTrue {
- for name, setting := range report {
- if *setting == unset && !experimental[name] {
- *setting = setTrue
- }
- }
- }
-
- // Accept space-separated tags because that matches
- // the go command's other subcommands.
- // Accept commas because go tool vet traditionally has.
- tagList = strings.Fields(strings.ReplaceAll(*tags, ",", " "))
-
- initPrintFlags()
- initUnusedFlags()
-
- if flag.NArg() == 0 {
- Usage()
- }
-
- // Special case for "go vet" passing an explicit configuration:
- // single argument ending in vet.cfg.
- // Once we have a more general mechanism for obtaining this
- // information from build tools like the go command,
- // vet should be changed to use it. This vet.cfg hack is an
- // experiment to learn about what form that information should take.
- if flag.NArg() == 1 && strings.HasSuffix(flag.Arg(0), "vet.cfg") {
- doPackageCfg(flag.Arg(0))
- os.Exit(exitCode)
- }
-
- for _, name := range flag.Args() {
- // Is it a directory?
- fi, err := os.Stat(name)
- if err != nil {
- warnf("error walking tree: %s", err)
- continue
- }
- if fi.IsDir() {
- dirsRun = true
- } else {
- filesRun = true
- if !strings.HasSuffix(name, "_test.go") {
- includesNonTest = true
- }
- }
- }
- if dirsRun && filesRun {
- Usage()
- }
- if dirsRun {
- for _, name := range flag.Args() {
- walkDir(name)
- }
- os.Exit(exitCode)
- }
- if doPackage(flag.Args(), nil) == nil {
- warnf("no files checked")
- }
- os.Exit(exitCode)
-}
-
-// prefixDirectory places the directory name on the beginning of each name in the list.
-func prefixDirectory(directory string, names []string) {
- if directory != "." {
- for i, name := range names {
- names[i] = filepath.Join(directory, name)
- }
- }
-}
-
-// vetConfig is the JSON config struct prepared by the Go command.
-type vetConfig struct {
- Compiler string
- Dir string
- ImportPath string
- GoFiles []string
- 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
-
- imp types.Importer
-}
-
-func (v *vetConfig) Import(path string) (*types.Package, error) {
- if v.imp == nil {
- v.imp = importer.For(v.Compiler, v.openPackageFile)
- }
- if path == "unsafe" {
- return v.imp.Import("unsafe")
- }
- p := v.ImportMap[path]
- if p == "" {
- return nil, fmt.Errorf("unknown import path %q", path)
- }
- if v.PackageFile[p] == "" {
- if v.Compiler == "gccgo" && v.Standard[path] {
- // gccgo doesn't have sources for standard library packages,
- // but the importer will do the right thing.
- return v.imp.Import(path)
- }
- return nil, fmt.Errorf("unknown package file for import %q", path)
- }
- return v.imp.Import(p)
-}
-
-func (v *vetConfig) openPackageFile(path string) (io.ReadCloser, error) {
- file := v.PackageFile[path]
- if file == "" {
- if v.Compiler == "gccgo" && v.Standard[path] {
- // The importer knows how to handle this.
- return nil, nil
- }
- // Note that path here has been translated via v.ImportMap,
- // unlike in the error in Import above. We prefer the error in
- // Import, but it's worth diagnosing this one too, just in case.
- return nil, fmt.Errorf("unknown package file for %q", path)
- }
- f, err := os.Open(file)
- if err != nil {
- return nil, err
- }
- return f, nil
-}
-
-// doPackageCfg analyzes a single package described in a config file.
-func doPackageCfg(cfgFile string) {
- js, err := ioutil.ReadFile(cfgFile)
- if err != nil {
- errorf("%v", err)
- }
- if err := json.Unmarshal(js, &vcfg); err != nil {
- errorf("parsing vet config %s: %v", cfgFile, err)
- }
- stdImporter = &vcfg
- inittypes()
- mustTypecheck = true
- doPackage(vcfg.GoFiles, nil)
- if vcfg.VetxOutput != "" {
- out := make([]vetxExport, 0, len(exporters))
- for name, fn := range exporters {
- 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)
- 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,
-// plus a test package, if there is one.
-func doPackageDir(directory string) {
- context := build.Default
- if len(context.BuildTags) != 0 {
- warnf("build tags %s previously set", context.BuildTags)
- }
- context.BuildTags = append(tagList, context.BuildTags...)
-
- pkg, err := context.ImportDir(directory, 0)
- if err != nil {
- // If it's just that there are no go source files, that's fine.
- if _, nogo := err.(*build.NoGoError); nogo {
- return
- }
- // Non-fatal: we are doing a recursive walk and there may be other directories.
- warnf("cannot process directory %s: %s", directory, err)
- return
- }
- var names []string
- names = append(names, pkg.GoFiles...)
- names = append(names, pkg.CgoFiles...)
- names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
- names = append(names, pkg.SFiles...)
- prefixDirectory(directory, names)
- basePkg := doPackage(names, nil)
- // Is there also a "foo_test" package? If so, do that one as well.
- if len(pkg.XTestGoFiles) > 0 {
- names = pkg.XTestGoFiles
- prefixDirectory(directory, names)
- doPackage(names, basePkg)
- }
-}
-
-type Package struct {
- path string
- defs map[*ast.Ident]types.Object
- uses map[*ast.Ident]types.Object
- implicits map[ast.Node]types.Object
- selectors map[*ast.SelectorExpr]*types.Selection
- types map[ast.Expr]types.TypeAndValue
- spans map[types.Object]Span
- files []*File
- typesPkg *types.Package
-}
-
-// doPackage analyzes the single package constructed from the named files.
-// It returns the parsed Package or nil if none of the files have been checked.
-func doPackage(names []string, basePkg *Package) *Package {
- var files []*File
- var astFiles []*ast.File
- fs := token.NewFileSet()
- for _, name := range names {
- data, err := ioutil.ReadFile(name)
- if err != nil {
- // Warn but continue to next package.
- warnf("%s: %s", name, err)
- return nil
- }
- var parsedFile *ast.File
- if strings.HasSuffix(name, ".go") {
- parsedFile, err = parser.ParseFile(fs, name, data, parser.ParseComments)
- if err != nil {
- warnf("%s: %s", name, err)
- return nil
- }
- astFiles = append(astFiles, parsedFile)
- }
- file := &File{
- fset: fs,
- content: data,
- name: name,
- file: parsedFile,
- dead: make(map[ast.Node]bool),
- }
- files = append(files, file)
- }
- if len(astFiles) == 0 {
- return nil
- }
- pkg := new(Package)
- pkg.path = astFiles[0].Name.Name
- pkg.files = files
- // Type check the package.
- errs := pkg.check(fs, astFiles)
- if errs != nil {
- if vcfg.SucceedOnTypecheckFailure {
- os.Exit(0)
- }
- if *verbose || mustTypecheck {
- for _, err := range errs {
- fmt.Fprintf(os.Stderr, "%v\n", err)
- }
- if mustTypecheck {
- // This message could be silenced, and we could just exit,
- // but it might be helpful at least at first to make clear that the
- // above errors are coming from vet and not the compiler
- // (they often look like compiler errors, such as "declared but not used").
- errorf("typecheck failures")
- }
- }
- }
-
- // 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 {
- if vet(name) {
- chk[typ] = append(chk[typ], fn)
- }
- }
- }
- for _, file := range files {
- checkBuildTag(file)
- file.checkers = chk
- if file.file != nil {
- file.walkFile(file.name, file.file)
- }
- }
- return pkg
-}
-
-func visit(path string, f os.FileInfo, err error) error {
- if err != nil {
- warnf("walk error: %s", err)
- return err
- }
- // One package per directory. Ignore the files themselves.
- if !f.IsDir() {
- return nil
- }
- doPackageDir(path)
- return nil
-}
-
-func (pkg *Package) hasFileWithSuffix(suffix string) bool {
- for _, f := range pkg.files {
- if strings.HasSuffix(f.name, suffix) {
- return true
- }
- }
- return false
-}
-
-// walkDir recursively walks the tree looking for Go packages.
-func walkDir(root string) {
- filepath.Walk(root, visit)
-}
-
-// errorf formats the error to standard error, adding program
-// identification and a newline, and exits.
-func errorf(format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
- os.Exit(2)
-}
-
-// warnf formats the error to standard error, adding program
-// identification and a newline, but does not exit.
-func warnf(format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
- setExit(1)
-}
-
-// Println is fmt.Println guarded by -v.
-func Println(args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Println(args...)
-}
-
-// Printf is fmt.Printf guarded by -v.
-func Printf(format string, args ...interface{}) {
- if !*verbose {
- return
- }
- fmt.Printf(format+"\n", args...)
-}
-
-// Bad reports an error and sets the exit code..
-func (f *File) Bad(pos token.Pos, args ...interface{}) {
- f.Warn(pos, args...)
- setExit(1)
-}
-
-// Badf reports a formatted error and sets the exit code.
-func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
- f.Warnf(pos, format, args...)
- setExit(1)
-}
-
-// loc returns a formatted representation of the position.
-func (f *File) loc(pos token.Pos) string {
- if pos == token.NoPos {
- return ""
- }
- // Do not print columns. Because the pos often points to the start of an
- // expression instead of the inner part with the actual error, the
- // precision can mislead.
- posn := f.fset.Position(pos)
- return fmt.Sprintf("%s:%d", posn.Filename, posn.Line)
-}
-
-// locPrefix returns a formatted representation of the position for use as a line prefix.
-func (f *File) locPrefix(pos token.Pos) string {
- if pos == token.NoPos {
- return ""
- }
- return fmt.Sprintf("%s: ", f.loc(pos))
-}
-
-// Warn reports an error but does not set the exit code.
-func (f *File) Warn(pos token.Pos, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "%s%s", f.locPrefix(pos), fmt.Sprintln(args...))
-}
-
-// Warnf reports a formatted error but does not set the exit code.
-func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "%s%s\n", f.locPrefix(pos), fmt.Sprintf(format, args...))
-}
-
-// walkFile walks the file's tree.
-func (f *File) walkFile(name string, file *ast.File) {
- Println("Checking file", name)
- ast.Walk(f, file)
-}
-
-// Visit implements the ast.Visitor interface.
-func (f *File) Visit(node ast.Node) ast.Visitor {
- f.updateDead(node)
- var key ast.Node
- switch node.(type) {
- case *ast.AssignStmt:
- key = assignStmt
- case *ast.BinaryExpr:
- key = binaryExpr
- case *ast.CallExpr:
- key = callExpr
- case *ast.CompositeLit:
- key = compositeLit
- case *ast.ExprStmt:
- key = exprStmt
- case *ast.ForStmt:
- key = forStmt
- case *ast.FuncDecl:
- key = funcDecl
- case *ast.FuncLit:
- key = funcLit
- case *ast.GenDecl:
- key = genDecl
- case *ast.InterfaceType:
- key = interfaceType
- case *ast.RangeStmt:
- key = rangeStmt
- case *ast.ReturnStmt:
- key = returnStmt
- case *ast.StructType:
- key = structType
- }
- for _, fn := range f.checkers[key] {
- fn(f, node)
- }
- return f
-}
-
-// gofmt returns a string representation of the expression.
-func (f *File) gofmt(x ast.Expr) string {
- f.b.Reset()
- 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
- }
- 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]
-}
diff --git a/go/analysis/passes/vet/testdata/tagtest/file1.go b/go/analysis/passes/vet/testdata/tagtest/file1.go
deleted file mode 100644
index 22a1509..0000000
--- a/go/analysis/passes/vet/testdata/tagtest/file1.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2015 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.
-
-// +build testtag
-
-package main
-
-func main() {
-}
diff --git a/go/analysis/passes/vet/testdata/tagtest/file2.go b/go/analysis/passes/vet/testdata/tagtest/file2.go
deleted file mode 100644
index ba7dd91..0000000
--- a/go/analysis/passes/vet/testdata/tagtest/file2.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2015 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.
-
-// +build !testtag
-
-package main
-
-func ignore() {
-}
diff --git a/go/analysis/passes/vet/vet_test.go b/go/analysis/passes/vet/vet_test.go
deleted file mode 100644
index 0d0c439..0000000
--- a/go/analysis/passes/vet/vet_test.go
+++ /dev/null
@@ -1,441 +0,0 @@
-// +build ignore
-
-// Copyright 2013 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 main_test
-
-import (
- "bytes"
- "errors"
- "fmt"
- "internal/testenv"
- "io/ioutil"
- "log"
- "os"
- "os/exec"
- "path/filepath"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "sync"
- "testing"
-)
-
-const (
- dataDir = "testdata"
- binary = "./testvet.exe"
-)
-
-// We implement TestMain so remove the test binary when all is done.
-func TestMain(m *testing.M) {
- result := m.Run()
- os.Remove(binary)
- os.Exit(result)
-}
-
-var (
- buildMu sync.Mutex // guards following
- built = false // We have built the binary.
- failed = false // We have failed to build the binary, don't try again.
-)
-
-func Build(t *testing.T) {
- buildMu.Lock()
- defer buildMu.Unlock()
- if built {
- return
- }
- if failed {
- t.Skip("cannot run on this environment")
- }
- testenv.MustHaveGoBuild(t)
- cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", binary)
- output, err := cmd.CombinedOutput()
- if err != nil {
- failed = true
- fmt.Fprintf(os.Stderr, "%s\n", output)
- t.Fatal(err)
- }
- built = true
-}
-
-func Vet(t *testing.T, files []string) {
- flags := []string{
- "-printfuncs=Warn:1,Warnf:1",
- "-all",
- "-shadow",
- }
- cmd := exec.Command(binary, append(flags, files...)...)
- errchk(cmd, files, t)
-}
-
-// TestVet is equivalent to running this:
-// go build -o ./testvet
-// errorCheck the output of ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s
-// rm ./testvet
-//
-
-// TestVet tests self-contained files in testdata/*.go.
-//
-// If a file contains assembly or has inter-dependencies, it should be
-// in its own test, like TestVetAsm, TestDivergentPackagesExamples,
-// etc below.
-func TestVet(t *testing.T) {
- Build(t)
- t.Parallel()
-
- gos, err := filepath.Glob(filepath.Join(dataDir, "*.go"))
- if err != nil {
- t.Fatal(err)
- }
- wide := runtime.GOMAXPROCS(0)
- if wide > len(gos) {
- wide = len(gos)
- }
- batch := make([][]string, wide)
- for i, file := range gos {
- // The print.go test is run by TestVetPrint.
- if strings.HasSuffix(file, "print.go") {
- continue
- }
- batch[i%wide] = append(batch[i%wide], file)
- }
- for i, files := range batch {
- if len(files) == 0 {
- continue
- }
- files := files
- t.Run(fmt.Sprint(i), func(t *testing.T) {
- t.Parallel()
- t.Logf("files: %q", files)
- Vet(t, files)
- })
- }
-}
-
-func TestVetPrint(t *testing.T) {
- Build(t)
- file := filepath.Join("testdata", "print.go")
- cmd := exec.Command(
- "go", "vet", "-vettool="+binary,
- "-printf",
- "-printfuncs=Warn:1,Warnf:1",
- file,
- )
- errchk(cmd, []string{file}, t)
-}
-
-func TestVetAsm(t *testing.T) {
- Build(t)
-
- asmDir := filepath.Join(dataDir, "asm")
- gos, err := filepath.Glob(filepath.Join(asmDir, "*.go"))
- if err != nil {
- t.Fatal(err)
- }
- asms, err := filepath.Glob(filepath.Join(asmDir, "*.s"))
- if err != nil {
- t.Fatal(err)
- }
-
- t.Parallel()
- Vet(t, append(gos, asms...))
-}
-
-func TestVetDirs(t *testing.T) {
- t.Parallel()
- Build(t)
- for _, dir := range []string{
- "testingpkg",
- "divergent",
- "buildtag",
- "incomplete", // incomplete examples
- "cgo",
- } {
- dir := dir
- t.Run(dir, func(t *testing.T) {
- t.Parallel()
- gos, err := filepath.Glob(filepath.Join("testdata", dir, "*.go"))
- if err != nil {
- t.Fatal(err)
- }
- Vet(t, gos)
- })
- }
-}
-
-func errchk(c *exec.Cmd, files []string, t *testing.T) {
- output, err := c.CombinedOutput()
- if _, ok := err.(*exec.ExitError); !ok {
- t.Logf("vet output:\n%s", output)
- t.Fatal(err)
- }
- fullshort := make([]string, 0, len(files)*2)
- for _, f := range files {
- fullshort = append(fullshort, f, filepath.Base(f))
- }
- err = errorCheck(string(output), false, fullshort...)
- if err != nil {
- t.Errorf("error check failed: %s", err)
- }
-}
-
-// TestTags verifies that the -tags argument controls which files to check.
-func TestTags(t *testing.T) {
- t.Parallel()
- Build(t)
- for _, tag := range []string{"testtag", "x testtag y", "x,testtag,y"} {
- tag := tag
- t.Run(tag, func(t *testing.T) {
- t.Parallel()
- t.Logf("-tags=%s", tag)
- args := []string{
- "-tags=" + tag,
- "-v", // We're going to look at the files it examines.
- "testdata/tagtest",
- }
- cmd := exec.Command(binary, args...)
- output, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatal(err)
- }
- // file1 has testtag and file2 has !testtag.
- if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
- t.Error("file1 was excluded, should be included")
- }
- if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
- t.Error("file2 was included, should be excluded")
- }
- })
- }
-}
-
-// Issue #21188.
-func TestVetVerbose(t *testing.T) {
- t.Parallel()
- Build(t)
- cmd := exec.Command(binary, "-v", "-all", "testdata/cgo/cgo3.go")
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Logf("%s", out)
- t.Error(err)
- }
-}
-
-// All declarations below were adapted from test/run.go.
-
-// errorCheck matches errors in outStr against comments in source files.
-// For each line of the source files which should generate an error,
-// there should be a comment of the form // ERROR "regexp".
-// If outStr has an error for a line which has no such comment,
-// this function will report an error.
-// Likewise if outStr does not have an error for a line which has a comment,
-// or if the error message does not match the <regexp>.
-// The <regexp> syntax is Perl but its best to stick to egrep.
-//
-// Sources files are supplied as fullshort slice.
-// It consists of pairs: full path to source file and it's base name.
-func errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
- var errs []error
- out := splitOutput(outStr, wantAuto)
- // Cut directory name.
- for i := range out {
- for j := 0; j < len(fullshort); j += 2 {
- full, short := fullshort[j], fullshort[j+1]
- out[i] = strings.ReplaceAll(out[i], full, short)
- }
- }
-
- var want []wantedError
- for j := 0; j < len(fullshort); j += 2 {
- full, short := fullshort[j], fullshort[j+1]
- want = append(want, wantedErrors(full, short)...)
- }
- for _, we := range want {
- var errmsgs []string
- if we.auto {
- errmsgs, out = partitionStrings("<autogenerated>", out)
- } else {
- errmsgs, out = partitionStrings(we.prefix, out)
- }
- if len(errmsgs) == 0 {
- errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr))
- continue
- }
- matched := false
- n := len(out)
- for _, errmsg := range errmsgs {
- // Assume errmsg says "file:line: foo".
- // Cut leading "file:line: " to avoid accidental matching of file name instead of message.
- text := errmsg
- if i := strings.Index(text, " "); i >= 0 {
- text = text[i+1:]
- }
- if we.re.MatchString(text) {
- matched = true
- } else {
- out = append(out, errmsg)
- }
- }
- if !matched {
- errs = append(errs, fmt.Errorf("%s:%d: no match for %#q in:\n\t%s", we.file, we.lineNum, we.reStr, strings.Join(out[n:], "\n\t")))
- continue
- }
- }
-
- if len(out) > 0 {
- errs = append(errs, fmt.Errorf("Unmatched Errors:"))
- for _, errLine := range out {
- errs = append(errs, fmt.Errorf("%s", errLine))
- }
- }
-
- if len(errs) == 0 {
- return nil
- }
- if len(errs) == 1 {
- return errs[0]
- }
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "\n")
- for _, err := range errs {
- fmt.Fprintf(&buf, "%s\n", err.Error())
- }
- return errors.New(buf.String())
-}
-
-func splitOutput(out string, wantAuto bool) []string {
- // gc error messages continue onto additional lines with leading tabs.
- // Split the output at the beginning of each line that doesn't begin with a tab.
- // <autogenerated> lines are impossible to match so those are filtered out.
- var res []string
- for _, line := range strings.Split(out, "\n") {
- line = strings.TrimSuffix(line, "\r") // normalize Windows output
- if strings.HasPrefix(line, "\t") {
- res[len(res)-1] += "\n" + line
- } else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "#") || !wantAuto && strings.HasPrefix(line, "<autogenerated>") {
- continue
- } else if strings.TrimSpace(line) != "" {
- res = append(res, line)
- }
- }
- return res
-}
-
-// matchPrefix reports whether s starts with file name prefix followed by a :,
-// and possibly preceded by a directory name.
-func matchPrefix(s, prefix string) bool {
- i := strings.Index(s, ":")
- if i < 0 {
- return false
- }
- j := strings.LastIndex(s[:i], "/")
- s = s[j+1:]
- if len(s) <= len(prefix) || s[:len(prefix)] != prefix {
- return false
- }
- if s[len(prefix)] == ':' {
- return true
- }
- return false
-}
-
-func partitionStrings(prefix string, strs []string) (matched, unmatched []string) {
- for _, s := range strs {
- if matchPrefix(s, prefix) {
- matched = append(matched, s)
- } else {
- unmatched = append(unmatched, s)
- }
- }
- return
-}
-
-type wantedError struct {
- reStr string
- re *regexp.Regexp
- lineNum int
- auto bool // match <autogenerated> line
- file string
- prefix string
-}
-
-var (
- errRx = regexp.MustCompile(`// (?:GC_)?ERROR (.*)`)
- errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO (.*)`)
- errQuotesRx = regexp.MustCompile(`"([^"]*)"`)
- lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`)
-)
-
-// wantedErrors parses expected errors from comments in a file.
-func wantedErrors(file, short string) (errs []wantedError) {
- cache := make(map[string]*regexp.Regexp)
-
- src, err := ioutil.ReadFile(file)
- if err != nil {
- log.Fatal(err)
- }
- for i, line := range strings.Split(string(src), "\n") {
- lineNum := i + 1
- if strings.Contains(line, "////") {
- // double comment disables ERROR
- continue
- }
- var auto bool
- m := errAutoRx.FindStringSubmatch(line)
- if m != nil {
- auto = true
- } else {
- m = errRx.FindStringSubmatch(line)
- }
- if m == nil {
- continue
- }
- all := m[1]
- mm := errQuotesRx.FindAllStringSubmatch(all, -1)
- if mm == nil {
- log.Fatalf("%s:%d: invalid errchk line: %s", file, lineNum, line)
- }
- for _, m := range mm {
- replacedOnce := false
- rx := lineRx.ReplaceAllStringFunc(m[1], func(m string) string {
- if replacedOnce {
- return m
- }
- replacedOnce = true
- n := lineNum
- if strings.HasPrefix(m, "LINE+") {
- delta, _ := strconv.Atoi(m[5:])
- n += delta
- } else if strings.HasPrefix(m, "LINE-") {
- delta, _ := strconv.Atoi(m[5:])
- n -= delta
- }
- return fmt.Sprintf("%s:%d", short, n)
- })
- re := cache[rx]
- if re == nil {
- var err error
- re, err = regexp.Compile(rx)
- if err != nil {
- log.Fatalf("%s:%d: invalid regexp \"%#q\" in ERROR line: %v", file, lineNum, rx, err)
- }
- cache[rx] = re
- }
- prefix := fmt.Sprintf("%s:%d", short, lineNum)
- errs = append(errs, wantedError{
- reStr: rx,
- re: re,
- prefix: prefix,
- auto: auto,
- lineNum: lineNum,
- file: short,
- })
- }
- }
-
- return
-}