name := prefix + f.Name
flag.Var(f.Value, name, f.Usage)
- var isBool bool
- if b, ok := f.Value.(interface{ IsBoolFlag() bool }); ok {
- isBool = b.IsBoolFlag()
- }
+ isBool := isBoolFlag(f.Value)
analysisFlags = append(analysisFlags, analysisFlag{name, isBool, f.Usage})
})
}
printflags := flag.Bool("flags", false, "print analyzer flags in JSON")
addVersionFlag()
- // Add shims for legacy vet flags.
+ // Add shims for legacy vet flags to enable existing
+ // scripts that run vet to continue to work.
+ _ = flag.Bool("source", false, "no effect (deprecated)")
+ _ = flag.Bool("v", false, "no effect (deprecated)")
+ _ = flag.Bool("all", false, "no effect (deprecated)")
+ _ = flag.String("tags", "", "no effect (deprecated)")
+ for _, name := range []string{"source", "v", "all", "tags"} {
+ f := flag.Lookup(name)
+ isBool := isBoolFlag(f.Value)
+ analysisFlags = append(analysisFlags, analysisFlag{name, isBool, f.Usage})
+ }
for old, new := range vetLegacyFlags {
newFlag := flag.Lookup(new)
if newFlag != nil && flag.Lookup(old) == nil {
flag.Var(newFlag.Value, old, "deprecated alias for -"+new)
+ isBool := isBoolFlag(newFlag.Value)
+ analysisFlags = append(analysisFlags, analysisFlag{old, isBool, newFlag.Usage})
}
}
return true
}
+func isBoolFlag(v flag.Value) bool {
+ b, ok := v.(interface{ IsBoolFlag() bool })
+ return ok && b.IsBoolFlag()
+}
+
// Legacy flag support
// vetLegacyFlags maps flags used by legacy vet to their corresponding
--- /dev/null
+package analysisflags
+
+import "cmd/internal/objabi"
+
+// This additional file changes the behavior of the vendored code.
+
+func init() { addVersionFlag = objabi.AddVersionFlag }
+++ /dev/null
-// Copyright 2018 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.
-
-// The unitchecker package defines the main function for an analysis
-// driver that analyzes a single compilation unit during a build.
-// It is invoked by a build system such as "go vet":
-//
-// $ go vet -vettool=$(which vet)
-//
-// It supports the following command-line protocol:
-//
-// -V=full describe executable (to the build tool)
-// -flags describe flags (to the build tool)
-// foo.cfg description of compilation unit (from the build tool)
-//
-// This package does not depend on go/packages.
-// If you need a standalone tool, use multichecker,
-// which supports this mode but can also load packages
-// from source using go/packages.
-package unitchecker
-
-// TODO(adonovan):
-// - with gccgo, go build does not build standard library,
-// so we will not get to analyze it. Yet we must in order
-// to create base facts for, say, the fmt package for the
-// printf checker.
-// - support JSON output, factored with multichecker.
-
-import (
- "encoding/gob"
- "encoding/json"
- "fmt"
- "go/ast"
- "go/build"
- "go/importer"
- "go/parser"
- "go/token"
- "go/types"
- "io"
- "io/ioutil"
- "log"
- "os"
- "sort"
- "strings"
- "sync"
- "time"
-
- "golang.org/x/tools/go/analysis"
- "golang.org/x/tools/go/analysis/internal/facts"
-)
-
-// A Config describes a compilation unit to be analyzed.
-// It is provided to the tool in a JSON-encoded file
-// whose name ends with ".cfg".
-type Config struct {
- Compiler string
- Dir string
- ImportPath string
- GoFiles []string
- OtherFiles []string // TODO(adonovan): make go vet populate this (github.com/golang/go/issues/27665)
- ImportMap map[string]string
- PackageFile map[string]string
- Standard map[string]bool
- PackageVetx map[string]string
- VetxOnly bool
- VetxOutput string
- SucceedOnTypecheckFailure bool
-}
-
-// Main reads the *.cfg file, runs the analysis,
-// and calls os.Exit with an appropriate error code.
-func Main(configFile string, analyzers []*analysis.Analyzer) {
- cfg, err := readConfig(configFile)
- if err != nil {
- log.Fatal(err)
- }
-
- fset := token.NewFileSet()
- diags, err := run(fset, cfg, analyzers)
- if err != nil {
- log.Fatal(err)
- }
-
- if len(diags) > 0 {
- for _, diag := range diags {
- fmt.Fprintf(os.Stderr, "%s: %s\n", fset.Position(diag.Pos), diag.Message)
- }
- os.Exit(1)
- }
-
- os.Exit(0)
-}
-
-func readConfig(filename string) (*Config, error) {
- data, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- cfg := new(Config)
- if err := json.Unmarshal(data, cfg); err != nil {
- return nil, fmt.Errorf("cannot decode JSON config file %s: %v", filename, err)
- }
- if len(cfg.GoFiles) == 0 {
- // The go command disallows packages with no files.
- // The only exception is unsafe, but the go command
- // doesn't call vet on it.
- return nil, fmt.Errorf("package has no files: %s", cfg.ImportPath)
- }
- return cfg, nil
-}
-
-func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]analysis.Diagnostic, error) {
- // Load, parse, typecheck.
- var files []*ast.File
- for _, name := range cfg.GoFiles {
- f, err := parser.ParseFile(fset, name, nil, parser.ParseComments)
- if err != nil {
- if cfg.SucceedOnTypecheckFailure {
- // Silently succeed; let the compiler
- // report parse errors.
- err = nil
- }
- return nil, err
- }
- files = append(files, f)
- }
- compilerImporter := importer.For(cfg.Compiler, func(path string) (io.ReadCloser, error) {
- // path is a resolved package path, not an import path.
- file, ok := cfg.PackageFile[path]
- if !ok {
- if cfg.Compiler == "gccgo" && cfg.Standard[path] {
- return nil, nil // fall back to default gccgo lookup
- }
- return nil, fmt.Errorf("no package file for %q", path)
- }
- return os.Open(file)
- })
- importer := importerFunc(func(importPath string) (*types.Package, error) {
- path, ok := cfg.ImportMap[importPath] // resolve vendoring, etc
- if !ok {
- return nil, fmt.Errorf("can't resolve import %q", path)
- }
- return compilerImporter.Import(path)
- })
- tc := &types.Config{
- Importer: importer,
- Sizes: types.SizesFor("gc", build.Default.GOARCH), // assume gccgo ≡ gc?
- }
- info := &types.Info{
- Types: make(map[ast.Expr]types.TypeAndValue),
- Defs: make(map[*ast.Ident]types.Object),
- Uses: make(map[*ast.Ident]types.Object),
- Implicits: make(map[ast.Node]types.Object),
- Scopes: make(map[ast.Node]*types.Scope),
- Selections: make(map[*ast.SelectorExpr]*types.Selection),
- }
- pkg, err := tc.Check(cfg.ImportPath, fset, files, info)
- if err != nil {
- if cfg.SucceedOnTypecheckFailure {
- // Silently succeed; let the compiler
- // report type errors.
- err = nil
- }
- return nil, err
- }
-
- // Register fact types with gob.
- // In VetxOnly mode, analyzers are only for their facts,
- // so we can skip any analysis that neither produces facts
- // nor depends on any analysis that produces facts.
- // Also build a map to hold working state and result.
- type action struct {
- once sync.Once
- result interface{}
- err error
- usesFacts bool // (transitively uses)
- diagnostics []analysis.Diagnostic
- }
- actions := make(map[*analysis.Analyzer]*action)
- var registerFacts func(a *analysis.Analyzer) bool
- registerFacts = func(a *analysis.Analyzer) bool {
- act, ok := actions[a]
- if !ok {
- act = new(action)
- var usesFacts bool
- for _, f := range a.FactTypes {
- usesFacts = true
- gob.Register(f)
- }
- for _, req := range a.Requires {
- if registerFacts(req) {
- usesFacts = true
- }
- }
- act.usesFacts = usesFacts
- actions[a] = act
- }
- return act.usesFacts
- }
- var filtered []*analysis.Analyzer
- for _, a := range analyzers {
- if registerFacts(a) || !cfg.VetxOnly {
- filtered = append(filtered, a)
- }
- }
- analyzers = filtered
-
- // Read facts from imported packages.
- read := func(path string) ([]byte, error) {
- if vetx, ok := cfg.PackageVetx[path]; ok {
- return ioutil.ReadFile(vetx)
- }
- return nil, nil // no .vetx file, no facts
- }
- facts, err := facts.Decode(pkg, read)
- if err != nil {
- return nil, err
- }
-
- // In parallel, execute the DAG of analyzers.
- var exec func(a *analysis.Analyzer) *action
- var execAll func(analyzers []*analysis.Analyzer)
- exec = func(a *analysis.Analyzer) *action {
- act := actions[a]
- act.once.Do(func() {
- execAll(a.Requires) // prefetch dependencies in parallel
-
- // The inputs to this analysis are the
- // results of its prerequisites.
- inputs := make(map[*analysis.Analyzer]interface{})
- var failed []string
- for _, req := range a.Requires {
- reqact := exec(req)
- if reqact.err != nil {
- failed = append(failed, req.String())
- continue
- }
- inputs[req] = reqact.result
- }
-
- // Report an error if any dependency failed.
- if failed != nil {
- sort.Strings(failed)
- act.err = fmt.Errorf("failed prerequisites: %s", strings.Join(failed, ", "))
- return
- }
-
- pass := &analysis.Pass{
- Analyzer: a,
- Fset: fset,
- Files: files,
- OtherFiles: cfg.OtherFiles,
- Pkg: pkg,
- TypesInfo: info,
- ResultOf: inputs,
- Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
- ImportObjectFact: facts.ImportObjectFact,
- ExportObjectFact: facts.ExportObjectFact,
- ImportPackageFact: facts.ImportPackageFact,
- ExportPackageFact: facts.ExportPackageFact,
- }
-
- t0 := time.Now()
- act.result, act.err = a.Run(pass)
- if false {
- log.Printf("analysis %s = %s", pass, time.Since(t0))
- }
- })
- return act
- }
- execAll = func(analyzers []*analysis.Analyzer) {
- var wg sync.WaitGroup
- for _, a := range analyzers {
- wg.Add(1)
- go func(a *analysis.Analyzer) {
- _ = exec(a)
- wg.Done()
- }(a)
- }
- wg.Wait()
- }
-
- execAll(analyzers)
-
- // Return diagnostics from root analyzers.
- var diags []analysis.Diagnostic
- for _, a := range analyzers {
- act := actions[a]
- if act.err != nil {
- return nil, act.err // some analysis failed
- }
- diags = append(diags, act.diagnostics...)
- }
-
- data := facts.Encode()
- if err := ioutil.WriteFile(cfg.VetxOutput, data, 0666); err != nil {
- return nil, fmt.Errorf("failed to write analysis facts: %v", err)
- }
-
- return diags, nil
-}
-
-type importerFunc func(path string) (*types.Package, error)
-
-func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }
+++ /dev/null
-// 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.
-
-// Identify mismatches between assembly files and Go func declarations.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/build"
- "go/token"
- "go/types"
- "regexp"
- "strconv"
- "strings"
-)
-
-// 'kind' is a kind of assembly variable.
-// The kinds 1, 2, 4, 8 stand for values of that size.
-type asmKind int
-
-// These special kinds are not valid sizes.
-const (
- asmString asmKind = 100 + iota
- asmSlice
- asmArray
- asmInterface
- asmEmptyInterface
- asmStruct
- asmComplex
-)
-
-// An asmArch describes assembly parameters for an architecture
-type asmArch struct {
- name string
- bigEndian bool
- stack string
- lr bool
- // calculated during initialization
- sizes types.Sizes
- intSize int
- ptrSize int
- maxAlign int
-}
-
-// An asmFunc describes the expected variables for a function on a given architecture.
-type asmFunc struct {
- arch *asmArch
- size int // size of all arguments
- vars map[string]*asmVar
- varByOffset map[int]*asmVar
-}
-
-// An asmVar describes a single assembly variable.
-type asmVar struct {
- name string
- kind asmKind
- typ string
- off int
- size int
- inner []*asmVar
-}
-
-var (
- asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false}
- asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true}
- asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true}
- asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false}
- asmArchAmd64p32 = asmArch{name: "amd64p32", bigEndian: false, stack: "SP", lr: false}
- asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true}
- asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true}
- asmArchMips64 = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true}
- asmArchMips64LE = asmArch{name: "mips64le", bigEndian: false, stack: "R29", lr: true}
- asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true}
- asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true}
- asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true}
- asmArchWasm = asmArch{name: "wasm", bigEndian: false, stack: "SP", lr: false}
-
- arches = []*asmArch{
- &asmArch386,
- &asmArchArm,
- &asmArchArm64,
- &asmArchAmd64,
- &asmArchAmd64p32,
- &asmArchMips,
- &asmArchMipsLE,
- &asmArchMips64,
- &asmArchMips64LE,
- &asmArchPpc64,
- &asmArchPpc64LE,
- &asmArchS390X,
- &asmArchWasm,
- }
-)
-
-func init() {
- for _, arch := range arches {
- arch.sizes = types.SizesFor("gc", arch.name)
- if arch.sizes == nil {
- panic("missing SizesFor for gc/" + arch.name)
- }
- arch.intSize = int(arch.sizes.Sizeof(types.Typ[types.Int]))
- arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer]))
- arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64]))
- }
-
- registerPkgCheck("asmdecl", asmCheck)
-}
-
-var (
- re = regexp.MustCompile
- asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
- asmTEXT = re(`\bTEXT\b(.*)·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+()]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
- asmDATA = re(`\b(DATA|GLOBL)\b`)
- asmNamedFP = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
- asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`)
- asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
- asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
- ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`)
-)
-
-func asmCheck(pkg *Package) {
- if vcfg.VetxOnly {
- return
- }
-
- // No work if no assembly files.
- if !pkg.hasFileWithSuffix(".s") {
- return
- }
-
- // Gather declarations. knownFunc[name][arch] is func description.
- knownFunc := make(map[string]map[string]*asmFunc)
-
- for _, f := range pkg.files {
- if f.file != nil {
- for _, decl := range f.file.Decls {
- if decl, ok := decl.(*ast.FuncDecl); ok && decl.Body == nil {
- knownFunc[decl.Name.Name] = f.asmParseDecl(decl)
- }
- }
- }
- }
-
-Files:
- for _, f := range pkg.files {
- if !strings.HasSuffix(f.name, ".s") {
- continue
- }
- Println("Checking file", f.name)
-
- // Determine architecture from file name if possible.
- var arch string
- var archDef *asmArch
- for _, a := range arches {
- if strings.HasSuffix(f.name, "_"+a.name+".s") {
- arch = a.name
- archDef = a
- break
- }
- }
-
- lines := strings.SplitAfter(string(f.content), "\n")
- var (
- fn *asmFunc
- fnName string
- localSize, argSize int
- wroteSP bool
- haveRetArg bool
- retLine []int
- )
-
- flushRet := func() {
- if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
- v := fn.vars["ret"]
- for _, line := range retLine {
- f.Badf(token.NoPos, "%s:%d: [%s] %s: RET without writing to %d-byte ret+%d(FP)", f.name, line, arch, fnName, v.size, v.off)
- }
- }
- retLine = nil
- }
- for lineno, line := range lines {
- lineno++
-
- badf := func(format string, args ...interface{}) {
- f.Badf(token.NoPos, "%s:%d: [%s] %s: %s", f.name, lineno, arch, fnName, fmt.Sprintf(format, args...))
- }
-
- if arch == "" {
- // Determine architecture from +build line if possible.
- if m := asmPlusBuild.FindStringSubmatch(line); m != nil {
- // There can be multiple architectures in a single +build line,
- // so accumulate them all and then prefer the one that
- // matches build.Default.GOARCH.
- var archCandidates []*asmArch
- for _, fld := range strings.Fields(m[1]) {
- for _, a := range arches {
- if a.name == fld {
- archCandidates = append(archCandidates, a)
- }
- }
- }
- for _, a := range archCandidates {
- if a.name == build.Default.GOARCH {
- archCandidates = []*asmArch{a}
- break
- }
- }
- if len(archCandidates) > 0 {
- arch = archCandidates[0].name
- archDef = archCandidates[0]
- }
- }
- }
-
- if m := asmTEXT.FindStringSubmatch(line); m != nil {
- flushRet()
- if arch == "" {
- // Arch not specified by filename or build tags.
- // Fall back to build.Default.GOARCH.
- for _, a := range arches {
- if a.name == build.Default.GOARCH {
- arch = a.name
- archDef = a
- break
- }
- }
- if arch == "" {
- f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
- continue Files
- }
- }
- fnName = m[2]
- if pkgName := strings.TrimSpace(m[1]); pkgName != "" {
- pathParts := strings.Split(pkgName, "∕")
- pkgName = pathParts[len(pathParts)-1]
- if pkgName != f.pkg.path {
- f.Warnf(token.NoPos, "%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", f.name, lineno, arch, fnName, pkgName)
- fn = nil
- fnName = ""
- continue
- }
- }
- flag := m[3]
- fn = knownFunc[fnName][arch]
- if fn != nil {
- size, _ := strconv.Atoi(m[5])
- if size != fn.size && (flag != "7" && !strings.Contains(flag, "NOSPLIT") || size != 0) {
- badf("wrong argument size %d; expected $...-%d", size, fn.size)
- }
- }
- localSize, _ = strconv.Atoi(m[4])
- localSize += archDef.intSize
- if archDef.lr && !strings.Contains(flag, "NOFRAME") {
- // Account for caller's saved LR
- localSize += archDef.intSize
- }
- argSize, _ = strconv.Atoi(m[5])
- if fn == nil && !strings.Contains(fnName, "<>") {
- badf("function %s missing Go declaration", fnName)
- }
- wroteSP = false
- haveRetArg = false
- continue
- } else if strings.Contains(line, "TEXT") && strings.Contains(line, "SB") {
- // function, but not visible from Go (didn't match asmTEXT), so stop checking
- flushRet()
- fn = nil
- fnName = ""
- continue
- }
-
- if strings.Contains(line, "RET") {
- retLine = append(retLine, lineno)
- }
-
- if fnName == "" {
- continue
- }
-
- if asmDATA.FindStringSubmatch(line) != nil {
- fn = nil
- }
-
- if archDef == nil {
- continue
- }
-
- if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) {
- wroteSP = true
- continue
- }
-
- for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
- if m[3] != archDef.stack || wroteSP {
- continue
- }
- off := 0
- if m[1] != "" {
- off, _ = strconv.Atoi(m[2])
- }
- if off >= localSize {
- if fn != nil {
- v := fn.varByOffset[off-localSize]
- if v != nil {
- badf("%s should be %s+%d(FP)", m[1], v.name, off-localSize)
- continue
- }
- }
- if off >= localSize+argSize {
- badf("use of %s points beyond argument frame", m[1])
- continue
- }
- badf("use of %s to access argument frame", m[1])
- }
- }
-
- if fn == nil {
- continue
- }
-
- for _, m := range asmUnnamedFP.FindAllStringSubmatch(line, -1) {
- off, _ := strconv.Atoi(m[2])
- v := fn.varByOffset[off]
- if v != nil {
- badf("use of unnamed argument %s; offset %d is %s+%d(FP)", m[1], off, v.name, v.off)
- } else {
- badf("use of unnamed argument %s", m[1])
- }
- }
-
- for _, m := range asmNamedFP.FindAllStringSubmatch(line, -1) {
- name := m[1]
- off := 0
- if m[2] != "" {
- off, _ = strconv.Atoi(m[2])
- }
- if name == "ret" || strings.HasPrefix(name, "ret_") {
- haveRetArg = true
- }
- v := fn.vars[name]
- if v == nil {
- // Allow argframe+0(FP).
- if name == "argframe" && off == 0 {
- continue
- }
- v = fn.varByOffset[off]
- if v != nil {
- badf("unknown variable %s; offset %d is %s+%d(FP)", name, off, v.name, v.off)
- } else {
- badf("unknown variable %s", name)
- }
- continue
- }
- asmCheckVar(badf, fn, line, m[0], off, v)
- }
- }
- flushRet()
- }
-}
-
-func asmKindForType(t types.Type, size int) asmKind {
- switch t := t.Underlying().(type) {
- case *types.Basic:
- switch t.Kind() {
- case types.String:
- return asmString
- case types.Complex64, types.Complex128:
- return asmComplex
- }
- return asmKind(size)
- case *types.Pointer, *types.Chan, *types.Map, *types.Signature:
- return asmKind(size)
- case *types.Struct:
- return asmStruct
- case *types.Interface:
- if t.Empty() {
- return asmEmptyInterface
- }
- return asmInterface
- case *types.Array:
- return asmArray
- case *types.Slice:
- return asmSlice
- }
- panic("unreachable")
-}
-
-// A component is an assembly-addressable component of a composite type,
-// or a composite type itself.
-type component struct {
- size int
- offset int
- kind asmKind
- typ string
- suffix string // Such as _base for string base, _0_lo for lo half of first element of [1]uint64 on 32 bit machine.
- outer string // The suffix for immediately containing composite type.
-}
-
-func newComponent(suffix string, kind asmKind, typ string, offset, size int, outer string) component {
- return component{suffix: suffix, kind: kind, typ: typ, offset: offset, size: size, outer: outer}
-}
-
-// componentsOfType generates a list of components of type t.
-// For example, given string, the components are the string itself, the base, and the length.
-func componentsOfType(arch *asmArch, t types.Type) []component {
- return appendComponentsRecursive(arch, t, nil, "", 0)
-}
-
-// appendComponentsRecursive implements componentsOfType.
-// Recursion is required to correct handle structs and arrays,
-// which can contain arbitrary other types.
-func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suffix string, off int) []component {
- s := t.String()
- size := int(arch.sizes.Sizeof(t))
- kind := asmKindForType(t, size)
- cc = append(cc, newComponent(suffix, kind, s, off, size, suffix))
-
- switch kind {
- case 8:
- if arch.ptrSize == 4 {
- w1, w2 := "lo", "hi"
- if arch.bigEndian {
- w1, w2 = w2, w1
- }
- cc = append(cc, newComponent(suffix+"_"+w1, 4, "half "+s, off, 4, suffix))
- cc = append(cc, newComponent(suffix+"_"+w2, 4, "half "+s, off+4, 4, suffix))
- }
-
- case asmEmptyInterface:
- cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize), "interface type", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
-
- case asmInterface:
- cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize), "interface itable", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
-
- case asmSlice:
- cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "slice base", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "slice len", off+arch.ptrSize, arch.intSize, suffix))
- cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize), "slice cap", off+arch.ptrSize+arch.intSize, arch.intSize, suffix))
-
- case asmString:
- cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "string base", off, arch.ptrSize, suffix))
- cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "string len", off+arch.ptrSize, arch.intSize, suffix))
-
- case asmComplex:
- fsize := size / 2
- cc = append(cc, newComponent(suffix+"_real", asmKind(fsize), fmt.Sprintf("real(complex%d)", size*8), off, fsize, suffix))
- cc = append(cc, newComponent(suffix+"_imag", asmKind(fsize), fmt.Sprintf("imag(complex%d)", size*8), off+fsize, fsize, suffix))
-
- case asmStruct:
- tu := t.Underlying().(*types.Struct)
- fields := make([]*types.Var, tu.NumFields())
- for i := 0; i < tu.NumFields(); i++ {
- fields[i] = tu.Field(i)
- }
- offsets := arch.sizes.Offsetsof(fields)
- for i, f := range fields {
- cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i]))
- }
-
- case asmArray:
- tu := t.Underlying().(*types.Array)
- elem := tu.Elem()
- // Calculate offset of each element array.
- fields := []*types.Var{
- types.NewVar(token.NoPos, nil, "fake0", elem),
- types.NewVar(token.NoPos, nil, "fake1", elem),
- }
- offsets := arch.sizes.Offsetsof(fields)
- elemoff := int(offsets[1])
- for i := 0; i < int(tu.Len()); i++ {
- cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff)
- }
- }
-
- return cc
-}
-
-// asmParseDecl parses a function decl for expected assembly variables.
-func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
- var (
- arch *asmArch
- fn *asmFunc
- offset int
- )
-
- // addParams adds asmVars for each of the parameters in list.
- // isret indicates whether the list are the arguments or the return values.
- addParams := func(list []*ast.Field, isret bool) {
- argnum := 0
- for _, fld := range list {
- t := f.pkg.types[fld.Type].Type
- align := int(arch.sizes.Alignof(t))
- size := int(arch.sizes.Sizeof(t))
- offset += -offset & (align - 1)
- cc := componentsOfType(arch, t)
-
- // names is the list of names with this type.
- names := fld.Names
- if len(names) == 0 {
- // Anonymous args will be called arg, arg1, arg2, ...
- // Similarly so for return values: ret, ret1, ret2, ...
- name := "arg"
- if isret {
- name = "ret"
- }
- if argnum > 0 {
- name += strconv.Itoa(argnum)
- }
- names = []*ast.Ident{ast.NewIdent(name)}
- }
- argnum += len(names)
-
- // Create variable for each name.
- for _, id := range names {
- name := id.Name
- for _, c := range cc {
- outer := name + c.outer
- v := asmVar{
- name: name + c.suffix,
- kind: c.kind,
- typ: c.typ,
- off: offset + c.offset,
- size: c.size,
- }
- if vo := fn.vars[outer]; vo != nil {
- vo.inner = append(vo.inner, &v)
- }
- fn.vars[v.name] = &v
- for i := 0; i < v.size; i++ {
- fn.varByOffset[v.off+i] = &v
- }
- }
- offset += size
- }
- }
- }
-
- m := make(map[string]*asmFunc)
- for _, arch = range arches {
- fn = &asmFunc{
- arch: arch,
- vars: make(map[string]*asmVar),
- varByOffset: make(map[int]*asmVar),
- }
- offset = 0
- addParams(decl.Type.Params.List, false)
- if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
- offset += -offset & (arch.maxAlign - 1)
- addParams(decl.Type.Results.List, true)
- }
- fn.size = offset
- m[arch.name] = fn
- }
-
- return m
-}
-
-// asmCheckVar checks a single variable reference.
-func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) {
- m := asmOpcode.FindStringSubmatch(line)
- if m == nil {
- if !strings.HasPrefix(strings.TrimSpace(line), "//") {
- badf("cannot find assembly opcode")
- }
- return
- }
-
- // Determine operand sizes from instruction.
- // Typically the suffix suffices, but there are exceptions.
- var src, dst, kind asmKind
- op := m[1]
- switch fn.arch.name + "." + op {
- case "386.FMOVLP":
- src, dst = 8, 4
- case "arm.MOVD":
- src = 8
- case "arm.MOVW":
- src = 4
- case "arm.MOVH", "arm.MOVHU":
- src = 2
- case "arm.MOVB", "arm.MOVBU":
- src = 1
- // LEA* opcodes don't really read the second arg.
- // They just take the address of it.
- case "386.LEAL":
- dst = 4
- case "amd64.LEAQ":
- dst = 8
- case "amd64p32.LEAL":
- dst = 4
- default:
- switch fn.arch.name {
- case "386", "amd64":
- if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "D") || strings.HasSuffix(op, "DP")) {
- // FMOVDP, FXCHD, etc
- src = 8
- break
- }
- if strings.HasPrefix(op, "P") && strings.HasSuffix(op, "RD") {
- // PINSRD, PEXTRD, etc
- src = 4
- break
- }
- if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
- // FMOVFP, FXCHF, etc
- src = 4
- break
- }
- if strings.HasSuffix(op, "SD") {
- // MOVSD, SQRTSD, etc
- src = 8
- break
- }
- if strings.HasSuffix(op, "SS") {
- // MOVSS, SQRTSS, etc
- src = 4
- break
- }
- if strings.HasPrefix(op, "SET") {
- // SETEQ, etc
- src = 1
- break
- }
- switch op[len(op)-1] {
- case 'B':
- src = 1
- case 'W':
- src = 2
- case 'L':
- src = 4
- case 'D', 'Q':
- src = 8
- }
- case "ppc64", "ppc64le":
- // Strip standard suffixes to reveal size letter.
- m := ppc64Suff.FindStringSubmatch(op)
- if m != nil {
- switch m[1][0] {
- case 'B':
- src = 1
- case 'H':
- src = 2
- case 'W':
- src = 4
- case 'D':
- src = 8
- }
- }
- case "mips", "mipsle", "mips64", "mips64le":
- switch op {
- case "MOVB", "MOVBU":
- src = 1
- case "MOVH", "MOVHU":
- src = 2
- case "MOVW", "MOVWU", "MOVF":
- src = 4
- case "MOVV", "MOVD":
- src = 8
- }
- case "s390x":
- switch op {
- case "MOVB", "MOVBZ":
- src = 1
- case "MOVH", "MOVHZ":
- src = 2
- case "MOVW", "MOVWZ", "FMOVS":
- src = 4
- case "MOVD", "FMOVD":
- src = 8
- }
- }
- }
- if dst == 0 {
- dst = src
- }
-
- // Determine whether the match we're holding
- // is the first or second argument.
- if strings.Index(line, expr) > strings.Index(line, ",") {
- kind = dst
- } else {
- kind = src
- }
-
- vk := v.kind
- vs := v.size
- vt := v.typ
- switch vk {
- case asmInterface, asmEmptyInterface, asmString, asmSlice:
- // allow reference to first word (pointer)
- vk = v.inner[0].kind
- vs = v.inner[0].size
- vt = v.inner[0].typ
- }
-
- if off != v.off {
- var inner bytes.Buffer
- for i, vi := range v.inner {
- if len(v.inner) > 1 {
- fmt.Fprintf(&inner, ",")
- }
- fmt.Fprintf(&inner, " ")
- if i == len(v.inner)-1 {
- fmt.Fprintf(&inner, "or ")
- }
- fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
- }
- badf("invalid offset %s; expected %s+%d(FP)%s", expr, v.name, v.off, inner.String())
- return
- }
- if kind != 0 && kind != vk {
- var inner bytes.Buffer
- if len(v.inner) > 0 {
- fmt.Fprintf(&inner, " containing")
- for i, vi := range v.inner {
- if i > 0 && len(v.inner) > 2 {
- fmt.Fprintf(&inner, ",")
- }
- fmt.Fprintf(&inner, " ")
- if i > 0 && i == len(v.inner)-1 {
- fmt.Fprintf(&inner, "and ")
- }
- fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
- }
- }
- badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vs, inner.String())
- }
-}
+++ /dev/null
-// 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.
-
-/*
-This file contains the code to check for useless assignments.
-*/
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "reflect"
-)
-
-func init() {
- register("assign",
- "check for useless assignments",
- checkAssignStmt,
- assignStmt)
-}
-
-// TODO: should also check for assignments to struct fields inside methods
-// that are on T instead of *T.
-
-// checkAssignStmt checks for assignments of the form "<expr> = <expr>".
-// These are almost always useless, and even when they aren't they are usually a mistake.
-func checkAssignStmt(f *File, node ast.Node) {
- stmt := node.(*ast.AssignStmt)
- if stmt.Tok != token.ASSIGN {
- return // ignore :=
- }
- if len(stmt.Lhs) != len(stmt.Rhs) {
- // If LHS and RHS have different cardinality, they can't be the same.
- return
- }
- for i, lhs := range stmt.Lhs {
- rhs := stmt.Rhs[i]
- if hasSideEffects(f, lhs) || hasSideEffects(f, rhs) {
- continue // expressions may not be equal
- }
- if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
- continue // short-circuit the heavy-weight gofmt check
- }
- le := f.gofmt(lhs)
- re := f.gofmt(rhs)
- if le == re {
- f.Badf(stmt.Pos(), "self-assignment of %s to %s", re, le)
- }
- }
-}
+++ /dev/null
-// 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
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("atomic",
- "check for common mistaken usages of the sync/atomic package",
- checkAtomicAssignment,
- assignStmt)
-}
-
-// checkAtomicAssignment walks the assignment statement checking for common
-// mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1)
-func checkAtomicAssignment(f *File, node ast.Node) {
- n := node.(*ast.AssignStmt)
- if len(n.Lhs) != len(n.Rhs) {
- return
- }
- if len(n.Lhs) == 1 && n.Tok == token.DEFINE {
- return
- }
-
- for i, right := range n.Rhs {
- call, ok := right.(*ast.CallExpr)
- if !ok {
- continue
- }
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- continue
- }
- pkgIdent, _ := sel.X.(*ast.Ident)
- pkgName, ok := f.pkg.uses[pkgIdent].(*types.PkgName)
- if !ok || pkgName.Imported().Path() != "sync/atomic" {
- continue
- }
-
- switch sel.Sel.Name {
- case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
- f.checkAtomicAddAssignment(n.Lhs[i], call)
- }
- }
-}
-
-// checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value
-// to the same variable being used in the operation
-func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) {
- if len(call.Args) != 2 {
- return
- }
- arg := call.Args[0]
- broken := false
-
- if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
- broken = f.gofmt(left) == f.gofmt(uarg.X)
- } else if star, ok := left.(*ast.StarExpr); ok {
- broken = f.gofmt(star.X) == f.gofmt(arg)
- }
-
- if broken {
- f.Bad(left.Pos(), "direct assignment to atomic value")
- }
-}
+++ /dev/null
-// Copyright 2014 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.
-
-// This file contains boolean condition tests.
-
-package main
-
-import (
- "go/ast"
- "go/token"
-)
-
-func init() {
- register("bool",
- "check for mistakes involving boolean operators",
- checkBool,
- binaryExpr)
-}
-
-func checkBool(f *File, n ast.Node) {
- e := n.(*ast.BinaryExpr)
-
- var op boolOp
- switch e.Op {
- case token.LOR:
- op = or
- case token.LAND:
- op = and
- default:
- return
- }
-
- comm := op.commutativeSets(f, e)
- for _, exprs := range comm {
- op.checkRedundant(f, exprs)
- op.checkSuspect(f, exprs)
- }
-}
-
-type boolOp struct {
- name string
- tok token.Token // token corresponding to this operator
- badEq token.Token // token corresponding to the equality test that should not be used with this operator
-}
-
-var (
- or = boolOp{"or", token.LOR, token.NEQ}
- and = boolOp{"and", token.LAND, token.EQL}
-)
-
-// commutativeSets returns all side effect free sets of
-// expressions in e that are connected by op.
-// For example, given 'a || b || f() || c || d' with the or op,
-// commutativeSets returns {{b, a}, {d, c}}.
-func (op boolOp) commutativeSets(f *File, e *ast.BinaryExpr) [][]ast.Expr {
- exprs := op.split(e)
-
- // Partition the slice of expressions into commutative sets.
- i := 0
- var sets [][]ast.Expr
- for j := 0; j <= len(exprs); j++ {
- if j == len(exprs) || hasSideEffects(f, exprs[j]) {
- if i < j {
- sets = append(sets, exprs[i:j])
- }
- i = j + 1
- }
- }
-
- return sets
-}
-
-// checkRedundant checks for expressions of the form
-// e && e
-// e || e
-// Exprs must contain only side effect free expressions.
-func (op boolOp) checkRedundant(f *File, exprs []ast.Expr) {
- seen := make(map[string]bool)
- for _, e := range exprs {
- efmt := f.gofmt(e)
- if seen[efmt] {
- f.Badf(e.Pos(), "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
- } else {
- seen[efmt] = true
- }
- }
-}
-
-// checkSuspect checks for expressions of the form
-// x != c1 || x != c2
-// x == c1 && x == c2
-// where c1 and c2 are constant expressions.
-// If c1 and c2 are the same then it's redundant;
-// if c1 and c2 are different then it's always true or always false.
-// Exprs must contain only side effect free expressions.
-func (op boolOp) checkSuspect(f *File, exprs []ast.Expr) {
- // seen maps from expressions 'x' to equality expressions 'x != c'.
- seen := make(map[string]string)
-
- for _, e := range exprs {
- bin, ok := e.(*ast.BinaryExpr)
- if !ok || bin.Op != op.badEq {
- continue
- }
-
- // In order to avoid false positives, restrict to cases
- // in which one of the operands is constant. We're then
- // interested in the other operand.
- // In the rare case in which both operands are constant
- // (e.g. runtime.GOOS and "windows"), we'll only catch
- // mistakes if the LHS is repeated, which is how most
- // code is written.
- var x ast.Expr
- switch {
- case f.pkg.types[bin.Y].Value != nil:
- x = bin.X
- case f.pkg.types[bin.X].Value != nil:
- x = bin.Y
- default:
- continue
- }
-
- // e is of the form 'x != c' or 'x == c'.
- xfmt := f.gofmt(x)
- efmt := f.gofmt(e)
- if prev, found := seen[xfmt]; found {
- // checkRedundant handles the case in which efmt == prev.
- if efmt != prev {
- f.Badf(e.Pos(), "suspect %s: %s %s %s", op.name, efmt, op.tok, prev)
- }
- } else {
- seen[xfmt] = efmt
- }
- }
-}
-
-// hasSideEffects reports whether evaluation of e has side effects.
-func hasSideEffects(f *File, e ast.Expr) bool {
- safe := true
- ast.Inspect(e, func(node ast.Node) bool {
- switch n := node.(type) {
- case *ast.CallExpr:
- typVal := f.pkg.types[n.Fun]
- switch {
- case typVal.IsType():
- // Type conversion, which is safe.
- case typVal.IsBuiltin():
- // Builtin func, conservatively assumed to not
- // be safe for now.
- safe = false
- return false
- default:
- // A non-builtin func or method call.
- // Conservatively assume that all of them have
- // side effects for now.
- safe = false
- return false
- }
- case *ast.UnaryExpr:
- if n.Op == token.ARROW {
- safe = false
- return false
- }
- }
- return true
- })
- return !safe
-}
-
-// split returns a slice of all subexpressions in e that are connected by op.
-// For example, given 'a || (b || c) || d' with the or op,
-// split returns []{d, c, b, a}.
-func (op boolOp) split(e ast.Expr) (exprs []ast.Expr) {
- for {
- e = unparen(e)
- if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
- exprs = append(exprs, op.split(b.Y)...)
- e = b.X
- } else {
- exprs = append(exprs, e)
- break
- }
- }
- return
-}
-
-// unparen returns e with any enclosing parentheses stripped.
-func unparen(e ast.Expr) ast.Expr {
- for {
- p, ok := e.(*ast.ParenExpr)
- if !ok {
- return e
- }
- e = p.X
- }
-}
+++ /dev/null
-// 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
-
-import (
- "bytes"
- "fmt"
- "os"
- "strings"
- "unicode"
-)
-
-var (
- nl = []byte("\n")
- slashSlash = []byte("//")
- plusBuild = []byte("+build")
-)
-
-func badfLine(f *File, line int, format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args...)
- fmt.Fprintf(os.Stderr, "%s:%d: %s\n", f.name, line, msg)
- setExit(1)
-}
-
-// checkBuildTag checks that build tags are in the correct location and well-formed.
-func checkBuildTag(f *File) {
- if !vet("buildtags") {
- return
- }
-
- // we must look at the raw lines, as build tags may appear in non-Go
- // files such as assembly files.
- lines := bytes.SplitAfter(f.content, nl)
-
- // lineWithComment reports whether a line corresponds to a comment in
- // the source file. If the source file wasn't Go, the function always
- // returns true.
- lineWithComment := func(line int) bool {
- if f.file == nil {
- // Current source file is not Go, so be conservative.
- return true
- }
- for _, group := range f.file.Comments {
- startLine := f.fset.Position(group.Pos()).Line
- endLine := f.fset.Position(group.End()).Line
- if startLine <= line && line <= endLine {
- return true
- }
- }
- return false
- }
-
- // Determine cutpoint where +build comments are no longer valid.
- // They are valid in leading // comments in the file followed by
- // a blank line.
- var cutoff int
- for i, line := range lines {
- line = bytes.TrimSpace(line)
- if len(line) == 0 {
- cutoff = i
- continue
- }
- if bytes.HasPrefix(line, slashSlash) {
- continue
- }
- break
- }
-
- for i, line := range lines {
- line = bytes.TrimSpace(line)
- if !bytes.HasPrefix(line, slashSlash) {
- continue
- }
- if !bytes.Contains(line, plusBuild) {
- // Check that the comment contains "+build" early, to
- // avoid unnecessary lineWithComment calls that may
- // incur linear searches.
- continue
- }
- if !lineWithComment(i + 1) {
- // This is a line in a Go source file that looks like a
- // comment, but actually isn't - such as part of a raw
- // string.
- continue
- }
-
- text := bytes.TrimSpace(line[2:])
- if bytes.HasPrefix(text, plusBuild) {
- fields := bytes.Fields(text)
- if !bytes.Equal(fields[0], plusBuild) {
- // Comment is something like +buildasdf not +build.
- badfLine(f, i+1, "possible malformed +build comment")
- continue
- }
- if i >= cutoff {
- badfLine(f, i+1, "+build comment must appear before package clause and be followed by a blank line")
- continue
- }
- // Check arguments.
- Args:
- for _, arg := range fields[1:] {
- for _, elem := range strings.Split(string(arg), ",") {
- if strings.HasPrefix(elem, "!!") {
- badfLine(f, i+1, "invalid double negative in build constraint: %s", arg)
- break Args
- }
- elem = strings.TrimPrefix(elem, "!")
- for _, c := range elem {
- if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
- badfLine(f, i+1, "invalid non-alphanumeric build constraint: %s", arg)
- break Args
- }
- }
- }
- }
- continue
- }
- // Comment with +build but not at beginning.
- if i < cutoff {
- badfLine(f, i+1, "possible malformed +build comment")
- continue
- }
- }
-}
+++ /dev/null
-// 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.
-
-// Check for invalid cgo pointer passing.
-// This looks for code that uses cgo to call C code passing values
-// whose types are almost always invalid according to the cgo pointer
-// sharing rules.
-// Specifically, it warns about attempts to pass a Go chan, map, func,
-// or slice to C, either directly, or via a pointer, array, or struct.
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("cgocall",
- "check for types that may not be passed to cgo calls",
- checkCgoCall,
- callExpr)
-}
-
-func checkCgoCall(f *File, node ast.Node) {
- x := node.(*ast.CallExpr)
-
- // We are only looking for calls to functions imported from
- // the "C" package.
- sel, ok := x.Fun.(*ast.SelectorExpr)
- if !ok {
- return
- }
- id, ok := sel.X.(*ast.Ident)
- if !ok {
- return
- }
-
- pkgname, ok := f.pkg.uses[id].(*types.PkgName)
- if !ok || pkgname.Imported().Path() != "C" {
- return
- }
-
- // A call to C.CBytes passes a pointer but is always safe.
- if sel.Sel.Name == "CBytes" {
- return
- }
-
- for _, arg := range x.Args {
- if !typeOKForCgoCall(cgoBaseType(f, arg), make(map[types.Type]bool)) {
- f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
- }
-
- // Check for passing the address of a bad type.
- if conv, ok := arg.(*ast.CallExpr); ok && len(conv.Args) == 1 && f.hasBasicType(conv.Fun, types.UnsafePointer) {
- arg = conv.Args[0]
- }
- if u, ok := arg.(*ast.UnaryExpr); ok && u.Op == token.AND {
- if !typeOKForCgoCall(cgoBaseType(f, u.X), make(map[types.Type]bool)) {
- f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
- }
- }
- }
-}
-
-// cgoBaseType tries to look through type conversions involving
-// unsafe.Pointer to find the real type. It converts:
-// unsafe.Pointer(x) => x
-// *(*unsafe.Pointer)(unsafe.Pointer(&x)) => x
-func cgoBaseType(f *File, arg ast.Expr) types.Type {
- switch arg := arg.(type) {
- case *ast.CallExpr:
- if len(arg.Args) == 1 && f.hasBasicType(arg.Fun, types.UnsafePointer) {
- return cgoBaseType(f, arg.Args[0])
- }
- case *ast.StarExpr:
- call, ok := arg.X.(*ast.CallExpr)
- if !ok || len(call.Args) != 1 {
- break
- }
- // Here arg is *f(v).
- t := f.pkg.types[call.Fun].Type
- if t == nil {
- break
- }
- ptr, ok := t.Underlying().(*types.Pointer)
- if !ok {
- break
- }
- // Here arg is *(*p)(v)
- elem, ok := ptr.Elem().Underlying().(*types.Basic)
- if !ok || elem.Kind() != types.UnsafePointer {
- break
- }
- // Here arg is *(*unsafe.Pointer)(v)
- call, ok = call.Args[0].(*ast.CallExpr)
- if !ok || len(call.Args) != 1 {
- break
- }
- // Here arg is *(*unsafe.Pointer)(f(v))
- if !f.hasBasicType(call.Fun, types.UnsafePointer) {
- break
- }
- // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(v))
- u, ok := call.Args[0].(*ast.UnaryExpr)
- if !ok || u.Op != token.AND {
- break
- }
- // Here arg is *(*unsafe.Pointer)(unsafe.Pointer(&v))
- return cgoBaseType(f, u.X)
- }
-
- return f.pkg.types[arg].Type
-}
-
-// typeOKForCgoCall reports whether the type of arg is OK to pass to a
-// C function using cgo. This is not true for Go types with embedded
-// pointers. m is used to avoid infinite recursion on recursive types.
-func typeOKForCgoCall(t types.Type, m map[types.Type]bool) bool {
- if t == nil || m[t] {
- return true
- }
- m[t] = true
- switch t := t.Underlying().(type) {
- case *types.Chan, *types.Map, *types.Signature, *types.Slice:
- return false
- case *types.Pointer:
- return typeOKForCgoCall(t.Elem(), m)
- case *types.Array:
- return typeOKForCgoCall(t.Elem(), m)
- case *types.Struct:
- for i := 0; i < t.NumFields(); i++ {
- if !typeOKForCgoCall(t.Field(i).Type(), m) {
- return false
- }
- }
- }
- return true
-}
+++ /dev/null
-// Copyright 2012 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.
-
-// This file contains the test for unkeyed struct literals.
-
-package main
-
-import (
- "cmd/vet/internal/whitelist"
- "flag"
- "go/ast"
- "go/types"
- "strings"
-)
-
-var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only")
-
-func init() {
- register("composites",
- "check that composite literals of types from imported packages use field-keyed elements",
- checkUnkeyedLiteral,
- compositeLit)
-}
-
-// checkUnkeyedLiteral checks if a composite literal is a struct literal with
-// unkeyed fields.
-func checkUnkeyedLiteral(f *File, node ast.Node) {
- cl := node.(*ast.CompositeLit)
-
- typ := f.pkg.types[cl].Type
- if typ == nil {
- // cannot determine composite literals' type, skip it
- return
- }
- typeName := typ.String()
- if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] {
- // skip whitelisted types
- return
- }
- under := typ.Underlying()
- for {
- ptr, ok := under.(*types.Pointer)
- if !ok {
- break
- }
- under = ptr.Elem().Underlying()
- }
- if _, ok := under.(*types.Struct); !ok {
- // skip non-struct composite literals
- return
- }
- if isLocalType(f, typ) {
- // allow unkeyed locally defined composite literal
- return
- }
-
- // check if the CompositeLit contains an unkeyed field
- allKeyValue := true
- for _, e := range cl.Elts {
- if _, ok := e.(*ast.KeyValueExpr); !ok {
- allKeyValue = false
- break
- }
- }
- if allKeyValue {
- // all the composite literal fields are keyed
- return
- }
-
- f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName)
-}
-
-func isLocalType(f *File, typ types.Type) bool {
- switch x := typ.(type) {
- case *types.Struct:
- // struct literals are local types
- return true
- case *types.Pointer:
- return isLocalType(f, x.Elem())
- case *types.Named:
- // names in package foo are local to foo_test too
- return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(f.pkg.path, "_test")
- }
- return false
-}
+++ /dev/null
-// 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.
-
-// This file contains the code to check that locks are not passed by value.
-
-package main
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("copylocks",
- "check that locks are not passed by value",
- checkCopyLocks,
- funcDecl, rangeStmt, funcLit, callExpr, assignStmt, genDecl, compositeLit, returnStmt)
-}
-
-// checkCopyLocks checks whether node might
-// inadvertently copy a lock.
-func checkCopyLocks(f *File, node ast.Node) {
- switch node := node.(type) {
- case *ast.RangeStmt:
- checkCopyLocksRange(f, node)
- case *ast.FuncDecl:
- checkCopyLocksFunc(f, node.Name.Name, node.Recv, node.Type)
- case *ast.FuncLit:
- checkCopyLocksFunc(f, "func", nil, node.Type)
- case *ast.CallExpr:
- checkCopyLocksCallExpr(f, node)
- case *ast.AssignStmt:
- checkCopyLocksAssign(f, node)
- case *ast.GenDecl:
- checkCopyLocksGenDecl(f, node)
- case *ast.CompositeLit:
- checkCopyLocksCompositeLit(f, node)
- case *ast.ReturnStmt:
- checkCopyLocksReturnStmt(f, node)
- }
-}
-
-// checkCopyLocksAssign checks whether an assignment
-// copies a lock.
-func checkCopyLocksAssign(f *File, as *ast.AssignStmt) {
- for i, x := range as.Rhs {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "assignment copies lock value to %v: %v", f.gofmt(as.Lhs[i]), path)
- }
- }
-}
-
-// checkCopyLocksGenDecl checks whether lock is copied
-// in variable declaration.
-func checkCopyLocksGenDecl(f *File, gd *ast.GenDecl) {
- if gd.Tok != token.VAR {
- return
- }
- for _, spec := range gd.Specs {
- valueSpec := spec.(*ast.ValueSpec)
- for i, x := range valueSpec.Values {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path)
- }
- }
- }
-}
-
-// checkCopyLocksCompositeLit detects lock copy inside a composite literal
-func checkCopyLocksCompositeLit(f *File, cl *ast.CompositeLit) {
- for _, x := range cl.Elts {
- if node, ok := x.(*ast.KeyValueExpr); ok {
- x = node.Value
- }
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "literal copies lock value from %v: %v", f.gofmt(x), path)
- }
- }
-}
-
-// checkCopyLocksReturnStmt detects lock copy in return statement
-func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) {
- for _, x := range rs.Results {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "return copies lock value: %v", path)
- }
- }
-}
-
-// checkCopyLocksCallExpr detects lock copy in the arguments to a function call
-func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
- var id *ast.Ident
- switch fun := ce.Fun.(type) {
- case *ast.Ident:
- id = fun
- case *ast.SelectorExpr:
- id = fun.Sel
- }
- if fun, ok := f.pkg.uses[id].(*types.Builtin); ok {
- switch fun.Name() {
- case "new", "len", "cap", "Sizeof":
- return
- }
- }
- for _, x := range ce.Args {
- if path := lockPathRhs(f, x); path != nil {
- f.Badf(x.Pos(), "call of %s copies lock value: %v", f.gofmt(ce.Fun), path)
- }
- }
-}
-
-// checkCopyLocksFunc checks whether a function might
-// inadvertently copy a lock, by checking whether
-// its receiver, parameters, or return values
-// are locks.
-func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.FuncType) {
- if recv != nil && len(recv.List) > 0 {
- expr := recv.List[0].Type
- if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
- f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path)
- }
- }
-
- if typ.Params != nil {
- for _, field := range typ.Params.List {
- expr := field.Type
- if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
- f.Badf(expr.Pos(), "%s passes lock by value: %v", name, path)
- }
- }
- }
-
- // Don't check typ.Results. If T has a Lock field it's OK to write
- // return T{}
- // because that is returning the zero value. Leave result checking
- // to the return statement.
-}
-
-// checkCopyLocksRange checks whether a range statement
-// might inadvertently copy a lock by checking whether
-// any of the range variables are locks.
-func checkCopyLocksRange(f *File, r *ast.RangeStmt) {
- checkCopyLocksRangeVar(f, r.Tok, r.Key)
- checkCopyLocksRangeVar(f, r.Tok, r.Value)
-}
-
-func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) {
- if e == nil {
- return
- }
- id, isId := e.(*ast.Ident)
- if isId && id.Name == "_" {
- return
- }
-
- var typ types.Type
- if rtok == token.DEFINE {
- if !isId {
- return
- }
- obj := f.pkg.defs[id]
- if obj == nil {
- return
- }
- typ = obj.Type()
- } else {
- typ = f.pkg.types[e].Type
- }
-
- if typ == nil {
- return
- }
- if path := lockPath(f.pkg.typesPkg, typ); path != nil {
- f.Badf(e.Pos(), "range var %s copies lock: %v", f.gofmt(e), path)
- }
-}
-
-type typePath []types.Type
-
-// String pretty-prints a typePath.
-func (path typePath) String() string {
- n := len(path)
- var buf bytes.Buffer
- for i := range path {
- if i > 0 {
- fmt.Fprint(&buf, " contains ")
- }
- // The human-readable path is in reverse order, outermost to innermost.
- fmt.Fprint(&buf, path[n-i-1].String())
- }
- return buf.String()
-}
-
-func lockPathRhs(f *File, x ast.Expr) typePath {
- if _, ok := x.(*ast.CompositeLit); ok {
- return nil
- }
- if _, ok := x.(*ast.CallExpr); ok {
- // A call may return a zero value.
- return nil
- }
- if star, ok := x.(*ast.StarExpr); ok {
- if _, ok := star.X.(*ast.CallExpr); ok {
- // A call may return a pointer to a zero value.
- return nil
- }
- }
- return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type)
-}
-
-// lockPath returns a typePath describing the location of a lock value
-// contained in typ. If there is no contained lock, it returns nil.
-func lockPath(tpkg *types.Package, typ types.Type) typePath {
- if typ == nil {
- return nil
- }
-
- for {
- atyp, ok := typ.Underlying().(*types.Array)
- if !ok {
- break
- }
- typ = atyp.Elem()
- }
-
- // We're only interested in the case in which the underlying
- // type is a struct. (Interfaces and pointers are safe to copy.)
- styp, ok := typ.Underlying().(*types.Struct)
- if !ok {
- return nil
- }
-
- // We're looking for cases in which a pointer to this type
- // is a sync.Locker, but a value is not. This differentiates
- // embedded interfaces from embedded values.
- if types.Implements(types.NewPointer(typ), lockerType) && !types.Implements(typ, lockerType) {
- return []types.Type{typ}
- }
-
- nfields := styp.NumFields()
- for i := 0; i < nfields; i++ {
- ftyp := styp.Field(i).Type()
- subpath := lockPath(tpkg, ftyp)
- if subpath != nil {
- return append(subpath, typ)
- }
- }
-
- return nil
-}
-
-var lockerType *types.Interface
-
-// Construct a sync.Locker interface type.
-func init() {
- nullary := types.NewSignature(nil, nil, nil, false) // func()
- methods := []*types.Func{
- types.NewFunc(token.NoPos, nil, "Lock", nullary),
- types.NewFunc(token.NoPos, nil, "Unlock", nullary),
- }
- lockerType = types.NewInterface(methods, nil).Complete()
-}
+++ /dev/null
-// Copyright 2017 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.
-//
-// Simplified dead code detector. Used for skipping certain checks
-// on unreachable code (for instance, shift checks on arch-specific code).
-
-package main
-
-import (
- "go/ast"
- "go/constant"
-)
-
-// updateDead puts unreachable "if" and "case" nodes into f.dead.
-func (f *File) updateDead(node ast.Node) {
- if f.dead[node] {
- // The node is already marked as dead.
- return
- }
-
- switch stmt := node.(type) {
- case *ast.IfStmt:
- // "if" branch is dead if its condition evaluates
- // to constant false.
- v := f.pkg.types[stmt.Cond].Value
- if v == nil {
- return
- }
- if !constant.BoolVal(v) {
- f.setDead(stmt.Body)
- return
- }
- f.setDead(stmt.Else)
- case *ast.SwitchStmt:
- // Case clause with empty switch tag is dead if it evaluates
- // to constant false.
- if stmt.Tag == nil {
- BodyLoopBool:
- for _, stmt := range stmt.Body.List {
- cc := stmt.(*ast.CaseClause)
- if cc.List == nil {
- // Skip default case.
- continue
- }
- for _, expr := range cc.List {
- v := f.pkg.types[expr].Value
- if v == nil || v.Kind() != constant.Bool || constant.BoolVal(v) {
- continue BodyLoopBool
- }
- }
- f.setDead(cc)
- }
- return
- }
-
- // Case clause is dead if its constant value doesn't match
- // the constant value from the switch tag.
- // TODO: This handles integer comparisons only.
- v := f.pkg.types[stmt.Tag].Value
- if v == nil || v.Kind() != constant.Int {
- return
- }
- tagN, ok := constant.Uint64Val(v)
- if !ok {
- return
- }
- BodyLoopInt:
- for _, x := range stmt.Body.List {
- cc := x.(*ast.CaseClause)
- if cc.List == nil {
- // Skip default case.
- continue
- }
- for _, expr := range cc.List {
- v := f.pkg.types[expr].Value
- if v == nil {
- continue BodyLoopInt
- }
- n, ok := constant.Uint64Val(v)
- if !ok || tagN == n {
- continue BodyLoopInt
- }
- }
- f.setDead(cc)
- }
- }
-}
-
-// setDead marks the node and all the children as dead.
-func (f *File) setDead(node ast.Node) {
- dv := deadVisitor{
- f: f,
- }
- ast.Walk(dv, node)
-}
-
-type deadVisitor struct {
- f *File
-}
-
-func (dv deadVisitor) Visit(node ast.Node) ast.Visitor {
- if node == nil {
- return nil
- }
- dv.f.dead[node] = true
- return dv
-}
+++ /dev/null
-// 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.
-
-// Check for syntactically unreachable code.
-
-package main
-
-import (
- "go/ast"
- "go/token"
-)
-
-func init() {
- register("unreachable",
- "check for unreachable code",
- checkUnreachable,
- funcDecl, funcLit)
-}
-
-type deadState struct {
- f *File
- hasBreak map[ast.Stmt]bool
- hasGoto map[string]bool
- labels map[string]ast.Stmt
- breakTarget ast.Stmt
-
- reachable bool
-}
-
-// checkUnreachable checks a function body for dead code.
-//
-// TODO(adonovan): use the new cfg package, which is more precise.
-func checkUnreachable(f *File, node ast.Node) {
- var body *ast.BlockStmt
- switch n := node.(type) {
- case *ast.FuncDecl:
- body = n.Body
- case *ast.FuncLit:
- body = n.Body
- }
- if body == nil {
- return
- }
-
- d := &deadState{
- f: f,
- hasBreak: make(map[ast.Stmt]bool),
- hasGoto: make(map[string]bool),
- labels: make(map[string]ast.Stmt),
- }
-
- d.findLabels(body)
-
- d.reachable = true
- d.findDead(body)
-}
-
-// findLabels gathers information about the labels defined and used by stmt
-// and about which statements break, whether a label is involved or not.
-func (d *deadState) findLabels(stmt ast.Stmt) {
- switch x := stmt.(type) {
- default:
- d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x)
-
- case *ast.AssignStmt,
- *ast.BadStmt,
- *ast.DeclStmt,
- *ast.DeferStmt,
- *ast.EmptyStmt,
- *ast.ExprStmt,
- *ast.GoStmt,
- *ast.IncDecStmt,
- *ast.ReturnStmt,
- *ast.SendStmt:
- // no statements inside
-
- case *ast.BlockStmt:
- for _, stmt := range x.List {
- d.findLabels(stmt)
- }
-
- case *ast.BranchStmt:
- switch x.Tok {
- case token.GOTO:
- if x.Label != nil {
- d.hasGoto[x.Label.Name] = true
- }
-
- case token.BREAK:
- stmt := d.breakTarget
- if x.Label != nil {
- stmt = d.labels[x.Label.Name]
- }
- if stmt != nil {
- d.hasBreak[stmt] = true
- }
- }
-
- case *ast.IfStmt:
- d.findLabels(x.Body)
- if x.Else != nil {
- d.findLabels(x.Else)
- }
-
- case *ast.LabeledStmt:
- d.labels[x.Label.Name] = x.Stmt
- d.findLabels(x.Stmt)
-
- // These cases are all the same, but the x.Body only works
- // when the specific type of x is known, so the cases cannot
- // be merged.
- case *ast.ForStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.RangeStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.SelectStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.SwitchStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.TypeSwitchStmt:
- outer := d.breakTarget
- d.breakTarget = x
- d.findLabels(x.Body)
- d.breakTarget = outer
-
- case *ast.CommClause:
- for _, stmt := range x.Body {
- d.findLabels(stmt)
- }
-
- case *ast.CaseClause:
- for _, stmt := range x.Body {
- d.findLabels(stmt)
- }
- }
-}
-
-// findDead walks the statement looking for dead code.
-// If d.reachable is false on entry, stmt itself is dead.
-// When findDead returns, d.reachable tells whether the
-// statement following stmt is reachable.
-func (d *deadState) findDead(stmt ast.Stmt) {
- // Is this a labeled goto target?
- // If so, assume it is reachable due to the goto.
- // This is slightly conservative, in that we don't
- // check that the goto is reachable, so
- // L: goto L
- // will not provoke a warning.
- // But it's good enough.
- if x, isLabel := stmt.(*ast.LabeledStmt); isLabel && d.hasGoto[x.Label.Name] {
- d.reachable = true
- }
-
- if !d.reachable {
- switch stmt.(type) {
- case *ast.EmptyStmt:
- // do not warn about unreachable empty statements
- default:
- d.f.Bad(stmt.Pos(), "unreachable code")
- d.reachable = true // silence error about next statement
- }
- }
-
- switch x := stmt.(type) {
- default:
- d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x)
-
- case *ast.AssignStmt,
- *ast.BadStmt,
- *ast.DeclStmt,
- *ast.DeferStmt,
- *ast.EmptyStmt,
- *ast.GoStmt,
- *ast.IncDecStmt,
- *ast.SendStmt:
- // no control flow
-
- case *ast.BlockStmt:
- for _, stmt := range x.List {
- d.findDead(stmt)
- }
-
- case *ast.BranchStmt:
- switch x.Tok {
- case token.BREAK, token.GOTO, token.FALLTHROUGH:
- d.reachable = false
- case token.CONTINUE:
- // NOTE: We accept "continue" statements as terminating.
- // They are not necessary in the spec definition of terminating,
- // because a continue statement cannot be the final statement
- // before a return. But for the more general problem of syntactically
- // identifying dead code, continue redirects control flow just
- // like the other terminating statements.
- d.reachable = false
- }
-
- case *ast.ExprStmt:
- // Call to panic?
- call, ok := x.X.(*ast.CallExpr)
- if ok {
- name, ok := call.Fun.(*ast.Ident)
- if ok && name.Name == "panic" && name.Obj == nil {
- d.reachable = false
- }
- }
-
- case *ast.ForStmt:
- d.findDead(x.Body)
- d.reachable = x.Cond != nil || d.hasBreak[x]
-
- case *ast.IfStmt:
- d.findDead(x.Body)
- if x.Else != nil {
- r := d.reachable
- d.reachable = true
- d.findDead(x.Else)
- d.reachable = d.reachable || r
- } else {
- // might not have executed if statement
- d.reachable = true
- }
-
- case *ast.LabeledStmt:
- d.findDead(x.Stmt)
-
- case *ast.RangeStmt:
- d.findDead(x.Body)
- d.reachable = true
-
- case *ast.ReturnStmt:
- d.reachable = false
-
- case *ast.SelectStmt:
- // NOTE: Unlike switch and type switch below, we don't care
- // whether a select has a default, because a select without a
- // default blocks until one of the cases can run. That's different
- // from a switch without a default, which behaves like it has
- // a default with an empty body.
- anyReachable := false
- for _, comm := range x.Body.List {
- d.reachable = true
- for _, stmt := range comm.(*ast.CommClause).Body {
- d.findDead(stmt)
- }
- anyReachable = anyReachable || d.reachable
- }
- d.reachable = anyReachable || d.hasBreak[x]
-
- case *ast.SwitchStmt:
- anyReachable := false
- hasDefault := false
- for _, cas := range x.Body.List {
- cc := cas.(*ast.CaseClause)
- if cc.List == nil {
- hasDefault = true
- }
- d.reachable = true
- for _, stmt := range cc.Body {
- d.findDead(stmt)
- }
- anyReachable = anyReachable || d.reachable
- }
- d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
-
- case *ast.TypeSwitchStmt:
- anyReachable := false
- hasDefault := false
- for _, cas := range x.Body.List {
- cc := cas.(*ast.CaseClause)
- if cc.List == nil {
- hasDefault = true
- }
- d.reachable = true
- for _, stmt := range cc.Body {
- d.findDead(stmt)
- }
- anyReachable = anyReachable || d.reachable
- }
- d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
- }
-}
+++ /dev/null
-// 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
+++ /dev/null
-// Copyright 2016 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.
-
-// This file contains the check for http.Response values being used before
-// checking for errors.
-
-package main
-
-import (
- "go/ast"
- "go/types"
-)
-
-func init() {
- register("httpresponse",
- "check errors are checked before using an http Response",
- checkHTTPResponse, callExpr)
-}
-
-func checkHTTPResponse(f *File, node ast.Node) {
- call := node.(*ast.CallExpr)
- if !isHTTPFuncOrMethodOnClient(f, call) {
- return // the function call is not related to this check.
- }
-
- finder := &blockStmtFinder{node: call}
- ast.Walk(finder, f.file)
- stmts := finder.stmts()
- if len(stmts) < 2 {
- return // the call to the http function is the last statement of the block.
- }
-
- asg, ok := stmts[0].(*ast.AssignStmt)
- if !ok {
- return // the first statement is not assignment.
- }
- resp := rootIdent(asg.Lhs[0])
- if resp == nil {
- return // could not find the http.Response in the assignment.
- }
-
- def, ok := stmts[1].(*ast.DeferStmt)
- if !ok {
- return // the following statement is not a defer.
- }
- root := rootIdent(def.Call.Fun)
- if root == nil {
- return // could not find the receiver of the defer call.
- }
-
- if resp.Obj == root.Obj {
- f.Badf(root.Pos(), "using %s before checking for errors", resp.Name)
- }
-}
-
-// isHTTPFuncOrMethodOnClient checks whether the given call expression is on
-// either a function of the net/http package or a method of http.Client that
-// returns (*http.Response, error).
-func isHTTPFuncOrMethodOnClient(f *File, expr *ast.CallExpr) bool {
- fun, _ := expr.Fun.(*ast.SelectorExpr)
- sig, _ := f.pkg.types[fun].Type.(*types.Signature)
- if sig == nil {
- return false // the call is not on of the form x.f()
- }
-
- res := sig.Results()
- if res.Len() != 2 {
- return false // the function called does not return two values.
- }
- if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !isNamedType(ptr.Elem(), "net/http", "Response") {
- return false // the first return type is not *http.Response.
- }
- if !types.Identical(res.At(1).Type().Underlying(), errorType) {
- return false // the second return type is not error
- }
-
- typ := f.pkg.types[fun.X].Type
- if typ == nil {
- id, ok := fun.X.(*ast.Ident)
- return ok && id.Name == "http" // function in net/http package.
- }
-
- if isNamedType(typ, "net/http", "Client") {
- return true // method on http.Client.
- }
- ptr, ok := typ.(*types.Pointer)
- return ok && isNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
-}
-
-// blockStmtFinder is an ast.Visitor that given any ast node can find the
-// statement containing it and its succeeding statements in the same block.
-type blockStmtFinder struct {
- node ast.Node // target of search
- stmt ast.Stmt // innermost statement enclosing argument to Visit
- block *ast.BlockStmt // innermost block enclosing argument to Visit.
-}
-
-// Visit finds f.node performing a search down the ast tree.
-// It keeps the last block statement and statement seen for later use.
-func (f *blockStmtFinder) Visit(node ast.Node) ast.Visitor {
- if node == nil || f.node.Pos() < node.Pos() || f.node.End() > node.End() {
- return nil // not here
- }
- switch n := node.(type) {
- case *ast.BlockStmt:
- f.block = n
- case ast.Stmt:
- f.stmt = n
- }
- if f.node.Pos() == node.Pos() && f.node.End() == node.End() {
- return nil // found
- }
- return f // keep looking
-}
-
-// stmts returns the statements of f.block starting from the one including f.node.
-func (f *blockStmtFinder) stmts() []ast.Stmt {
- for i, v := range f.block.List {
- if f.stmt == v {
- return f.block.List[i:]
- }
- }
- return nil
-}
-
-// rootIdent finds the root identifier x in a chain of selections x.y.z, or nil if not found.
-func rootIdent(n ast.Node) *ast.Ident {
- switch n := n.(type) {
- case *ast.SelectorExpr:
- return rootIdent(n.X)
- case *ast.Ident:
- return n
- default:
- return nil
- }
-}
+++ /dev/null
-// Copyright 2016 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 cfg
-
-// This file implements the CFG construction pass.
-
-import (
- "fmt"
- "go/ast"
- "go/token"
-)
-
-type builder struct {
- cfg *CFG
- mayReturn func(*ast.CallExpr) bool
- current *Block
- lblocks map[*ast.Object]*lblock // labeled blocks
- targets *targets // linked stack of branch targets
-}
-
-func (b *builder) stmt(_s ast.Stmt) {
- // The label of the current statement. If non-nil, its _goto
- // target is always set; its _break and _continue are set only
- // within the body of switch/typeswitch/select/for/range.
- // It is effectively an additional default-nil parameter of stmt().
- var label *lblock
-start:
- switch s := _s.(type) {
- case *ast.BadStmt,
- *ast.SendStmt,
- *ast.IncDecStmt,
- *ast.GoStmt,
- *ast.DeferStmt,
- *ast.EmptyStmt,
- *ast.AssignStmt:
- // No effect on control flow.
- b.add(s)
-
- case *ast.ExprStmt:
- b.add(s)
- if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) {
- // Calls to panic, os.Exit, etc, never return.
- b.current = b.newUnreachableBlock("unreachable.call")
- }
-
- case *ast.DeclStmt:
- // Treat each var ValueSpec as a separate statement.
- d := s.Decl.(*ast.GenDecl)
- if d.Tok == token.VAR {
- for _, spec := range d.Specs {
- if spec, ok := spec.(*ast.ValueSpec); ok {
- b.add(spec)
- }
- }
- }
-
- case *ast.LabeledStmt:
- label = b.labeledBlock(s.Label)
- b.jump(label._goto)
- b.current = label._goto
- _s = s.Stmt
- goto start // effectively: tailcall stmt(g, s.Stmt, label)
-
- case *ast.ReturnStmt:
- b.add(s)
- b.current = b.newUnreachableBlock("unreachable.return")
-
- case *ast.BranchStmt:
- var block *Block
- switch s.Tok {
- case token.BREAK:
- if s.Label != nil {
- if lb := b.labeledBlock(s.Label); lb != nil {
- block = lb._break
- }
- } else {
- for t := b.targets; t != nil && block == nil; t = t.tail {
- block = t._break
- }
- }
-
- case token.CONTINUE:
- if s.Label != nil {
- if lb := b.labeledBlock(s.Label); lb != nil {
- block = lb._continue
- }
- } else {
- for t := b.targets; t != nil && block == nil; t = t.tail {
- block = t._continue
- }
- }
-
- case token.FALLTHROUGH:
- for t := b.targets; t != nil; t = t.tail {
- block = t._fallthrough
- }
-
- case token.GOTO:
- if s.Label != nil {
- block = b.labeledBlock(s.Label)._goto
- }
- }
- if block == nil {
- block = b.newBlock("undefined.branch")
- }
- b.jump(block)
- b.current = b.newUnreachableBlock("unreachable.branch")
-
- case *ast.BlockStmt:
- b.stmtList(s.List)
-
- case *ast.IfStmt:
- if s.Init != nil {
- b.stmt(s.Init)
- }
- then := b.newBlock("if.then")
- done := b.newBlock("if.done")
- _else := done
- if s.Else != nil {
- _else = b.newBlock("if.else")
- }
- b.add(s.Cond)
- b.ifelse(then, _else)
- b.current = then
- b.stmt(s.Body)
- b.jump(done)
-
- if s.Else != nil {
- b.current = _else
- b.stmt(s.Else)
- b.jump(done)
- }
-
- b.current = done
-
- case *ast.SwitchStmt:
- b.switchStmt(s, label)
-
- case *ast.TypeSwitchStmt:
- b.typeSwitchStmt(s, label)
-
- case *ast.SelectStmt:
- b.selectStmt(s, label)
-
- case *ast.ForStmt:
- b.forStmt(s, label)
-
- case *ast.RangeStmt:
- b.rangeStmt(s, label)
-
- default:
- panic(fmt.Sprintf("unexpected statement kind: %T", s))
- }
-}
-
-func (b *builder) stmtList(list []ast.Stmt) {
- for _, s := range list {
- b.stmt(s)
- }
-}
-
-func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
- if s.Init != nil {
- b.stmt(s.Init)
- }
- if s.Tag != nil {
- b.add(s.Tag)
- }
- done := b.newBlock("switch.done")
- if label != nil {
- label._break = done
- }
- // We pull the default case (if present) down to the end.
- // But each fallthrough label must point to the next
- // body block in source order, so we preallocate a
- // body block (fallthru) for the next case.
- // Unfortunately this makes for a confusing block order.
- var defaultBody *[]ast.Stmt
- var defaultFallthrough *Block
- var fallthru, defaultBlock *Block
- ncases := len(s.Body.List)
- for i, clause := range s.Body.List {
- body := fallthru
- if body == nil {
- body = b.newBlock("switch.body") // first case only
- }
-
- // Preallocate body block for the next case.
- fallthru = done
- if i+1 < ncases {
- fallthru = b.newBlock("switch.body")
- }
-
- cc := clause.(*ast.CaseClause)
- if cc.List == nil {
- // Default case.
- defaultBody = &cc.Body
- defaultFallthrough = fallthru
- defaultBlock = body
- continue
- }
-
- var nextCond *Block
- for _, cond := range cc.List {
- nextCond = b.newBlock("switch.next")
- b.add(cond) // one half of the tag==cond condition
- b.ifelse(body, nextCond)
- b.current = nextCond
- }
- b.current = body
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _fallthrough: fallthru,
- }
- b.stmtList(cc.Body)
- b.targets = b.targets.tail
- b.jump(done)
- b.current = nextCond
- }
- if defaultBlock != nil {
- b.jump(defaultBlock)
- b.current = defaultBlock
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _fallthrough: defaultFallthrough,
- }
- b.stmtList(*defaultBody)
- b.targets = b.targets.tail
- }
- b.jump(done)
- b.current = done
-}
-
-func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) {
- if s.Init != nil {
- b.stmt(s.Init)
- }
- if s.Assign != nil {
- b.add(s.Assign)
- }
-
- done := b.newBlock("typeswitch.done")
- if label != nil {
- label._break = done
- }
- var default_ *ast.CaseClause
- for _, clause := range s.Body.List {
- cc := clause.(*ast.CaseClause)
- if cc.List == nil {
- default_ = cc
- continue
- }
- body := b.newBlock("typeswitch.body")
- var next *Block
- for _, casetype := range cc.List {
- next = b.newBlock("typeswitch.next")
- // casetype is a type, so don't call b.add(casetype).
- // This block logically contains a type assertion,
- // x.(casetype), but it's unclear how to represent x.
- _ = casetype
- b.ifelse(body, next)
- b.current = next
- }
- b.current = body
- b.typeCaseBody(cc, done)
- b.current = next
- }
- if default_ != nil {
- b.typeCaseBody(default_, done)
- } else {
- b.jump(done)
- }
- b.current = done
-}
-
-func (b *builder) typeCaseBody(cc *ast.CaseClause, done *Block) {
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- }
- b.stmtList(cc.Body)
- b.targets = b.targets.tail
- b.jump(done)
-}
-
-func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) {
- // First evaluate channel expressions.
- // TODO(adonovan): fix: evaluate only channel exprs here.
- for _, clause := range s.Body.List {
- if comm := clause.(*ast.CommClause).Comm; comm != nil {
- b.stmt(comm)
- }
- }
-
- done := b.newBlock("select.done")
- if label != nil {
- label._break = done
- }
-
- var defaultBody *[]ast.Stmt
- for _, cc := range s.Body.List {
- clause := cc.(*ast.CommClause)
- if clause.Comm == nil {
- defaultBody = &clause.Body
- continue
- }
- body := b.newBlock("select.body")
- next := b.newBlock("select.next")
- b.ifelse(body, next)
- b.current = body
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- }
- switch comm := clause.Comm.(type) {
- case *ast.ExprStmt: // <-ch
- // nop
- case *ast.AssignStmt: // x := <-states[state].Chan
- b.add(comm.Lhs[0])
- }
- b.stmtList(clause.Body)
- b.targets = b.targets.tail
- b.jump(done)
- b.current = next
- }
- if defaultBody != nil {
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- }
- b.stmtList(*defaultBody)
- b.targets = b.targets.tail
- b.jump(done)
- }
- b.current = done
-}
-
-func (b *builder) forStmt(s *ast.ForStmt, label *lblock) {
- // ...init...
- // jump loop
- // loop:
- // if cond goto body else done
- // body:
- // ...body...
- // jump post
- // post: (target of continue)
- // ...post...
- // jump loop
- // done: (target of break)
- if s.Init != nil {
- b.stmt(s.Init)
- }
- body := b.newBlock("for.body")
- done := b.newBlock("for.done") // target of 'break'
- loop := body // target of back-edge
- if s.Cond != nil {
- loop = b.newBlock("for.loop")
- }
- cont := loop // target of 'continue'
- if s.Post != nil {
- cont = b.newBlock("for.post")
- }
- if label != nil {
- label._break = done
- label._continue = cont
- }
- b.jump(loop)
- b.current = loop
- if loop != body {
- b.add(s.Cond)
- b.ifelse(body, done)
- b.current = body
- }
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _continue: cont,
- }
- b.stmt(s.Body)
- b.targets = b.targets.tail
- b.jump(cont)
-
- if s.Post != nil {
- b.current = cont
- b.stmt(s.Post)
- b.jump(loop) // back-edge
- }
- b.current = done
-}
-
-func (b *builder) rangeStmt(s *ast.RangeStmt, label *lblock) {
- b.add(s.X)
-
- if s.Key != nil {
- b.add(s.Key)
- }
- if s.Value != nil {
- b.add(s.Value)
- }
-
- // ...
- // loop: (target of continue)
- // if ... goto body else done
- // body:
- // ...
- // jump loop
- // done: (target of break)
-
- loop := b.newBlock("range.loop")
- b.jump(loop)
- b.current = loop
-
- body := b.newBlock("range.body")
- done := b.newBlock("range.done")
- b.ifelse(body, done)
- b.current = body
-
- if label != nil {
- label._break = done
- label._continue = loop
- }
- b.targets = &targets{
- tail: b.targets,
- _break: done,
- _continue: loop,
- }
- b.stmt(s.Body)
- b.targets = b.targets.tail
- b.jump(loop) // back-edge
- b.current = done
-}
-
-// -------- helpers --------
-
-// Destinations associated with unlabeled for/switch/select stmts.
-// We push/pop one of these as we enter/leave each construct and for
-// each BranchStmt we scan for the innermost target of the right type.
-//
-type targets struct {
- tail *targets // rest of stack
- _break *Block
- _continue *Block
- _fallthrough *Block
-}
-
-// Destinations associated with a labeled block.
-// We populate these as labels are encountered in forward gotos or
-// labeled statements.
-//
-type lblock struct {
- _goto *Block
- _break *Block
- _continue *Block
-}
-
-// labeledBlock returns the branch target associated with the
-// specified label, creating it if needed.
-//
-func (b *builder) labeledBlock(label *ast.Ident) *lblock {
- lb := b.lblocks[label.Obj]
- if lb == nil {
- lb = &lblock{_goto: b.newBlock(label.Name)}
- if b.lblocks == nil {
- b.lblocks = make(map[*ast.Object]*lblock)
- }
- b.lblocks[label.Obj] = lb
- }
- return lb
-}
-
-// newBlock appends a new unconnected basic block to b.cfg's block
-// slice and returns it.
-// It does not automatically become the current block.
-// comment is an optional string for more readable debugging output.
-func (b *builder) newBlock(comment string) *Block {
- g := b.cfg
- block := &Block{
- index: int32(len(g.Blocks)),
- comment: comment,
- }
- block.Succs = block.succs2[:0]
- g.Blocks = append(g.Blocks, block)
- return block
-}
-
-func (b *builder) newUnreachableBlock(comment string) *Block {
- block := b.newBlock(comment)
- block.unreachable = true
- return block
-}
-
-func (b *builder) add(n ast.Node) {
- b.current.Nodes = append(b.current.Nodes, n)
-}
-
-// jump adds an edge from the current block to the target block,
-// and sets b.current to nil.
-func (b *builder) jump(target *Block) {
- b.current.Succs = append(b.current.Succs, target)
- b.current = nil
-}
-
-// ifelse emits edges from the current block to the t and f blocks,
-// and sets b.current to nil.
-func (b *builder) ifelse(t, f *Block) {
- b.current.Succs = append(b.current.Succs, t, f)
- b.current = nil
-}
+++ /dev/null
-// Copyright 2016 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.
-
-// This package constructs a simple control-flow graph (CFG) of the
-// statements and expressions within a single function.
-//
-// Use cfg.New to construct the CFG for a function body.
-//
-// The blocks of the CFG contain all the function's non-control
-// statements. The CFG does not contain control statements such as If,
-// Switch, Select, and Branch, but does contain their subexpressions.
-// For example, this source code:
-//
-// if x := f(); x != nil {
-// T()
-// } else {
-// F()
-// }
-//
-// produces this CFG:
-//
-// 1: x := f()
-// x != nil
-// succs: 2, 3
-// 2: T()
-// succs: 4
-// 3: F()
-// succs: 4
-// 4:
-//
-// The CFG does contain Return statements; even implicit returns are
-// materialized (at the position of the function's closing brace).
-//
-// The CFG does not record conditions associated with conditional branch
-// edges, nor the short-circuit semantics of the && and || operators,
-// nor abnormal control flow caused by panic. If you need this
-// information, use golang.org/x/tools/go/ssa instead.
-//
-package cfg
-
-// Although the vet tool has type information, it is often extremely
-// fragmentary, so for simplicity this package does not depend on
-// go/types. Consequently control-flow conditions are ignored even
-// when constant, and "mayReturn" information must be provided by the
-// client.
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/format"
- "go/token"
-)
-
-// A CFG represents the control-flow graph of a single function.
-//
-// The entry point is Blocks[0]; there may be multiple return blocks.
-type CFG struct {
- Blocks []*Block // block[0] is entry; order otherwise undefined
-}
-
-// A Block represents a basic block: a list of statements and
-// expressions that are always evaluated sequentially.
-//
-// A block may have 0-2 successors: zero for a return block or a block
-// that calls a function such as panic that never returns; one for a
-// normal (jump) block; and two for a conditional (if) block.
-type Block struct {
- Nodes []ast.Node // statements, expressions, and ValueSpecs
- Succs []*Block // successor nodes in the graph
-
- comment string // for debugging
- index int32 // index within CFG.Blocks
- unreachable bool // is block of stmts following return/panic/for{}
- succs2 [2]*Block // underlying array for Succs
-}
-
-// New returns a new control-flow graph for the specified function body,
-// which must be non-nil.
-//
-// The CFG builder calls mayReturn to determine whether a given function
-// call may return. For example, calls to panic, os.Exit, and log.Fatal
-// do not return, so the builder can remove infeasible graph edges
-// following such calls. The builder calls mayReturn only for a
-// CallExpr beneath an ExprStmt.
-func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
- b := builder{
- mayReturn: mayReturn,
- cfg: new(CFG),
- }
- b.current = b.newBlock("entry")
- b.stmt(body)
-
- // Does control fall off the end of the function's body?
- // Make implicit return explicit.
- if b.current != nil && !b.current.unreachable {
- b.add(&ast.ReturnStmt{
- Return: body.End() - 1,
- })
- }
-
- return b.cfg
-}
-
-func (b *Block) String() string {
- return fmt.Sprintf("block %d (%s)", b.index, b.comment)
-}
-
-// Return returns the return statement at the end of this block if present, nil otherwise.
-func (b *Block) Return() (ret *ast.ReturnStmt) {
- if len(b.Nodes) > 0 {
- ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt)
- }
- return
-}
-
-// Format formats the control-flow graph for ease of debugging.
-func (g *CFG) Format(fset *token.FileSet) string {
- var buf bytes.Buffer
- for _, b := range g.Blocks {
- fmt.Fprintf(&buf, ".%d: # %s\n", b.index, b.comment)
- for _, n := range b.Nodes {
- fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
- }
- if len(b.Succs) > 0 {
- fmt.Fprintf(&buf, "\tsuccs:")
- for _, succ := range b.Succs {
- fmt.Fprintf(&buf, " %d", succ.index)
- }
- buf.WriteByte('\n')
- }
- buf.WriteByte('\n')
- }
- return buf.String()
-}
-
-func formatNode(fset *token.FileSet, n ast.Node) string {
- var buf bytes.Buffer
- format.Node(&buf, fset, n)
- // Indent secondary lines by a tab.
- return string(bytes.Replace(buf.Bytes(), []byte("\n"), []byte("\n\t"), -1))
-}
+++ /dev/null
-// Copyright 2016 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 cfg
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "testing"
-)
-
-const src = `package main
-
-import "log"
-
-func f1() {
- live()
- return
- dead()
-}
-
-func f2() {
- for {
- live()
- }
- dead()
-}
-
-func f3() {
- if true { // even known values are ignored
- return
- }
- for true { // even known values are ignored
- live()
- }
- for {
- live()
- }
- dead()
-}
-
-func f4(x int) {
- switch x {
- case 1:
- live()
- fallthrough
- case 2:
- live()
- log.Fatal()
- default:
- panic("oops")
- }
- dead()
-}
-
-func f4(ch chan int) {
- select {
- case <-ch:
- live()
- return
- default:
- live()
- panic("oops")
- }
- dead()
-}
-
-func f5(unknown bool) {
- for {
- if unknown {
- break
- }
- continue
- dead()
- }
- live()
-}
-
-func f6(unknown bool) {
-outer:
- for {
- for {
- break outer
- dead()
- }
- dead()
- }
- live()
-}
-
-func f7() {
- for {
- break nosuchlabel
- dead()
- }
- dead()
-}
-
-func f8() {
- select{}
- dead()
-}
-
-func f9(ch chan int) {
- select {
- case <-ch:
- return
- }
- dead()
-}
-
-func f10(ch chan int) {
- select {
- case <-ch:
- return
- dead()
- default:
- }
- live()
-}
-
-func f11() {
- goto; // mustn't crash
- dead()
-}
-
-`
-
-func TestDeadCode(t *testing.T) {
- // We'll use dead code detection to verify the CFG.
-
- fset := token.NewFileSet()
- f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0))
- if err != nil {
- t.Fatal(err)
- }
- for _, decl := range f.Decls {
- if decl, ok := decl.(*ast.FuncDecl); ok {
- g := New(decl.Body, mayReturn)
-
- // Mark blocks reachable from entry.
- live := make(map[*Block]bool)
- var visit func(*Block)
- visit = func(b *Block) {
- if !live[b] {
- live[b] = true
- for _, succ := range b.Succs {
- visit(succ)
- }
- }
- }
- visit(g.Blocks[0])
-
- // Print statements in unreachable blocks
- // (in order determined by builder).
- var buf bytes.Buffer
- for _, b := range g.Blocks {
- if !live[b] {
- for _, n := range b.Nodes {
- fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
- }
- }
- }
-
- // Check that the result contains "dead" at least once but not "live".
- if !bytes.Contains(buf.Bytes(), []byte("dead")) ||
- bytes.Contains(buf.Bytes(), []byte("live")) {
- t.Errorf("unexpected dead statements in function %s:\n%s",
- decl.Name.Name,
- &buf)
- t.Logf("control flow graph:\n%s", g.Format(fset))
- }
- }
- }
-}
-
-// A trivial mayReturn predicate that looks only at syntax, not types.
-func mayReturn(call *ast.CallExpr) bool {
- switch fun := call.Fun.(type) {
- case *ast.Ident:
- return fun.Name != "panic"
- case *ast.SelectorExpr:
- return fun.Sel.Name != "Fatal"
- }
- return true
-}
+++ /dev/null
-// 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 whitelist defines exceptions for the vet tool.
-package whitelist
-
-// UnkeyedLiteral is a white list of types in the standard packages
-// that are used with unkeyed literals we deem to be acceptable.
-var UnkeyedLiteral = map[string]bool{
- // These image and image/color struct types are frozen. We will never add fields to them.
- "image/color.Alpha16": true,
- "image/color.Alpha": true,
- "image/color.CMYK": true,
- "image/color.Gray16": true,
- "image/color.Gray": true,
- "image/color.NRGBA64": true,
- "image/color.NRGBA": true,
- "image/color.NYCbCrA": true,
- "image/color.RGBA64": true,
- "image/color.RGBA": true,
- "image/color.YCbCr": true,
- "image.Point": true,
- "image.Rectangle": true,
- "image.Uniform": true,
-
- "unicode.Range16": true,
-}
+++ /dev/null
-// Copyright 2016 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
-
-import (
- "cmd/vet/internal/cfg"
- "fmt"
- "go/ast"
- "go/types"
- "strconv"
-)
-
-func init() {
- register("lostcancel",
- "check for failure to call cancelation function returned by context.WithCancel",
- checkLostCancel,
- funcDecl, funcLit)
-}
-
-const debugLostCancel = false
-
-var contextPackage = "context"
-
-// checkLostCancel reports a failure to the call the cancel function
-// returned by context.WithCancel, either because the variable was
-// assigned to the blank identifier, or because there exists a
-// control-flow path from the call to a return statement and that path
-// does not "use" the cancel function. Any reference to the variable
-// counts as a use, even within a nested function literal.
-//
-// checkLostCancel analyzes a single named or literal function.
-func checkLostCancel(f *File, node ast.Node) {
- // Fast path: bypass check if file doesn't use context.WithCancel.
- if !hasImport(f.file, contextPackage) {
- return
- }
-
- // Maps each cancel variable to its defining ValueSpec/AssignStmt.
- cancelvars := make(map[*types.Var]ast.Node)
-
- // Find the set of cancel vars to analyze.
- stack := make([]ast.Node, 0, 32)
- ast.Inspect(node, func(n ast.Node) bool {
- switch n.(type) {
- case *ast.FuncLit:
- if len(stack) > 0 {
- return false // don't stray into nested functions
- }
- case nil:
- stack = stack[:len(stack)-1] // pop
- return true
- }
- stack = append(stack, n) // push
-
- // Look for [{AssignStmt,ValueSpec} CallExpr SelectorExpr]:
- //
- // ctx, cancel := context.WithCancel(...)
- // ctx, cancel = context.WithCancel(...)
- // var ctx, cancel = context.WithCancel(...)
- //
- if isContextWithCancel(f, n) && isCall(stack[len(stack)-2]) {
- var id *ast.Ident // id of cancel var
- stmt := stack[len(stack)-3]
- switch stmt := stmt.(type) {
- case *ast.ValueSpec:
- if len(stmt.Names) > 1 {
- id = stmt.Names[1]
- }
- case *ast.AssignStmt:
- if len(stmt.Lhs) > 1 {
- id, _ = stmt.Lhs[1].(*ast.Ident)
- }
- }
- if id != nil {
- if id.Name == "_" {
- f.Badf(id.Pos(), "the cancel function returned by context.%s should be called, not discarded, to avoid a context leak",
- n.(*ast.SelectorExpr).Sel.Name)
- } else if v, ok := f.pkg.uses[id].(*types.Var); ok {
- cancelvars[v] = stmt
- } else if v, ok := f.pkg.defs[id].(*types.Var); ok {
- cancelvars[v] = stmt
- }
- }
- }
-
- return true
- })
-
- if len(cancelvars) == 0 {
- return // no need to build CFG
- }
-
- // Tell the CFG builder which functions never return.
- info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors}
- mayReturn := func(call *ast.CallExpr) bool {
- name := callName(info, call)
- return !noReturnFuncs[name]
- }
-
- // Build the CFG.
- var g *cfg.CFG
- var sig *types.Signature
- switch node := node.(type) {
- case *ast.FuncDecl:
- obj := f.pkg.defs[node.Name]
- if obj == nil {
- return // type error (e.g. duplicate function declaration)
- }
- sig, _ = obj.Type().(*types.Signature)
- g = cfg.New(node.Body, mayReturn)
- case *ast.FuncLit:
- sig, _ = f.pkg.types[node.Type].Type.(*types.Signature)
- g = cfg.New(node.Body, mayReturn)
- }
-
- // Print CFG.
- if debugLostCancel {
- fmt.Println(g.Format(f.fset))
- }
-
- // Examine the CFG for each variable in turn.
- // (It would be more efficient to analyze all cancelvars in a
- // single pass over the AST, but seldom is there more than one.)
- for v, stmt := range cancelvars {
- if ret := lostCancelPath(f, g, v, stmt, sig); ret != nil {
- lineno := f.fset.Position(stmt.Pos()).Line
- f.Badf(stmt.Pos(), "the %s function is not used on all paths (possible context leak)", v.Name())
- f.Badf(ret.Pos(), "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno)
- }
- }
-}
-
-func isCall(n ast.Node) bool { _, ok := n.(*ast.CallExpr); return ok }
-
-func hasImport(f *ast.File, path string) bool {
- for _, imp := range f.Imports {
- v, _ := strconv.Unquote(imp.Path.Value)
- if v == path {
- return true
- }
- }
- return false
-}
-
-// isContextWithCancel reports whether n is one of the qualified identifiers
-// context.With{Cancel,Timeout,Deadline}.
-func isContextWithCancel(f *File, n ast.Node) bool {
- if sel, ok := n.(*ast.SelectorExpr); ok {
- switch sel.Sel.Name {
- case "WithCancel", "WithTimeout", "WithDeadline":
- if x, ok := sel.X.(*ast.Ident); ok {
- if pkgname, ok := f.pkg.uses[x].(*types.PkgName); ok {
- return pkgname.Imported().Path() == contextPackage
- }
- // Import failed, so we can't check package path.
- // Just check the local package name (heuristic).
- return x.Name == "context"
- }
- }
- }
- return false
-}
-
-// lostCancelPath finds a path through the CFG, from stmt (which defines
-// the 'cancel' variable v) to a return statement, that doesn't "use" v.
-// If it finds one, it returns the return statement (which may be synthetic).
-// sig is the function's type, if known.
-func lostCancelPath(f *File, g *cfg.CFG, v *types.Var, stmt ast.Node, sig *types.Signature) *ast.ReturnStmt {
- vIsNamedResult := sig != nil && tupleContains(sig.Results(), v)
-
- // uses reports whether stmts contain a "use" of variable v.
- uses := func(f *File, v *types.Var, stmts []ast.Node) bool {
- found := false
- for _, stmt := range stmts {
- ast.Inspect(stmt, func(n ast.Node) bool {
- switch n := n.(type) {
- case *ast.Ident:
- if f.pkg.uses[n] == v {
- found = true
- }
- case *ast.ReturnStmt:
- // A naked return statement counts as a use
- // of the named result variables.
- if n.Results == nil && vIsNamedResult {
- found = true
- }
- }
- return !found
- })
- }
- return found
- }
-
- // blockUses computes "uses" for each block, caching the result.
- memo := make(map[*cfg.Block]bool)
- blockUses := func(f *File, v *types.Var, b *cfg.Block) bool {
- res, ok := memo[b]
- if !ok {
- res = uses(f, v, b.Nodes)
- memo[b] = res
- }
- return res
- }
-
- // Find the var's defining block in the CFG,
- // plus the rest of the statements of that block.
- var defblock *cfg.Block
- var rest []ast.Node
-outer:
- for _, b := range g.Blocks {
- for i, n := range b.Nodes {
- if n == stmt {
- defblock = b
- rest = b.Nodes[i+1:]
- break outer
- }
- }
- }
- if defblock == nil {
- panic("internal error: can't find defining block for cancel var")
- }
-
- // Is v "used" in the remainder of its defining block?
- if uses(f, v, rest) {
- return nil
- }
-
- // Does the defining block return without using v?
- if ret := defblock.Return(); ret != nil {
- return ret
- }
-
- // Search the CFG depth-first for a path, from defblock to a
- // return block, in which v is never "used".
- seen := make(map[*cfg.Block]bool)
- var search func(blocks []*cfg.Block) *ast.ReturnStmt
- search = func(blocks []*cfg.Block) *ast.ReturnStmt {
- for _, b := range blocks {
- if !seen[b] {
- seen[b] = true
-
- // Prune the search if the block uses v.
- if blockUses(f, v, b) {
- continue
- }
-
- // Found path to return statement?
- if ret := b.Return(); ret != nil {
- if debugLostCancel {
- fmt.Printf("found path to return in block %s\n", b)
- }
- return ret // found
- }
-
- // Recur
- if ret := search(b.Succs); ret != nil {
- if debugLostCancel {
- fmt.Printf(" from block %s\n", b)
- }
- return ret
- }
- }
- }
- return nil
- }
- return search(defblock.Succs)
-}
-
-func tupleContains(tuple *types.Tuple, v *types.Var) bool {
- for i := 0; i < tuple.Len(); i++ {
- if tuple.At(i) == v {
- return true
- }
- }
- return false
-}
-
-var noReturnFuncs = map[string]bool{
- "(*testing.common).FailNow": true,
- "(*testing.common).Fatal": true,
- "(*testing.common).Fatalf": true,
- "(*testing.common).Skip": true,
- "(*testing.common).SkipNow": true,
- "(*testing.common).Skipf": true,
- "log.Fatal": true,
- "log.Fatalf": true,
- "log.Fatalln": true,
- "os.Exit": true,
- "panic": true,
- "runtime.Goexit": true,
-}
-
-// callName returns the canonical name of the builtin, method, or
-// function called by call, if known.
-func callName(info *types.Info, call *ast.CallExpr) string {
- switch fun := call.Fun.(type) {
- case *ast.Ident:
- // builtin, e.g. "panic"
- if obj, ok := info.Uses[fun].(*types.Builtin); ok {
- return obj.Name()
- }
- case *ast.SelectorExpr:
- if sel, ok := info.Selections[fun]; ok && sel.Kind() == types.MethodVal {
- // method call, e.g. "(*testing.common).Fatal"
- meth := sel.Obj()
- return fmt.Sprintf("(%s).%s",
- meth.Type().(*types.Signature).Recv().Type(),
- meth.Name())
- }
- if obj, ok := info.Uses[fun.Sel]; ok {
- // qualified identifier, e.g. "os.Exit"
- return fmt.Sprintf("%s.%s",
- obj.Pkg().Path(),
- obj.Name())
- }
- }
-
- // function with no name, or defined in missing imported package
- return ""
-}
-// 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.
-
+// The vet command is a driver for static checkers conforming to
+// the golang.org/x/tools/go/analysis API. Run it using 'go vet'.
+//
+// For a tool capable of running standalone, use a multichecker-based
+// tool such as golang.org/x/tools/go/analysis/cmd/vet.
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"
- "log"
- "os"
- "path/filepath"
- "sort"
- "strconv"
- "strings"
-
- "cmd/internal/objabi"
-)
-
-var (
- verbose = flag.Bool("v", false, "verbose")
- flags = flag.Bool("flags", false, "print flags in JSON")
- 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
+ "golang.org/x/tools/go/analysis/unitchecker"
+
+ "golang.org/x/tools/go/analysis/passes/asmdecl"
+ "golang.org/x/tools/go/analysis/passes/assign"
+ "golang.org/x/tools/go/analysis/passes/atomic"
+ "golang.org/x/tools/go/analysis/passes/bools"
+ "golang.org/x/tools/go/analysis/passes/buildtag"
+ "golang.org/x/tools/go/analysis/passes/cgocall"
+ "golang.org/x/tools/go/analysis/passes/composite"
+ "golang.org/x/tools/go/analysis/passes/copylock"
+ "golang.org/x/tools/go/analysis/passes/httpresponse"
+ "golang.org/x/tools/go/analysis/passes/loopclosure"
+ "golang.org/x/tools/go/analysis/passes/lostcancel"
+ "golang.org/x/tools/go/analysis/passes/nilfunc"
+ "golang.org/x/tools/go/analysis/passes/pkgfact"
+ "golang.org/x/tools/go/analysis/passes/printf"
+ "golang.org/x/tools/go/analysis/passes/shift"
+ "golang.org/x/tools/go/analysis/passes/stdmethods"
+ "golang.org/x/tools/go/analysis/passes/structtag"
+ "golang.org/x/tools/go/analysis/passes/tests"
+ "golang.org/x/tools/go/analysis/passes/unmarshal"
+ "golang.org/x/tools/go/analysis/passes/unreachable"
+ "golang.org/x/tools/go/analysis/passes/unsafeptr"
+ "golang.org/x/tools/go/analysis/passes/unusedresult"
)
-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
-}
+// Legacy vet had the concept of "experimental" checkers.
+
+// There was exactly one, shadow, and it had to be explicitly
+// enabled by the -shadow flag, which would of course disable
+// all the other tristate flags, requiring the -all flag (which
+// is now a no-op) to reenable them.
+//
+// The shadow analyzer has been removed from the suite,
+// but can be run using these additional commands:
+// $ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
+// $ go vet -vettool=$(which shadow)
+// Alternatively, one could build a multichecker containing all
+// the desired checks (vet's suite + shadow) and run it in a
+// single "go vet" command.
func main() {
- objabi.AddVersionFlag()
- flag.Usage = Usage
- flag.Parse()
-
- // -flags: print flags as JSON. Used by go vet.
- if *flags {
- type jsonFlag struct {
- Name string
- Bool bool
- Usage string
- }
- var jsonFlags []jsonFlag
- flag.VisitAll(func(f *flag.Flag) {
- isBool := false
- switch v := f.Value.(type) {
- case interface{ BoolFlag() bool }:
- isBool = v.BoolFlag()
- case *triState:
- isBool = true // go vet should treat it as boolean
- }
- jsonFlags = append(jsonFlags, jsonFlag{f.Name, isBool, f.Usage})
- })
- data, err := json.MarshalIndent(jsonFlags, "", "\t")
- if err != nil {
- log.Fatal(err)
- }
- os.Stdout.Write(data)
- os.Exit(0)
- }
-
- // 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
- NonGoFiles []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
-
- var allFiles []string
- allFiles = append(allFiles, vcfg.GoFiles...)
- allFiles = append(allFiles, vcfg.NonGoFiles...)
-
- doPackage(allFiles, 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]
+ unitchecker.Main(
+ asmdecl.Analyzer,
+ assign.Analyzer,
+ atomic.Analyzer,
+ bools.Analyzer,
+ buildtag.Analyzer,
+ cgocall.Analyzer,
+ composite.Analyzer,
+ copylock.Analyzer,
+ httpresponse.Analyzer,
+ loopclosure.Analyzer,
+ lostcancel.Analyzer,
+ nilfunc.Analyzer,
+ pkgfact.Analyzer,
+ printf.Analyzer,
+ shift.Analyzer,
+ stdmethods.Analyzer,
+ structtag.Analyzer,
+ tests.Analyzer,
+ unmarshal.Analyzer,
+ unreachable.Analyzer,
+ unsafeptr.Analyzer,
+ unusedresult.Analyzer,
+ )
}
+++ /dev/null
-// 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.
-
-// This file contains the code to check canonical methods.
-
-package main
-
-import (
- "go/ast"
- "go/types"
- "strings"
-)
-
-func init() {
- register("methods",
- "check that canonically named methods are canonically defined",
- checkCanonicalMethod,
- funcDecl, interfaceType)
-}
-
-type MethodSig struct {
- args []string
- results []string
-}
-
-// canonicalMethods lists the input and output types for Go methods
-// that are checked using dynamic interface checks. Because the
-// checks are dynamic, such methods would not cause a compile error
-// if they have the wrong signature: instead the dynamic check would
-// fail, sometimes mysteriously. If a method is found with a name listed
-// here but not the input/output types listed here, vet complains.
-//
-// A few of the canonical methods have very common names.
-// For example, a type might implement a Scan method that
-// has nothing to do with fmt.Scanner, but we still want to check
-// the methods that are intended to implement fmt.Scanner.
-// To do that, the arguments that have a = prefix are treated as
-// signals that the canonical meaning is intended: if a Scan
-// method doesn't have a fmt.ScanState as its first argument,
-// we let it go. But if it does have a fmt.ScanState, then the
-// rest has to match.
-var canonicalMethods = map[string]MethodSig{
- // "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict
- "Format": {[]string{"=fmt.State", "rune"}, []string{}}, // fmt.Formatter
- "GobDecode": {[]string{"[]byte"}, []string{"error"}}, // gob.GobDecoder
- "GobEncode": {[]string{}, []string{"[]byte", "error"}}, // gob.GobEncoder
- "MarshalJSON": {[]string{}, []string{"[]byte", "error"}}, // json.Marshaler
- "MarshalXML": {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler
- "ReadByte": {[]string{}, []string{"byte", "error"}}, // io.ByteReader
- "ReadFrom": {[]string{"=io.Reader"}, []string{"int64", "error"}}, // io.ReaderFrom
- "ReadRune": {[]string{}, []string{"rune", "int", "error"}}, // io.RuneReader
- "Scan": {[]string{"=fmt.ScanState", "rune"}, []string{"error"}}, // fmt.Scanner
- "Seek": {[]string{"=int64", "int"}, []string{"int64", "error"}}, // io.Seeker
- "UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}}, // json.Unmarshaler
- "UnmarshalXML": {[]string{"*xml.Decoder", "xml.StartElement"}, []string{"error"}}, // xml.Unmarshaler
- "UnreadByte": {[]string{}, []string{"error"}},
- "UnreadRune": {[]string{}, []string{"error"}},
- "WriteByte": {[]string{"byte"}, []string{"error"}}, // jpeg.writer (matching bufio.Writer)
- "WriteTo": {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo
-}
-
-func checkCanonicalMethod(f *File, node ast.Node) {
- switch n := node.(type) {
- case *ast.FuncDecl:
- if n.Recv != nil {
- canonicalMethod(f, n.Name)
- }
- case *ast.InterfaceType:
- for _, field := range n.Methods.List {
- for _, id := range field.Names {
- canonicalMethod(f, id)
- }
- }
- }
-}
-
-func canonicalMethod(f *File, id *ast.Ident) {
- // Expected input/output.
- expect, ok := canonicalMethods[id.Name]
- if !ok {
- return
- }
- sign := f.pkg.defs[id].Type().(*types.Signature)
- args := sign.Params()
- results := sign.Results()
-
- // Do the =s (if any) all match?
- if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") {
- return
- }
-
- // Everything must match.
- if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") {
- expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
- if len(expect.results) == 1 {
- expectFmt += " " + argjoin(expect.results)
- } else if len(expect.results) > 1 {
- expectFmt += " (" + argjoin(expect.results) + ")"
- }
-
- actual := sign.String()
- actual = strings.TrimPrefix(actual, "func")
- actual = id.Name + actual
-
- f.Badf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
- }
-}
-
-func argjoin(x []string) string {
- y := make([]string, len(x))
- for i, s := range x {
- if s[0] == '=' {
- s = s[1:]
- }
- y[i] = s
- }
- return strings.Join(y, ", ")
-}
-
-// Does each type in expect with the given prefix match the corresponding type in actual?
-func (f *File) matchParams(expect []string, actual *types.Tuple, prefix string) bool {
- for i, x := range expect {
- if !strings.HasPrefix(x, prefix) {
- continue
- }
- if i >= actual.Len() {
- return false
- }
- if !f.matchParamType(x, actual.At(i).Type()) {
- return false
- }
- }
- if prefix == "" && actual.Len() > len(expect) {
- return false
- }
- return true
-}
-
-// Does this one type match?
-func (f *File) matchParamType(expect string, actual types.Type) bool {
- expect = strings.TrimPrefix(expect, "=")
- // Strip package name if we're in that package.
- if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' {
- expect = expect[n+1:]
- }
-
- // Overkill but easy.
- return actual.String() == expect
-}
+++ /dev/null
-// 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.
-
-/*
-This file contains the code to check for useless function comparisons.
-A useless comparison is one like f == nil as opposed to f() == nil.
-*/
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("nilfunc",
- "check for comparisons between functions and nil",
- checkNilFuncComparison,
- binaryExpr)
-}
-
-func checkNilFuncComparison(f *File, node ast.Node) {
- e := node.(*ast.BinaryExpr)
-
- // Only want == or != comparisons.
- if e.Op != token.EQL && e.Op != token.NEQ {
- return
- }
-
- // Only want comparisons with a nil identifier on one side.
- var e2 ast.Expr
- switch {
- case f.isNil(e.X):
- e2 = e.Y
- case f.isNil(e.Y):
- e2 = e.X
- default:
- return
- }
-
- // Only want identifiers or selector expressions.
- var obj types.Object
- switch v := e2.(type) {
- case *ast.Ident:
- obj = f.pkg.uses[v]
- case *ast.SelectorExpr:
- obj = f.pkg.uses[v.Sel]
- default:
- return
- }
-
- // Only want functions.
- if _, ok := obj.(*types.Func); !ok {
- return
- }
-
- f.Badf(e.Pos(), "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ)
-}
-
-// isNil reports whether the provided expression is the built-in nil
-// identifier.
-func (f *File) isNil(e ast.Expr) bool {
- return f.pkg.types[e].Type == types.Typ[types.UntypedNil]
-}
+++ /dev/null
-// 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.
-
-// This file contains the printf-checker.
-
-package main
-
-import (
- "bytes"
- "encoding/gob"
- "flag"
- "fmt"
- "go/ast"
- "go/constant"
- "go/token"
- "go/types"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "unicode/utf8"
-)
-
-var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
-
-func init() {
- register("printf",
- "check printf-like invocations",
- checkFmtPrintfCall,
- funcDecl, callExpr)
- registerPkgCheck("printf", findPrintfLike)
- registerExport("printf", exportPrintfLike)
- gob.Register([]printfExport(nil))
-}
-
-func initPrintFlags() {
- if *printfuncs == "" {
- return
- }
- for _, name := range strings.Split(*printfuncs, ",") {
- if len(name) == 0 {
- flag.Usage()
- }
-
- // Backwards compatibility: skip optional first argument
- // index after the colon.
- if colon := strings.LastIndex(name, ":"); colon > 0 {
- name = name[:colon]
- }
-
- if !strings.Contains(name, ".") {
- name = strings.ToLower(name)
- }
- isPrint[name] = true
- }
-}
-
-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
- format *ast.Field
- args *ast.Field
- callers []printfCaller
- failed bool // if true, not a printf wrapper
-}
-
-type printfCaller struct {
- w *printfWrapper
- call *ast.CallExpr
-}
-
-// maybePrintfWrapper decides whether decl (a declared function) may be a wrapper
-// around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper
-// function describing the declaration. Later processing will analyze the
-// graph of potential printf wrappers to pick out the ones that are true wrappers.
-// A function may be a Printf or Print wrapper if its last argument is ...interface{}.
-// If the next-to-last argument is a string, then this may be a Printf wrapper.
-// Otherwise it may be a Print wrapper.
-func maybePrintfWrapper(decl ast.Decl) *printfWrapper {
- // Look for functions with final argument type ...interface{}.
- fn, ok := decl.(*ast.FuncDecl)
- if !ok || fn.Body == nil {
- return nil
- }
- name := fn.Name.Name
- if fn.Recv != nil {
- // For (*T).Name or T.name, use "T.name".
- rcvr := fn.Recv.List[0].Type
- if ptr, ok := rcvr.(*ast.StarExpr); ok {
- rcvr = ptr.X
- }
- id, ok := rcvr.(*ast.Ident)
- if !ok {
- return nil
- }
- name = id.Name + "." + name
- }
- params := fn.Type.Params.List
- if len(params) == 0 {
- return nil
- }
- args := params[len(params)-1]
- if len(args.Names) != 1 {
- return nil
- }
- ddd, ok := args.Type.(*ast.Ellipsis)
- if !ok {
- return nil
- }
- iface, ok := ddd.Elt.(*ast.InterfaceType)
- if !ok || len(iface.Methods.List) > 0 {
- return nil
- }
- var format *ast.Field
- if len(params) >= 2 {
- p := params[len(params)-2]
- if len(p.Names) == 1 {
- if id, ok := p.Type.(*ast.Ident); ok && id.Name == "string" {
- format = p
- }
- }
- }
-
- return &printfWrapper{
- name: name,
- fn: fn,
- format: format,
- args: args,
- }
-}
-
-// findPrintfLike scans the entire package to find printf-like functions.
-func findPrintfLike(pkg *Package) {
- if vcfg.ImportPath == "" { // no type or vetx information; don't bother
- return
- }
-
- // Gather potential wrappesr and call graph between them.
- byName := make(map[string]*printfWrapper)
- var wrappers []*printfWrapper
- for _, file := range pkg.files {
- if file.file == nil {
- continue
- }
- for _, decl := range file.file.Decls {
- w := maybePrintfWrapper(decl)
- if w == nil {
- continue
- }
- byName[w.name] = w
- wrappers = append(wrappers, w)
- }
- }
-
- // Walk the graph to figure out which are really printf wrappers.
- for _, w := range wrappers {
- // Scan function for calls that could be to other printf-like functions.
- ast.Inspect(w.fn.Body, func(n ast.Node) bool {
- if w.failed {
- return false
- }
-
- // TODO: Relax these checks; issue 26555.
- if assign, ok := n.(*ast.AssignStmt); ok {
- for _, lhs := range assign.Lhs {
- if match(lhs, w.format) || match(lhs, w.args) {
- // Modifies the format
- // string or args in
- // some way, so not a
- // simple wrapper.
- w.failed = true
- return false
- }
- }
- }
- if un, ok := n.(*ast.UnaryExpr); ok && un.Op == token.AND {
- if match(un.X, w.format) || match(un.X, w.args) {
- // Taking the address of the
- // format string or args,
- // so not a simple wrapper.
- w.failed = true
- return false
- }
- }
-
- call, ok := n.(*ast.CallExpr)
- if !ok || len(call.Args) == 0 || !match(call.Args[len(call.Args)-1], w.args) {
- return true
- }
-
- pkgpath, name, kind := printfNameAndKind(pkg, call.Fun)
- if kind != 0 {
- checkPrintfFwd(pkg, w, call, kind)
- return true
- }
-
- // If the call is to another function in this package,
- // maybe we will find out it is printf-like later.
- // Remember this call for later checking.
- if pkgpath == "" && byName[name] != nil {
- callee := byName[name]
- callee.callers = append(callee.callers, printfCaller{w, call})
- }
-
- return true
- })
- }
-}
-
-func match(arg ast.Expr, param *ast.Field) bool {
- id, ok := arg.(*ast.Ident)
- return ok && id.Obj != nil && id.Obj.Decl == param
-}
-
-const (
- kindPrintf = 1
- kindPrint = 2
-)
-
-// printfLike reports whether a call to fn should be considered a call to a printf-like function.
-// It returns 0 (indicating not a printf-like function), kindPrintf, or kindPrint.
-func printfLike(pkg *Package, fn ast.Expr, byName map[string]*printfWrapper) int {
- if id, ok := fn.(*ast.Ident); ok && id.Obj != nil {
- if w := byName[id.Name]; w != nil && id.Obj.Decl == w.fn {
- // Found call to function in same package.
- return localPrintfLike[id.Name]
- }
- }
- if sel, ok := fn.(*ast.SelectorExpr); ok {
- if id, ok := sel.X.(*ast.Ident); ok && id.Name == "fmt" && strings.Contains(sel.Sel.Name, "rint") {
- if strings.HasSuffix(sel.Sel.Name, "f") {
- return kindPrintf
- }
- return kindPrint
- }
- }
- return 0
-}
-
-// checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly.
-// It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...).
-func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int) {
- matched := kind == kindPrint ||
- kind == kindPrintf && len(call.Args) >= 2 && match(call.Args[len(call.Args)-2], w.format)
- if !matched {
- return
- }
-
- if !call.Ellipsis.IsValid() {
- typ, ok := pkg.types[call.Fun].Type.(*types.Signature)
- if !ok {
- return
- }
- if len(call.Args) > typ.Params().Len() {
- // If we're passing more arguments than what the
- // print/printf function can take, adding an ellipsis
- // would break the program. For example:
- //
- // func foo(arg1 string, arg2 ...interface{} {
- // fmt.Printf("%s %v", arg1, arg2)
- // }
- return
- }
- if !vcfg.VetxOnly {
- desc := "printf"
- if kind == kindPrint {
- desc = "print"
- }
- pkg.files[0].Badf(call.Pos(), "missing ... in args forwarded to %s-like function", desc)
- }
- return
- }
- name := w.name
- if localPrintfLike[name] == 0 {
- localPrintfLike[name] = kind
- for _, caller := range w.callers {
- checkPrintfFwd(pkg, caller.w, caller.call, kind)
- }
- }
-}
-
-func exportPrintfLike() interface{} {
- 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.
-// If a key ends in 'f' then it is assumed to be a formatted print.
-var isPrint = map[string]bool{
- "fmt.Errorf": true,
- "fmt.Fprint": true,
- "fmt.Fprintf": true,
- "fmt.Fprintln": true,
- "fmt.Print": true,
- "fmt.Printf": true,
- "fmt.Println": true,
- "fmt.Sprint": true,
- "fmt.Sprintf": true,
- "fmt.Sprintln": true,
-
- // testing.B, testing.T not auto-detected
- // because the methods are picked up by embedding.
- "testing.B.Error": true,
- "testing.B.Errorf": true,
- "testing.B.Fatal": true,
- "testing.B.Fatalf": true,
- "testing.B.Log": true,
- "testing.B.Logf": true,
- "testing.B.Skip": true,
- "testing.B.Skipf": true,
- "testing.T.Error": true,
- "testing.T.Errorf": true,
- "testing.T.Fatal": true,
- "testing.T.Fatalf": true,
- "testing.T.Log": true,
- "testing.T.Logf": true,
- "testing.T.Skip": true,
- "testing.T.Skipf": true,
-
- // testing.TB is an interface, so can't detect wrapping.
- "testing.TB.Error": true,
- "testing.TB.Errorf": true,
- "testing.TB.Fatal": true,
- "testing.TB.Fatalf": true,
- "testing.TB.Log": true,
- "testing.TB.Logf": true,
- "testing.TB.Skip": true,
- "testing.TB.Skipf": true,
-}
-
-// formatString returns the format string argument and its index within
-// the given printf-like call expression.
-//
-// The last parameter before variadic arguments is assumed to be
-// a format string.
-//
-// The first string literal or string constant is assumed to be a format string
-// if the call's signature cannot be determined.
-//
-// If it cannot find any format string parameter, it returns ("", -1).
-func formatString(f *File, call *ast.CallExpr) (format string, idx int) {
- typ := f.pkg.types[call.Fun].Type
- if typ != nil {
- if sig, ok := typ.(*types.Signature); ok {
- if !sig.Variadic() {
- // Skip checking non-variadic functions.
- return "", -1
- }
- idx := sig.Params().Len() - 2
- if idx < 0 {
- // Skip checking variadic functions without
- // fixed arguments.
- return "", -1
- }
- s, ok := stringConstantArg(f, call, idx)
- if !ok {
- // The last argument before variadic args isn't a string.
- return "", -1
- }
- return s, idx
- }
- }
-
- // Cannot determine call's signature. Fall back to scanning for the first
- // string constant in the call.
- for idx := range call.Args {
- if s, ok := stringConstantArg(f, call, idx); ok {
- return s, idx
- }
- if f.pkg.types[call.Args[idx]].Type == types.Typ[types.String] {
- // Skip checking a call with a non-constant format
- // string argument, since its contents are unavailable
- // for validation.
- return "", -1
- }
- }
- return "", -1
-}
-
-// stringConstantArg returns call's string constant argument at the index idx.
-//
-// ("", false) is returned if call's argument at the index idx isn't a string
-// constant.
-func stringConstantArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
- if idx >= len(call.Args) {
- return "", false
- }
- arg := call.Args[idx]
- lit := f.pkg.types[arg].Value
- if lit != nil && lit.Kind() == constant.String {
- return constant.StringVal(lit), true
- }
- return "", false
-}
-
-// checkCall triggers the print-specific checks if the call invokes a print function.
-func checkFmtPrintfCall(f *File, node ast.Node) {
- if f.pkg.typesPkg == nil {
- // This check now requires type information.
- return
- }
-
- if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) {
- // Remember we saw this.
- if f.stringerPtrs == nil {
- f.stringerPtrs = make(map[*ast.Object]bool)
- }
- if l := d.Recv.List; len(l) == 1 {
- if n := l[0].Names; len(n) == 1 {
- typ := f.pkg.types[l[0].Type]
- _, ptrRecv := typ.Type.(*types.Pointer)
- f.stringerPtrs[n[0].Obj] = ptrRecv
- }
- }
- return
- }
-
- call, ok := node.(*ast.CallExpr)
- if !ok {
- return
- }
-
- // Construct name like pkg.Printf or pkg.Type.Printf for lookup.
- _, name, kind := printfNameAndKind(f.pkg, call.Fun)
- if kind == kindPrintf {
- f.checkPrintf(call, name)
- }
- if kind == kindPrint {
- f.checkPrint(call, name)
- }
-}
-
-func printfName(pkg *Package, called ast.Expr) (pkgpath, name string) {
- switch x := called.(type) {
- case *ast.Ident:
- if fn, ok := pkg.uses[x].(*types.Func); ok {
- if fn.Pkg() == nil || fn.Pkg() == pkg.typesPkg {
- pkgpath = ""
- } else {
- pkgpath = fn.Pkg().Path()
- }
- return pkgpath, x.Name
- }
-
- case *ast.SelectorExpr:
- // Check for "fmt.Printf".
- if id, ok := x.X.(*ast.Ident); ok {
- if pkgName, ok := pkg.uses[id].(*types.PkgName); ok {
- return pkgName.Imported().Path(), x.Sel.Name
- }
- }
-
- // Check for t.Logf where t is a *testing.T.
- if sel := pkg.selectors[x]; sel != nil {
- recv := sel.Recv()
- if p, ok := recv.(*types.Pointer); ok {
- recv = p.Elem()
- }
- if named, ok := recv.(*types.Named); ok {
- obj := named.Obj()
- if obj.Pkg() == nil || obj.Pkg() == pkg.typesPkg {
- pkgpath = ""
- } else {
- pkgpath = obj.Pkg().Path()
- }
- return pkgpath, obj.Name() + "." + x.Sel.Name
- }
- }
- }
- return "", ""
-}
-
-func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kind int) {
- pkgpath, name = printfName(pkg, called)
- if name == "" {
- return pkgpath, name, 0
- }
-
- if pkgpath == "" {
- kind = localPrintfLike[name]
- } else if m, ok := printfImported[pkgpath]; ok {
- kind = m[name]
- } else {
- 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 {
- _, ok := isPrint[pkgpath+"."+name]
- if !ok {
- // Next look up just "printf", for use with -printfuncs.
- short := name[strings.LastIndex(name, ".")+1:]
- _, ok = isPrint[strings.ToLower(short)]
- }
- if ok {
- if strings.HasSuffix(name, "f") {
- kind = kindPrintf
- } else {
- kind = kindPrint
- }
- }
- }
- return pkgpath, name, kind
-}
-
-// isStringer reports whether the provided declaration is a "String() string"
-// method, an implementation of fmt.Stringer.
-func isStringer(f *File, d *ast.FuncDecl) bool {
- return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil &&
- len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 &&
- f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String]
-}
-
-// isFormatter reports whether t satisfies fmt.Formatter.
-// Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt.
-func (f *File) isFormatter(t types.Type) bool {
- return formatterType != nil && types.Implements(t, formatterType)
-}
-
-// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
-// It is constructed by parsePrintfVerb.
-type formatState struct {
- verb rune // the format verb: 'd' for "%d"
- format string // the full format directive from % through verb, "%.3d".
- name string // Printf, Sprintf etc.
- flags []byte // the list of # + etc.
- argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call
- firstArg int // Index of first argument after the format in the Printf call.
- // Used only during parse.
- file *File
- call *ast.CallExpr
- argNum int // Which argument we're expecting to format now.
- hasIndex bool // Whether the argument is indexed.
- indexPending bool // Whether we have an indexed argument that has not resolved.
- nbytes int // number of bytes of the format string consumed.
-}
-
-// checkPrintf checks a call to a formatted print routine such as Printf.
-func (f *File) checkPrintf(call *ast.CallExpr, name string) {
- format, idx := formatString(f, call)
- if idx < 0 {
- if *verbose {
- f.Warn(call.Pos(), "can't check non-constant format in call to", name)
- }
- return
- }
-
- firstArg := idx + 1 // Arguments are immediately after format string.
- if !strings.Contains(format, "%") {
- if len(call.Args) > firstArg {
- f.Badf(call.Pos(), "%s call has arguments but no formatting directives", name)
- }
- return
- }
- // Hard part: check formats against args.
- argNum := firstArg
- maxArgNum := firstArg
- anyIndex := false
- for i, w := 0, 0; i < len(format); i += w {
- w = 1
- if format[i] != '%' {
- continue
- }
- state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum)
- if state == nil {
- return
- }
- w = len(state.format)
- if !f.okPrintfArg(call, state) { // One error per format is enough.
- return
- }
- if state.hasIndex {
- anyIndex = true
- }
- if len(state.argNums) > 0 {
- // Continue with the next sequential argument.
- argNum = state.argNums[len(state.argNums)-1] + 1
- }
- for _, n := range state.argNums {
- if n >= maxArgNum {
- maxArgNum = n + 1
- }
- }
- }
- // Dotdotdot is hard.
- if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
- return
- }
- // If any formats are indexed, extra arguments are ignored.
- if anyIndex {
- return
- }
- // There should be no leftover arguments.
- if maxArgNum != len(call.Args) {
- expect := maxArgNum - firstArg
- numArgs := len(call.Args) - firstArg
- f.Badf(call.Pos(), "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg"))
- }
-}
-
-// parseFlags accepts any printf flags.
-func (s *formatState) parseFlags() {
- for s.nbytes < len(s.format) {
- switch c := s.format[s.nbytes]; c {
- case '#', '0', '+', '-', ' ':
- s.flags = append(s.flags, c)
- s.nbytes++
- default:
- return
- }
- }
-}
-
-// scanNum advances through a decimal number if present.
-func (s *formatState) scanNum() {
- for ; s.nbytes < len(s.format); s.nbytes++ {
- c := s.format[s.nbytes]
- if c < '0' || '9' < c {
- return
- }
- }
-}
-
-// parseIndex scans an index expression. It returns false if there is a syntax error.
-func (s *formatState) parseIndex() bool {
- if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' {
- return true
- }
- // Argument index present.
- s.nbytes++ // skip '['
- start := s.nbytes
- s.scanNum()
- ok := true
- if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
- ok = false
- s.nbytes = strings.Index(s.format, "]")
- if s.nbytes < 0 {
- s.file.Badf(s.call.Pos(), "%s format %s is missing closing ]", s.name, s.format)
- return false
- }
- }
- arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
- if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) {
- s.file.Badf(s.call.Pos(), "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes])
- return false
- }
- s.nbytes++ // skip ']'
- arg := int(arg32)
- arg += s.firstArg - 1 // We want to zero-index the actual arguments.
- s.argNum = arg
- s.hasIndex = true
- s.indexPending = true
- return true
-}
-
-// parseNum scans a width or precision (or *). It returns false if there's a bad index expression.
-func (s *formatState) parseNum() bool {
- if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' {
- if s.indexPending { // Absorb it.
- s.indexPending = false
- }
- s.nbytes++
- s.argNums = append(s.argNums, s.argNum)
- s.argNum++
- } else {
- s.scanNum()
- }
- return true
-}
-
-// parsePrecision scans for a precision. It returns false if there's a bad index expression.
-func (s *formatState) parsePrecision() bool {
- // If there's a period, there may be a precision.
- if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' {
- s.flags = append(s.flags, '.') // Treat precision as a flag.
- s.nbytes++
- if !s.parseIndex() {
- return false
- }
- if !s.parseNum() {
- return false
- }
- }
- return true
-}
-
-// parsePrintfVerb looks the formatting directive that begins the format string
-// and returns a formatState that encodes what the directive wants, without looking
-// at the actual arguments present in the call. The result is nil if there is an error.
-func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
- state := &formatState{
- format: format,
- name: name,
- flags: make([]byte, 0, 5),
- argNum: argNum,
- argNums: make([]int, 0, 1),
- nbytes: 1, // There's guaranteed to be a percent sign.
- firstArg: firstArg,
- file: f,
- call: call,
- }
- // There may be flags.
- state.parseFlags()
- // There may be an index.
- if !state.parseIndex() {
- return nil
- }
- // There may be a width.
- if !state.parseNum() {
- return nil
- }
- // There may be a precision.
- if !state.parsePrecision() {
- return nil
- }
- // Now a verb, possibly prefixed by an index (which we may already have).
- if !state.indexPending && !state.parseIndex() {
- return nil
- }
- if state.nbytes == len(state.format) {
- f.Badf(call.Pos(), "%s format %s is missing verb at end of string", name, state.format)
- return nil
- }
- verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
- state.verb = verb
- state.nbytes += w
- if verb != '%' {
- state.argNums = append(state.argNums, state.argNum)
- }
- state.format = state.format[:state.nbytes]
- return state
-}
-
-// printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.
-type printfArgType int
-
-const (
- argBool printfArgType = 1 << iota
- argInt
- argRune
- argString
- argFloat
- argComplex
- argPointer
- anyType printfArgType = ^0
-)
-
-type printVerb struct {
- verb rune // User may provide verb through Formatter; could be a rune.
- flags string // known flags are all ASCII
- typ printfArgType
-}
-
-// Common flag sets for printf verbs.
-const (
- noFlag = ""
- numFlag = " -+.0"
- sharpNumFlag = " -+.0#"
- allFlags = " -+.0#"
-)
-
-// printVerbs identifies which flags are known to printf for each verb.
-var printVerbs = []printVerb{
- // '-' is a width modifier, always valid.
- // '.' is a precision for float, max width for strings.
- // '+' is required sign for numbers, Go format for %v.
- // '#' is alternate format for several verbs.
- // ' ' is spacer for numbers
- {'%', noFlag, 0},
- {'b', numFlag, argInt | argFloat | argComplex},
- {'c', "-", argRune | argInt},
- {'d', numFlag, argInt | argPointer},
- {'e', sharpNumFlag, argFloat | argComplex},
- {'E', sharpNumFlag, argFloat | argComplex},
- {'f', sharpNumFlag, argFloat | argComplex},
- {'F', sharpNumFlag, argFloat | argComplex},
- {'g', sharpNumFlag, argFloat | argComplex},
- {'G', sharpNumFlag, argFloat | argComplex},
- {'o', sharpNumFlag, argInt},
- {'p', "-#", argPointer},
- {'q', " -+.0#", argRune | argInt | argString},
- {'s', " -+.0", argString},
- {'t', "-", argBool},
- {'T', "-", anyType},
- {'U', "-#", argRune | argInt},
- {'v', allFlags, anyType},
- {'x', sharpNumFlag, argRune | argInt | argString | argPointer},
- {'X', sharpNumFlag, argRune | argInt | argString | argPointer},
-}
-
-// okPrintfArg compares the formatState to the arguments actually present,
-// reporting any discrepancies it can discern. If the final argument is ellipsissed,
-// there's little it can do for that.
-func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
- var v printVerb
- found := false
- // Linear scan is fast enough for a small list.
- for _, v = range printVerbs {
- if v.verb == state.verb {
- found = true
- break
- }
- }
-
- // Does current arg implement fmt.Formatter?
- formatter := false
- if state.argNum < len(call.Args) {
- if tv, ok := f.pkg.types[call.Args[state.argNum]]; ok {
- formatter = f.isFormatter(tv.Type)
- }
- }
-
- if !formatter {
- if !found {
- f.Badf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb)
- return false
- }
- for _, flag := range state.flags {
- // TODO: Disable complaint about '0' for Go 1.10. To be fixed properly in 1.11.
- // See issues 23598 and 23605.
- if flag == '0' {
- continue
- }
- if !strings.ContainsRune(v.flags, rune(flag)) {
- f.Badf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag)
- return false
- }
- }
- }
- // Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all
- // but the final arg must be an integer.
- trueArgs := 1
- if state.verb == '%' {
- trueArgs = 0
- }
- nargs := len(state.argNums)
- for i := 0; i < nargs-trueArgs; i++ {
- argNum := state.argNums[i]
- if !f.argCanBeChecked(call, i, state) {
- return
- }
- arg := call.Args[argNum]
- if !f.matchArgType(argInt, nil, arg) {
- f.Badf(call.Pos(), "%s format %s uses non-int %s as argument of *", state.name, state.format, f.gofmt(arg))
- return false
- }
- }
- if state.verb == '%' || formatter {
- return true
- }
- argNum := state.argNums[len(state.argNums)-1]
- if !f.argCanBeChecked(call, len(state.argNums)-1, state) {
- return false
- }
- arg := call.Args[argNum]
- if f.isFunctionValue(arg) && state.verb != 'p' && state.verb != 'T' {
- f.Badf(call.Pos(), "%s format %s arg %s is a func value, not called", state.name, state.format, f.gofmt(arg))
- return false
- }
- if !f.matchArgType(v.typ, nil, arg) {
- typeString := ""
- if typ := f.pkg.types[arg].Type; typ != nil {
- typeString = typ.String()
- }
- f.Badf(call.Pos(), "%s format %s has arg %s of wrong type %s", state.name, state.format, f.gofmt(arg), typeString)
- return false
- }
- if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) {
- f.Badf(call.Pos(), "%s format %s with arg %s causes recursive String method call", state.name, state.format, f.gofmt(arg))
- return false
- }
- return true
-}
-
-// recursiveStringer reports whether the provided argument is r or &r for the
-// fmt.Stringer receiver identifier r.
-func (f *File) recursiveStringer(e ast.Expr) bool {
- if len(f.stringerPtrs) == 0 {
- return false
- }
- ptr := false
- var obj *ast.Object
- switch e := e.(type) {
- case *ast.Ident:
- obj = e.Obj
- case *ast.UnaryExpr:
- if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND {
- obj = id.Obj
- ptr = true
- }
- }
-
- // It's unlikely to be a recursive stringer if it has a Format method.
- if typ := f.pkg.types[e].Type; typ != nil {
- if f.isFormatter(typ) {
- return false
- }
- }
-
- // We compare the underlying Object, which checks that the identifier
- // is the one we declared as the receiver for the String method in
- // which this printf appears.
- ptrRecv, exist := f.stringerPtrs[obj]
- if !exist {
- return false
- }
- // We also need to check that using &t when we declared String
- // on (t *T) is ok; in such a case, the address is printed.
- if ptr && ptrRecv {
- return false
- }
- return true
-}
-
-// isFunctionValue reports whether the expression is a function as opposed to a function call.
-// It is almost always a mistake to print a function value.
-func (f *File) isFunctionValue(e ast.Expr) bool {
- if typ := f.pkg.types[e].Type; typ != nil {
- _, ok := typ.(*types.Signature)
- return ok
- }
- return false
-}
-
-// argCanBeChecked reports whether the specified argument is statically present;
-// it may be beyond the list of arguments or in a terminal slice... argument, which
-// means we can't see it.
-func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, state *formatState) bool {
- argNum := state.argNums[formatArg]
- if argNum <= 0 {
- // Shouldn't happen, so catch it with prejudice.
- panic("negative arg num")
- }
- if argNum < len(call.Args)-1 {
- return true // Always OK.
- }
- if call.Ellipsis.IsValid() {
- return false // We just can't tell; there could be many more arguments.
- }
- if argNum < len(call.Args) {
- return true
- }
- // There are bad indexes in the format or there are fewer arguments than the format needs.
- // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
- arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
- f.Badf(call.Pos(), "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
- return false
-}
-
-// printFormatRE is the regexp we match and report as a possible format string
-// in the first argument to unformatted prints like fmt.Print.
-// We exclude the space flag, so that printing a string like "x % y" is not reported as a format.
-var printFormatRE = regexp.MustCompile(`%` + flagsRE + numOptRE + `\.?` + numOptRE + indexOptRE + verbRE)
-
-const (
- flagsRE = `[+\-#]*`
- indexOptRE = `(\[[0-9]+\])?`
- numOptRE = `([0-9]+|` + indexOptRE + `\*)?`
- verbRE = `[bcdefgopqstvxEFGTUX]`
-)
-
-// checkPrint checks a call to an unformatted print routine such as Println.
-func (f *File) checkPrint(call *ast.CallExpr, name string) {
- firstArg := 0
- typ := f.pkg.types[call.Fun].Type
- if typ == nil {
- // Skip checking functions with unknown type.
- return
- }
- if sig, ok := typ.(*types.Signature); ok {
- if !sig.Variadic() {
- // Skip checking non-variadic functions.
- return
- }
- params := sig.Params()
- firstArg = params.Len() - 1
-
- typ := params.At(firstArg).Type()
- typ = typ.(*types.Slice).Elem()
- it, ok := typ.(*types.Interface)
- if !ok || !it.Empty() {
- // Skip variadic functions accepting non-interface{} args.
- return
- }
- }
- args := call.Args
- if len(args) <= firstArg {
- // Skip calls without variadic args.
- return
- }
- args = args[firstArg:]
-
- if firstArg == 0 {
- if sel, ok := call.Args[0].(*ast.SelectorExpr); ok {
- if x, ok := sel.X.(*ast.Ident); ok {
- if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
- f.Badf(call.Pos(), "%s does not take io.Writer but has first arg %s", name, f.gofmt(call.Args[0]))
- }
- }
- }
- }
-
- arg := args[0]
- if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
- // Ignore trailing % character in lit.Value.
- // The % in "abc 0.0%" couldn't be a formatting directive.
- s := strings.TrimSuffix(lit.Value, `%"`)
- if strings.Contains(s, "%") {
- m := printFormatRE.FindStringSubmatch(s)
- if m != nil {
- f.Badf(call.Pos(), "%s call has possible formatting directive %s", name, m[0])
- }
- }
- }
- if strings.HasSuffix(name, "ln") {
- // The last item, if a string, should not have a newline.
- arg = args[len(args)-1]
- if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
- str, _ := strconv.Unquote(lit.Value)
- if strings.HasSuffix(str, "\n") {
- f.Badf(call.Pos(), "%s arg list ends with redundant newline", name)
- }
- }
- }
- for _, arg := range args {
- if f.isFunctionValue(arg) {
- f.Badf(call.Pos(), "%s arg %s is a func value, not called", name, f.gofmt(arg))
- }
- if f.recursiveStringer(arg) {
- f.Badf(call.Pos(), "%s arg %s causes recursive call to String method", name, f.gofmt(arg))
- }
- }
-}
-
-// count(n, what) returns "1 what" or "N whats"
-// (assuming the plural of what is whats).
-func count(n int, what string) string {
- if n == 1 {
- return "1 " + what
- }
- return fmt.Sprintf("%d %ss", n, what)
-}
+++ /dev/null
-// Copyright 2012 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.
-
-/*
-This file contains the code to check range loop variables bound inside function
-literals that are deferred or launched in new goroutines. We only check
-instances where the defer or go statement is the last statement in the loop
-body, as otherwise we would need whole program analysis.
-
-For example:
-
- for i, v := range s {
- go func() {
- println(i, v) // not what you might expect
- }()
- }
-
-See: https://golang.org/doc/go_faq.html#closures_and_goroutines
-*/
-
-package main
-
-import "go/ast"
-
-func init() {
- register("rangeloops",
- "check that loop variables are used correctly",
- checkLoop,
- rangeStmt, forStmt)
-}
-
-// checkLoop walks the body of the provided loop statement, checking whether
-// its index or value variables are used unsafely inside goroutines or deferred
-// function literals.
-func checkLoop(f *File, node ast.Node) {
- // Find the variables updated by the loop statement.
- var vars []*ast.Ident
- addVar := func(expr ast.Expr) {
- if id, ok := expr.(*ast.Ident); ok {
- vars = append(vars, id)
- }
- }
- var body *ast.BlockStmt
- switch n := node.(type) {
- case *ast.RangeStmt:
- body = n.Body
- addVar(n.Key)
- addVar(n.Value)
- case *ast.ForStmt:
- body = n.Body
- switch post := n.Post.(type) {
- case *ast.AssignStmt:
- // e.g. for p = head; p != nil; p = p.next
- for _, lhs := range post.Lhs {
- addVar(lhs)
- }
- case *ast.IncDecStmt:
- // e.g. for i := 0; i < n; i++
- addVar(post.X)
- }
- }
- if vars == nil {
- return
- }
-
- // Inspect a go or defer statement
- // if it's the last one in the loop body.
- // (We give up if there are following statements,
- // because it's hard to prove go isn't followed by wait,
- // or defer by return.)
- if len(body.List) == 0 {
- return
- }
- var last *ast.CallExpr
- switch s := body.List[len(body.List)-1].(type) {
- case *ast.GoStmt:
- last = s.Call
- case *ast.DeferStmt:
- last = s.Call
- default:
- return
- }
- lit, ok := last.Fun.(*ast.FuncLit)
- if !ok {
- return
- }
- ast.Inspect(lit.Body, func(n ast.Node) bool {
- id, ok := n.(*ast.Ident)
- if !ok || id.Obj == nil {
- return true
- }
- if f.pkg.types[id].Type == nil {
- // Not referring to a variable (e.g. struct field name)
- return true
- }
- for _, v := range vars {
- if v.Obj == id.Obj {
- f.Badf(id.Pos(), "loop variable %s captured by func literal",
- id.Name)
- }
- }
- return true
- })
-}
+++ /dev/null
-// 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.
-
-/*
-This file contains the code to check for shadowed variables.
-A shadowed variable is a variable declared in an inner scope
-with the same name and type as a variable in an outer scope,
-and where the outer variable is mentioned after the inner one
-is declared.
-
-(This definition can be refined; the module generates too many
-false positives and is not yet enabled by default.)
-
-For example:
-
- func BadRead(f *os.File, buf []byte) error {
- var err error
- for {
- n, err := f.Read(buf) // shadows the function variable 'err'
- if err != nil {
- break // causes return of wrong value
- }
- foo(buf)
- }
- return err
- }
-
-*/
-
-package main
-
-import (
- "flag"
- "go/ast"
- "go/token"
- "go/types"
-)
-
-var strictShadowing = flag.Bool("shadowstrict", false, "whether to be strict about shadowing; can be noisy")
-
-func init() {
- register("shadow",
- "check for shadowed variables (experimental; must be set explicitly)",
- checkShadow,
- assignStmt, genDecl)
- experimental["shadow"] = true
-}
-
-func checkShadow(f *File, node ast.Node) {
- switch n := node.(type) {
- case *ast.AssignStmt:
- checkShadowAssignment(f, n)
- case *ast.GenDecl:
- checkShadowDecl(f, n)
- }
-}
-
-// Span stores the minimum range of byte positions in the file in which a
-// given variable (types.Object) is mentioned. It is lexically defined: it spans
-// from the beginning of its first mention to the end of its last mention.
-// A variable is considered shadowed (if *strictShadowing is off) only if the
-// shadowing variable is declared within the span of the shadowed variable.
-// In other words, if a variable is shadowed but not used after the shadowed
-// variable is declared, it is inconsequential and not worth complaining about.
-// This simple check dramatically reduces the nuisance rate for the shadowing
-// check, at least until something cleverer comes along.
-//
-// One wrinkle: A "naked return" is a silent use of a variable that the Span
-// will not capture, but the compilers catch naked returns of shadowed
-// variables so we don't need to.
-//
-// Cases this gets wrong (TODO):
-// - If a for loop's continuation statement mentions a variable redeclared in
-// the block, we should complain about it but don't.
-// - A variable declared inside a function literal can falsely be identified
-// as shadowing a variable in the outer function.
-//
-type Span struct {
- min token.Pos
- max token.Pos
-}
-
-// contains reports whether the position is inside the span.
-func (s Span) contains(pos token.Pos) bool {
- return s.min <= pos && pos < s.max
-}
-
-// growSpan expands the span for the object to contain the source range [pos, end).
-func (pkg *Package) growSpan(obj types.Object, pos, end token.Pos) {
- if *strictShadowing {
- return // No need
- }
- span, ok := pkg.spans[obj]
- if ok {
- if span.min > pos {
- span.min = pos
- }
- if span.max < end {
- span.max = end
- }
- } else {
- span = Span{pos, end}
- }
- pkg.spans[obj] = span
-}
-
-// checkShadowAssignment checks for shadowing in a short variable declaration.
-func checkShadowAssignment(f *File, a *ast.AssignStmt) {
- if a.Tok != token.DEFINE {
- return
- }
- if f.idiomaticShortRedecl(a) {
- return
- }
- for _, expr := range a.Lhs {
- ident, ok := expr.(*ast.Ident)
- if !ok {
- f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
- return
- }
- checkShadowing(f, ident)
- }
-}
-
-// idiomaticShortRedecl reports whether this short declaration can be ignored for
-// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
-func (f *File) idiomaticShortRedecl(a *ast.AssignStmt) bool {
- // Don't complain about deliberate redeclarations of the form
- // i := i
- // Such constructs are idiomatic in range loops to create a new variable
- // for each iteration. Another example is
- // switch n := n.(type)
- if len(a.Rhs) != len(a.Lhs) {
- return false
- }
- // We know it's an assignment, so the LHS must be all identifiers. (We check anyway.)
- for i, expr := range a.Lhs {
- lhs, ok := expr.(*ast.Ident)
- if !ok {
- f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
- return true // Don't do any more processing.
- }
- switch rhs := a.Rhs[i].(type) {
- case *ast.Ident:
- if lhs.Name != rhs.Name {
- return false
- }
- case *ast.TypeAssertExpr:
- if id, ok := rhs.X.(*ast.Ident); ok {
- if lhs.Name != id.Name {
- return false
- }
- }
- default:
- return false
- }
- }
- return true
-}
-
-// idiomaticRedecl reports whether this declaration spec can be ignored for
-// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
-func (f *File) idiomaticRedecl(d *ast.ValueSpec) bool {
- // Don't complain about deliberate redeclarations of the form
- // var i, j = i, j
- if len(d.Names) != len(d.Values) {
- return false
- }
- for i, lhs := range d.Names {
- if rhs, ok := d.Values[i].(*ast.Ident); ok {
- if lhs.Name != rhs.Name {
- return false
- }
- }
- }
- return true
-}
-
-// checkShadowDecl checks for shadowing in a general variable declaration.
-func checkShadowDecl(f *File, d *ast.GenDecl) {
- if d.Tok != token.VAR {
- return
- }
- for _, spec := range d.Specs {
- valueSpec, ok := spec.(*ast.ValueSpec)
- if !ok {
- f.Badf(spec.Pos(), "invalid AST: var GenDecl not ValueSpec")
- return
- }
- // Don't complain about deliberate redeclarations of the form
- // var i = i
- if f.idiomaticRedecl(valueSpec) {
- return
- }
- for _, ident := range valueSpec.Names {
- checkShadowing(f, ident)
- }
- }
-}
-
-// checkShadowing checks whether the identifier shadows an identifier in an outer scope.
-func checkShadowing(f *File, ident *ast.Ident) {
- if ident.Name == "_" {
- // Can't shadow the blank identifier.
- return
- }
- obj := f.pkg.defs[ident]
- if obj == nil {
- return
- }
- // obj.Parent.Parent is the surrounding scope. If we can find another declaration
- // starting from there, we have a shadowed identifier.
- _, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos())
- if shadowed == nil {
- return
- }
- // Don't complain if it's shadowing a universe-declared identifier; that's fine.
- if shadowed.Parent() == types.Universe {
- return
- }
- if *strictShadowing {
- // The shadowed identifier must appear before this one to be an instance of shadowing.
- if shadowed.Pos() > ident.Pos() {
- return
- }
- } else {
- // Don't complain if the span of validity of the shadowed identifier doesn't include
- // the shadowing identifier.
- span, ok := f.pkg.spans[shadowed]
- if !ok {
- f.Badf(shadowed.Pos(), "internal error: no range for %q", shadowed.Name())
- return
- }
- if !span.contains(ident.Pos()) {
- return
- }
- }
- // Don't complain if the types differ: that implies the programmer really wants two different things.
- if types.Identical(obj.Type(), shadowed.Type()) {
- f.Badf(ident.Pos(), "declaration of %q shadows declaration at %s", obj.Name(), f.loc(shadowed.Pos()))
- }
-}
+++ /dev/null
-// Copyright 2014 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.
-
-/*
-This file contains the code to check for suspicious shifts.
-*/
-
-package main
-
-import (
- "go/ast"
- "go/constant"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("shift",
- "check for useless shifts",
- checkShift,
- binaryExpr, assignStmt)
-}
-
-func checkShift(f *File, node ast.Node) {
- if f.dead[node] {
- // Skip shift checks on unreachable nodes.
- return
- }
-
- switch node := node.(type) {
- case *ast.BinaryExpr:
- if node.Op == token.SHL || node.Op == token.SHR {
- checkLongShift(f, node, node.X, node.Y)
- }
- case *ast.AssignStmt:
- if len(node.Lhs) != 1 || len(node.Rhs) != 1 {
- return
- }
- if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN {
- checkLongShift(f, node, node.Lhs[0], node.Rhs[0])
- }
- }
-}
-
-// checkLongShift checks if shift or shift-assign operations shift by more than
-// the length of the underlying variable.
-func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
- if f.pkg.types[x].Value != nil {
- // Ignore shifts of constants.
- // These are frequently used for bit-twiddling tricks
- // like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
- return
- }
-
- v := f.pkg.types[y].Value
- if v == nil {
- return
- }
- amt, ok := constant.Int64Val(v)
- if !ok {
- return
- }
- t := f.pkg.types[x].Type
- if t == nil {
- return
- }
- b, ok := t.Underlying().(*types.Basic)
- if !ok {
- return
- }
- var size int64
- switch b.Kind() {
- case types.Uint8, types.Int8:
- size = 8
- case types.Uint16, types.Int16:
- size = 16
- case types.Uint32, types.Int32:
- size = 32
- case types.Uint64, types.Int64:
- size = 64
- case types.Int, types.Uint:
- size = uintBitSize
- case types.Uintptr:
- size = uintptrBitSize
- default:
- return
- }
- if amt >= size {
- ident := f.gofmt(x)
- f.Badf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
- }
-}
-
-var (
- uintBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uint])
- uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
-)
+++ /dev/null
-// 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.
-
-// This file contains the test for canonical struct tags.
-
-package main
-
-import (
- "errors"
- "go/ast"
- "go/token"
- "go/types"
- "reflect"
- "strconv"
- "strings"
-)
-
-func init() {
- register("structtags",
- "check that struct field tags have canonical format and apply to exported fields as needed",
- checkStructFieldTags,
- structType)
-}
-
-// checkStructFieldTags checks all the field tags of a struct, including checking for duplicates.
-func checkStructFieldTags(f *File, node ast.Node) {
- astType := node.(*ast.StructType)
- typ := f.pkg.types[astType].Type.(*types.Struct)
- var seen map[[2]string]token.Pos
- for i := 0; i < typ.NumFields(); i++ {
- field := typ.Field(i)
- tag := typ.Tag(i)
- checkCanonicalFieldTag(f, astType, field, tag, &seen)
- }
-}
-
-var checkTagDups = []string{"json", "xml"}
-var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true}
-
-// checkCanonicalFieldTag checks a single struct field tag.
-// top is the top-level struct type that is currently being checked.
-func checkCanonicalFieldTag(f *File, top *ast.StructType, field *types.Var, tag string, seen *map[[2]string]token.Pos) {
- for _, key := range checkTagDups {
- checkTagDuplicates(f, tag, key, field, field, seen)
- }
-
- if err := validateStructTag(tag); err != nil {
- f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", tag, err)
- }
-
- // Check for use of json or xml tags with unexported fields.
-
- // Embedded struct. Nothing to do for now, but that
- // may change, depending on what happens with issue 7363.
- if field.Anonymous() {
- return
- }
-
- if field.Exported() {
- return
- }
-
- for _, enc := range [...]string{"json", "xml"} {
- if reflect.StructTag(tag).Get(enc) != "" {
- f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Name(), enc)
- return
- }
- }
-}
-
-// checkTagDuplicates checks a single struct field tag to see if any tags are
-// duplicated. nearest is the field that's closest to the field being checked,
-// while still being part of the top-level struct type.
-func checkTagDuplicates(f *File, tag, key string, nearest, field *types.Var, seen *map[[2]string]token.Pos) {
- val := reflect.StructTag(tag).Get(key)
- if val == "-" {
- // Ignored, even if the field is anonymous.
- return
- }
- if val == "" || val[0] == ',' {
- if field.Anonymous() {
- typ, ok := field.Type().Underlying().(*types.Struct)
- if !ok {
- return
- }
- for i := 0; i < typ.NumFields(); i++ {
- field := typ.Field(i)
- if !field.Exported() {
- continue
- }
- tag := typ.Tag(i)
- checkTagDuplicates(f, tag, key, nearest, field, seen)
- }
- }
- // Ignored if the field isn't anonymous.
- return
- }
- if key == "xml" && field.Name() == "XMLName" {
- // XMLName defines the XML element name of the struct being
- // checked. That name cannot collide with element or attribute
- // names defined on other fields of the struct. Vet does not have a
- // check for untagged fields of type struct defining their own name
- // by containing a field named XMLName; see issue 18256.
- return
- }
- if i := strings.Index(val, ","); i >= 0 {
- if key == "xml" {
- // Use a separate namespace for XML attributes.
- for _, opt := range strings.Split(val[i:], ",") {
- if opt == "attr" {
- key += " attribute" // Key is part of the error message.
- break
- }
- }
- }
- val = val[:i]
- }
- if *seen == nil {
- *seen = map[[2]string]token.Pos{}
- }
- if pos, ok := (*seen)[[2]string{key, val}]; ok {
- f.Badf(nearest.Pos(), "struct field %s repeats %s tag %q also at %s", field.Name(), key, val, f.loc(pos))
- } else {
- (*seen)[[2]string{key, val}] = field.Pos()
- }
-}
-
-var (
- errTagSyntax = errors.New("bad syntax for struct tag pair")
- errTagKeySyntax = errors.New("bad syntax for struct tag key")
- errTagValueSyntax = errors.New("bad syntax for struct tag value")
- errTagValueSpace = errors.New("suspicious space in struct tag value")
- errTagSpace = errors.New("key:\"value\" pairs not separated by spaces")
-)
-
-// validateStructTag parses the struct tag and returns an error if it is not
-// in the canonical format, which is a space-separated list of key:"value"
-// settings. The value may contain spaces.
-func validateStructTag(tag string) error {
- // This code is based on the StructTag.Get code in package reflect.
-
- n := 0
- for ; tag != ""; n++ {
- if n > 0 && tag != "" && tag[0] != ' ' {
- // More restrictive than reflect, but catches likely mistakes
- // like `x:"foo",y:"bar"`, which parses as `x:"foo" ,y:"bar"` with second key ",y".
- return errTagSpace
- }
- // Skip leading space.
- i := 0
- for i < len(tag) && tag[i] == ' ' {
- i++
- }
- tag = tag[i:]
- if tag == "" {
- break
- }
-
- // Scan to colon. A space, a quote or a control character is a syntax error.
- // Strictly speaking, control chars include the range [0x7f, 0x9f], not just
- // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
- // as it is simpler to inspect the tag's bytes than the tag's runes.
- i = 0
- for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
- i++
- }
- if i == 0 {
- return errTagKeySyntax
- }
- if i+1 >= len(tag) || tag[i] != ':' {
- return errTagSyntax
- }
- if tag[i+1] != '"' {
- return errTagValueSyntax
- }
- key := tag[:i]
- tag = tag[i+1:]
-
- // Scan quoted string to find value.
- i = 1
- for i < len(tag) && tag[i] != '"' {
- if tag[i] == '\\' {
- i++
- }
- i++
- }
- if i >= len(tag) {
- return errTagValueSyntax
- }
- qvalue := tag[:i+1]
- tag = tag[i+1:]
-
- value, err := strconv.Unquote(qvalue)
- if err != nil {
- return errTagValueSyntax
- }
-
- if !checkTagSpaces[key] {
- continue
- }
-
- switch key {
- case "xml":
- // If the first or last character in the XML tag is a space, it is
- // suspicious.
- if strings.Trim(value, " ") != value {
- return errTagValueSpace
- }
-
- // If there are multiple spaces, they are suspicious.
- if strings.Count(value, " ") > 1 {
- return errTagValueSpace
- }
-
- // If there is no comma, skip the rest of the checks.
- comma := strings.IndexRune(value, ',')
- if comma < 0 {
- continue
- }
-
- // If the character before a comma is a space, this is suspicious.
- if comma > 0 && value[comma-1] == ' ' {
- return errTagValueSpace
- }
- value = value[comma+1:]
- case "json":
- // JSON allows using spaces in the name, so skip it.
- comma := strings.IndexRune(value, ',')
- if comma < 0 {
- continue
- }
- value = value[comma+1:]
- }
-
- if strings.IndexByte(value, ' ') >= 0 {
- return errTagValueSpace
- }
- }
- return nil
-}
+++ /dev/null
-// 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.
-
-// +build ignore
-
-// This file contains declarations to test the assembly in test_asm.s.
-
-package testdata
-
-type S struct {
- i int32
- b bool
- s string
-}
-
-func arg1(x int8, y uint8)
-func arg2(x int16, y uint16)
-func arg4(x int32, y uint32)
-func arg8(x int64, y uint64)
-func argint(x int, y uint)
-func argptr(x *byte, y *byte, c chan int, m map[int]int, f func())
-func argstring(x, y string)
-func argslice(x, y []string)
-func argiface(x interface{}, y interface {
- m()
-})
-func argcomplex(x complex64, y complex128)
-func argstruct(x S, y struct{})
-func argarray(x [2]S)
-func returnint() int
-func returnbyte(x int) byte
-func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte)
-func returnintmissing() int
-func leaf(x, y int) int
-
-func noprof(x int)
-func dupok(x int)
-func nosplit(x int)
-func rodata(x int)
-func noptr(x int)
-func wrapper(x int)
-
-func f15271() (x uint32)
-func f17584(x float32, y complex64)
-
-func noframe1(x int32)
-func noframe2(x int32)
+++ /dev/null
-// 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.
-
-// +build amd64
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), AX
- // MOVB x+0(FP), AX // commented out instructions used to panic
- MOVB y+1(FP), BX
- MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
- MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
- MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- TESTB x+0(FP), AX
- TESTB y+1(FP), BX
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
- TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
- TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
- TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
- TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 8(SP), AX // ERROR "8\(SP\) should be x\+0\(FP\)"
- MOVB 9(SP), AX // ERROR "9\(SP\) should be y\+1\(FP\)"
- MOVB 10(SP), AX // ERROR "use of 10\(SP\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+0(FP), AX
- MOVW y+2(FP), BX
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
- MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
- MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
- TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+0(FP), AX
- TESTW y+2(FP), BX
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
- TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
- TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVL c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value"
- MOVL m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVL f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value"
- MOVQ x_base+0(FP), AX
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value"
- MOVQ x_len+8(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value"
- MOVQ x_base+0(FP), AX
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value"
- MOVQ x_len+8(FP), AX
- MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVL x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVQ x_cap+16(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVQ y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVL x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value"
- MOVQ x_type+0(FP), AX
- MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVL x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value"
- MOVQ x_data+8(FP), AX
- MOVW y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVL y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value"
- MOVQ y+16(FP), AX
- MOVW y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVL y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVQ y_itable+16(FP), AX
- MOVQ y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVW y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVL y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVQ y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVL y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value"
- MOVQ y_data+24(FP), AX
- RET
-
-TEXT ·argcomplex(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVSS x+0(FP), X0 // ERROR "invalid MOVSS of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)"
- MOVSD x+0(FP), X0 // ERROR "invalid MOVSD of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)"
- MOVSS x_real+0(FP), X0
- MOVSD x_real+0(FP), X0 // ERROR "invalid MOVSD of x_real\+0\(FP\); real\(complex64\) is 4-byte value"
- MOVSS x_real+4(FP), X0 // ERROR "invalid offset x_real\+4\(FP\); expected x_real\+0\(FP\)"
- MOVSS x_imag+4(FP), X0
- MOVSD x_imag+4(FP), X0 // ERROR "invalid MOVSD of x_imag\+4\(FP\); imag\(complex64\) is 4-byte value"
- MOVSS x_imag+8(FP), X0 // ERROR "invalid offset x_imag\+8\(FP\); expected x_imag\+4\(FP\)"
- MOVSD y+8(FP), X0 // ERROR "invalid MOVSD of y\+8\(FP\); complex128 is 16-byte value containing y_real\+8\(FP\) and y_imag\+16\(FP\)"
- MOVSS y_real+8(FP), X0 // ERROR "invalid MOVSS of y_real\+8\(FP\); real\(complex128\) is 8-byte value"
- MOVSD y_real+8(FP), X0
- MOVSS y_real+16(FP), X0 // ERROR "invalid offset y_real\+16\(FP\); expected y_real\+8\(FP\)"
- MOVSS y_imag+16(FP), X0 // ERROR "invalid MOVSS of y_imag\+16\(FP\); imag\(complex128\) is 8-byte value"
- MOVSD y_imag+16(FP), X0
- MOVSS y_imag+24(FP), X0 // ERROR "invalid offset y_imag\+24\(FP\); expected y_imag\+16\(FP\)"
- RET
-
-TEXT ·argstruct(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); testdata.S is 24-byte value"
- MOVQ x_i+0(FP), AX // ERROR "invalid MOVQ of x_i\+0\(FP\); int32 is 4-byte value"
- MOVQ x_b+0(FP), AX // ERROR "invalid offset x_b\+0\(FP\); expected x_b\+4\(FP\)"
- MOVQ x_s+8(FP), AX
- MOVQ x_s_base+8(FP), AX
- MOVQ x_s+16(FP), AX // ERROR "invalid offset x_s\+16\(FP\); expected x_s\+8\(FP\), x_s_base\+8\(FP\), or x_s_len\+16\(FP\)"
- MOVQ x_s_len+16(FP), AX
- RET
-
-TEXT ·argarray(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \[2\]testdata.S is 48-byte value"
- MOVQ x_0_i+0(FP), AX // ERROR "invalid MOVQ of x_0_i\+0\(FP\); int32 is 4-byte value"
- MOVQ x_0_b+0(FP), AX // ERROR "invalid offset x_0_b\+0\(FP\); expected x_0_b\+4\(FP\)"
- MOVQ x_0_s+8(FP), AX
- MOVQ x_0_s_base+8(FP), AX
- MOVQ x_0_s+16(FP), AX // ERROR "invalid offset x_0_s\+16\(FP\); expected x_0_s\+8\(FP\), x_0_s_base\+8\(FP\), or x_0_s_len\+16\(FP\)"
- MOVQ x_0_s_len+16(FP), AX
- MOVB foo+25(FP), AX // ERROR "unknown variable foo; offset 25 is x_1_i\+24\(FP\)"
- MOVQ x_1_s+32(FP), AX
- MOVQ x_1_s_base+32(FP), AX
- MOVQ x_1_s+40(FP), AX // ERROR "invalid offset x_1_s\+40\(FP\); expected x_1_s\+32\(FP\), x_1_s_base\+32\(FP\), or x_1_s_len\+40\(FP\)"
- MOVQ x_1_s_len+40(FP), AX
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVL AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value"
- MOVQ AX, ret+0(FP)
- MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVQ x+0(FP), AX
- MOVB AX, ret+8(FP)
- MOVW AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVL AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value"
- MOVQ AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value"
- MOVB AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), AX
- MOVQ AX, r1+8(FP)
- MOVW AX, r2+16(FP)
- MOVQ AX, r3+24(FP)
- MOVQ AX, r3_base+24(FP)
- MOVQ AX, r3_len+32(FP)
- MOVB AX, r4+40(FP)
- MOVL AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
-
-
-// issue 15271
-TEXT ·f15271(SB), NOSPLIT, $0-4
- // Stick 123 into the low 32 bits of X0.
- MOVQ $123, AX
- PINSRD $0, AX, X0
-
- // Return them.
- PEXTRD $0, X0, x+0(FP)
- RET
-
-// issue 17584
-TEXT ·f17584(SB), NOSPLIT, $12
- MOVSS x+0(FP), X0
- MOVSS y_real+4(FP), X0
- MOVSS y_imag+8(FP), X0
- RET
+++ /dev/null
-// 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.
-
-// +build 386
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), AX
- MOVB y+1(FP), BX
- MOVW x+0(FP), AX // ERROR "\[386\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
- MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
- MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- TESTB x+0(FP), AX
- TESTB y+1(FP), BX
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
- TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
- TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
- TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
- TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 4(SP), AX // ERROR "4\(SP\) should be x\+0\(FP\)"
- MOVB 5(SP), AX // ERROR "5\(SP\) should be y\+1\(FP\)"
- MOVB 6(SP), AX // ERROR "use of 6\(SP\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+0(FP), AX
- MOVW y+2(FP), BX
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
- MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
- MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
- TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+0(FP), AX
- TESTW y+2(FP), BX
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
- TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
- TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- MOVL x_lo+0(FP), AX
- MOVL x_hi+4(FP), AX
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- MOVL y_lo+8(FP), AX
- MOVL y_hi+12(FP), AX
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint is 4-byte value"
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint is 4-byte value"
- TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); \*byte is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \*byte is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); \*byte is 4-byte value"
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); \*byte is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); \*byte is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); \*byte is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); \*byte is 4-byte value"
- TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- MOVW c+8(FP), AX // ERROR "invalid MOVW of c\+8\(FP\); chan int is 4-byte value"
- MOVW m+12(FP), AX // ERROR "invalid MOVW of m\+12\(FP\); map\[int\]int is 4-byte value"
- MOVW f+16(FP), AX // ERROR "invalid MOVW of f\+16\(FP\); func\(\) is 4-byte value"
- RET
-
-TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 4-byte value"
- MOVL x+0(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); string base is 4-byte value"
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 4-byte value"
- MOVL x_base+0(FP), AX
- MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); string base is 4-byte value"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); string len is 4-byte value"
- MOVL x_len+4(FP), AX
- MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); string len is 4-byte value"
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 4-byte value"
- MOVL x+0(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); slice base is 4-byte value"
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 4-byte value"
- MOVL x_base+0(FP), AX
- MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); slice base is 4-byte value"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); slice len is 4-byte value"
- MOVL x_len+4(FP), AX
- MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); slice len is 4-byte value"
- MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVW x_cap+8(FP), AX // ERROR "invalid MOVW of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVL x_cap+8(FP), AX
- MOVQ x_cap+8(FP), AX // ERROR "invalid MOVQ of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
- MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-16
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 4-byte value"
- MOVL x+0(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); interface type is 4-byte value"
- MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 4-byte value"
- MOVL x_type+0(FP), AX
- MOVQ x_type+0(FP), AX // ERROR "invalid MOVQ of x_type\+0\(FP\); interface type is 4-byte value"
- MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVW x_data+4(FP), AX // ERROR "invalid MOVW of x_data\+4\(FP\); interface data is 4-byte value"
- MOVL x_data+4(FP), AX
- MOVQ x_data+4(FP), AX // ERROR "invalid MOVQ of x_data\+4\(FP\); interface data is 4-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); interface itable is 4-byte value"
- MOVL y+8(FP), AX
- MOVQ y+8(FP), AX // ERROR "invalid MOVQ of y\+8\(FP\); interface itable is 4-byte value"
- MOVW y_itable+8(FP), AX // ERROR "invalid MOVW of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVL y_itable+8(FP), AX
- MOVQ y_itable+8(FP), AX // ERROR "invalid MOVQ of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
- MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVL y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVW y_data+12(FP), AX // ERROR "invalid MOVW of y_data\+12\(FP\); interface data is 4-byte value"
- MOVL y_data+12(FP), AX
- MOVQ y_data+12(FP), AX // ERROR "invalid MOVQ of y_data\+12\(FP\); interface data is 4-byte value"
- RET
-
-TEXT ·returnint(SB),0,$0-4
- MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
- MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 4-byte value"
- MOVL AX, ret+0(FP)
- MOVQ AX, ret+0(FP) // ERROR "invalid MOVQ of ret\+0\(FP\); int is 4-byte value"
- MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVL x+0(FP), AX
- MOVB AX, ret+4(FP)
- MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVL AX, ret+4(FP) // ERROR "invalid MOVL of ret\+4\(FP\); byte is 1-byte value"
- MOVQ AX, ret+4(FP) // ERROR "invalid MOVQ of ret\+4\(FP\); byte is 1-byte value"
- MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-21
- MOVB x+0(FP), AX
- MOVL AX, r1+4(FP)
- MOVW AX, r2+8(FP)
- MOVL AX, r3+12(FP)
- MOVL AX, r3_base+12(FP)
- MOVL AX, r3_len+16(FP)
- MOVB AX, r4+20(FP)
- MOVQ AX, r1+4(FP) // ERROR "invalid MOVQ of r1\+4\(FP\); int is 4-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-4
- RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
+++ /dev/null
-// 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.
-
-// +build arm
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), AX
- MOVB y+1(FP), BX
- MOVH x+0(FP), AX // ERROR "\[arm\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVH y+1(FP), AX // ERROR "invalid MOVH of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 8(R13), AX // ERROR "8\(R13\) should be x\+0\(FP\)"
- MOVB 9(R13), AX // ERROR "9\(R13\) should be y\+1\(FP\)"
- MOVB 10(R13), AX // ERROR "use of 10\(R13\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVH x+0(FP), AX
- MOVH y+2(FP), BX
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), AX // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVH x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVW x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- MOVW x_lo+0(FP), AX
- MOVW x_hi+4(FP), AX
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- MOVW y_lo+8(FP), AX
- MOVW y_hi+12(FP), AX
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
- MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
- MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- MOVH c+8(FP), AX // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
- MOVH m+12(FP), AX // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
- MOVH f+16(FP), AX // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
- RET
-
-TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
- MOVW x+0(FP), AX
- MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
- MOVW x_base+0(FP), AX
- MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
- MOVW x_len+4(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
- MOVW x+0(FP), AX
- MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
- MOVW x_base+0(FP), AX
- MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
- MOVW x_len+4(FP), AX
- MOVH x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVH x_cap+8(FP), AX // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVW x_cap+8(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
- MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
- MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-16
- MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
- MOVW x+0(FP), AX
- MOVH x_type+0(FP), AX // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
- MOVW x_type+0(FP), AX
- MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVH x_data+4(FP), AX // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
- MOVW x_data+4(FP), AX
- MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
- MOVW y+8(FP), AX
- MOVH y_itable+8(FP), AX // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVW y_itable+8(FP), AX
- MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
- MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
- MOVW y_data+12(FP), AX
- RET
-
-TEXT ·returnint(SB),0,$0-4
- MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
- MOVH AX, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 4-byte value"
- MOVW AX, ret+0(FP)
- MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVW x+0(FP), AX
- MOVB AX, ret+4(FP)
- MOVH AX, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
- MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-21
- MOVB x+0(FP), AX
- MOVW AX, r1+4(FP)
- MOVH AX, r2+8(FP)
- MOVW AX, r3+12(FP)
- MOVW AX, r3_base+12(FP)
- MOVW AX, r3_len+16(FP)
- MOVB AX, r4+20(FP)
- MOVB AX, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-4
- RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
-
-TEXT ·leaf(SB),0,$-4-12
- MOVW x+0(FP), AX
- MOVW y+4(FP), AX
- MOVW AX, ret+8(FP)
- RET
-
-TEXT ·noframe1(SB),0,$0-4
- MOVW 0(R13), AX // Okay; our saved LR
- MOVW 4(R13), AX // Okay; caller's saved LR
- MOVW x+8(R13), AX // Okay; x argument
- MOVW 12(R13), AX // ERROR "use of 12\(R13\) points beyond argument frame"
- RET
-
-TEXT ·noframe2(SB),NOFRAME,$0-4
- MOVW 0(R13), AX // Okay; caller's saved LR
- MOVW x+4(R13), AX // Okay; x argument
- MOVW 8(R13), AX // ERROR "use of 8\(R13\) points beyond argument frame"
- MOVW 12(R13), AX // ERROR "use of 12\(R13\) points beyond argument frame"
- RET
+++ /dev/null
-// 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.
-
-// +build amd64
-// +build vet_test
-
-// Test cases for symbolic NOSPLIT etc. on TEXT symbols.
-
-TEXT ·noprof(SB),NOPROF,$0-8
- RET
-
-TEXT ·dupok(SB),DUPOK,$0-8
- RET
-
-TEXT ·nosplit(SB),NOSPLIT,$0
- RET
-
-TEXT ·rodata(SB),RODATA,$0-8
- RET
-
-TEXT ·noptr(SB),NOPTR|NOSPLIT,$0
- RET
-
-TEXT ·wrapper(SB),WRAPPER,$0-8
- RET
+++ /dev/null
-// Copyright 2016 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 mips64
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R1
- MOVBU y+1(FP), R2
- MOVH x+0(FP), R1 // ERROR "\[mips64\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value"
- MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int8 is 1-byte value"
- MOVV y+1(FP), R1 // ERROR "invalid MOVV of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 16(R29), R1 // ERROR "16\(R29\) should be x\+0\(FP\)"
- MOVB 17(R29), R1 // ERROR "17\(R29\) should be y\+1\(FP\)"
- MOVB 18(R29), R1 // ERROR "use of 18\(R29\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+0(FP), R1
- MOVH y+2(FP), R2
- MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int16 is 2-byte value"
- MOVV y+2(FP), R1 // ERROR "invalid MOVV of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVV x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int32 is 4-byte value"
- MOVV y+4(FP), R1 // ERROR "invalid MOVV of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVV x+0(FP), R1
- MOVV y+8(FP), R1
- MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVV x+0(FP), R1
- MOVV y+8(FP), R1
- MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVV x+0(FP), R1
- MOVV y+8(FP), R1
- MOVV x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVV y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVW c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
- MOVW m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVW f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVV x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVV x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVV x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVV x_len+8(FP), R1
- MOVV y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVV y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVV x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVV x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVV x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVV x_len+8(FP), R1
- MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVV x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVH x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVW x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVV x_cap+16(FP), R1
- MOVV y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVV y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVV y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVV x+0(FP), R1
- MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
- MOVW x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVV x_type+0(FP), R1
- MOVV x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVV x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVV x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVH x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
- MOVW x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVV x_data+8(FP), R1
- MOVH y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
- MOVW y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVV y+16(FP), R1
- MOVH y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVW y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVV y_itable+16(FP), R1
- MOVV y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVH y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVV y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVH y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
- MOVW y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVV y_data+24(FP), R1
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVH R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
- MOVW R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVV R1, ret+0(FP)
- MOVV R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVV R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVV x+0(FP), R1
- MOVB R1, ret+8(FP)
- MOVH R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
- MOVW R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVV R1, ret+8(FP) // ERROR "invalid MOVV of ret\+8\(FP\); byte is 1-byte value"
- MOVB R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), R1
- MOVV R1, r1+8(FP)
- MOVH R1, r2+16(FP)
- MOVV R1, r3+24(FP)
- MOVV R1, r3_base+24(FP)
- MOVV R1, r3_len+32(FP)
- MOVB R1, r4+40(FP)
- MOVW R1, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
+++ /dev/null
-// Copyright 2016 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 s390x
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R1
- MOVBZ y+1(FP), R2
- MOVH x+0(FP), R1 // ERROR "\[s390x\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHZ y+1(FP), R1 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWZ y+1(FP), R1 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value"
- MOVD y+1(FP), R1 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBZ y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 16(R15), R1 // ERROR "16\(R15\) should be x\+0\(FP\)"
- MOVB 17(R15), R1 // ERROR "17\(R15\) should be y\+1\(FP\)"
- MOVB 18(R15), R1 // ERROR "use of 18\(R15\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBZ x+0(FP), R1 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+0(FP), R1
- MOVH y+2(FP), R2
- MOVWZ x+0(FP), R1 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value"
- MOVD y+2(FP), R1 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value"
- MOVD y+4(FP), R1 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVD x+0(FP), R1
- MOVD y+8(FP), R1
- MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVD x+0(FP), R1
- MOVD y+8(FP), R1
- MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVD x+0(FP), R1
- MOVD y+8(FP), R1
- MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVW c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
- MOVW m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVW f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVD x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVD x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVD x_len+8(FP), R1
- MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVD x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
- MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVD x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
- MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVD x_len+8(FP), R1
- MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVD x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVH x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVW x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVD x_cap+16(FP), R1
- MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVD y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVD x+0(FP), R1
- MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
- MOVW x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVD x_type+0(FP), R1
- MOVD x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVD x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVD x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVH x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
- MOVW x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVD x_data+8(FP), R1
- MOVH y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
- MOVW y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVD y+16(FP), R1
- MOVH y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVW y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVD y_itable+16(FP), R1
- MOVD y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVH y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVD y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVH y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
- MOVW y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVD y_data+24(FP), R1
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVH R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
- MOVW R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVD R1, ret+0(FP)
- MOVD R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVD R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVD x+0(FP), R1
- MOVB R1, ret+8(FP)
- MOVH R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
- MOVW R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVD R1, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value"
- MOVB R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), R1
- MOVD R1, r1+8(FP)
- MOVH R1, r2+16(FP)
- MOVD R1, r3+24(FP)
- MOVD R1, r3_base+24(FP)
- MOVD R1, r3_len+32(FP)
- MOVB R1, r4+40(FP)
- MOVW R1, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
+++ /dev/null
-// Copyright 2016 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 ppc64 ppc64le
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R3
- MOVBZ y+1(FP), R4
- MOVH x+0(FP), R3 // ERROR "\[(ppc64|ppc64le)\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHZ y+1(FP), R3 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWZ y+1(FP), R3 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value"
- MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value"
- MOVD y+1(FP), R3 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R3 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBZ y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 16(R1), R3 // ERROR "16\(R1\) should be x\+0\(FP\)"
- MOVB 17(R1), R3 // ERROR "17\(R1\) should be y\+1\(FP\)"
- MOVB 18(R1), R3 // ERROR "use of 18\(R1\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBZ x+0(FP), R3 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R3 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+0(FP), R3
- MOVH y+2(FP), R4
- MOVWZ x+0(FP), R3 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R3 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value"
- MOVD y+2(FP), R3 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value"
- MOVHZ x+2(FP), R3 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R4 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R3 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R3
- MOVW y+4(FP), R3
- MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value"
- MOVD y+4(FP), R3 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+4(FP), R3 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVD x+0(FP), R3
- MOVD y+8(FP), R3
- MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
- MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVD x+0(FP), R3
- MOVD y+8(FP), R3
- MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
- MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVD x+0(FP), R3
- MOVD y+8(FP), R3
- MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVW c+16(FP), R3 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
- MOVW m+24(FP), R3 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVW f+32(FP), R3 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVD x+0(FP), R3
- MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
- MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVD x_base+0(FP), R3
- MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
- MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVD x_len+8(FP), R3
- MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVD x+0(FP), R3
- MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
- MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVD x_base+0(FP), R3
- MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
- MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVD x_len+8(FP), R3
- MOVH x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVD x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVH x_cap+16(FP), R3 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVW x_cap+16(FP), R3 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVD x_cap+16(FP), R3
- MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVD y_cap+16(FP), R3 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
- MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVD x+0(FP), R3
- MOVH x_type+0(FP), R3 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
- MOVW x_type+0(FP), R3 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVD x_type+0(FP), R3
- MOVD x_itable+0(FP), R3 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVD x_itable+1(FP), R3 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVD x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVH x_data+8(FP), R3 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
- MOVW x_data+8(FP), R3 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVD x_data+8(FP), R3
- MOVH y+16(FP), R3 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
- MOVW y+16(FP), R3 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVD y+16(FP), R3
- MOVH y_itable+16(FP), R3 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVW y_itable+16(FP), R3 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVD y_itable+16(FP), R3
- MOVD y_type+16(FP), R3 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVH y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVD y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVH y_data+24(FP), R3 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
- MOVW y_data+24(FP), R3 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVD y_data+24(FP), R3
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB R3, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVH R3, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
- MOVW R3, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVD R3, ret+0(FP)
- MOVD R3, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVD R3, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVD x+0(FP), R3
- MOVB R3, ret+8(FP)
- MOVH R3, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
- MOVW R3, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVD R3, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value"
- MOVB R3, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), R3
- MOVD R3, r1+8(FP)
- MOVH R3, r2+16(FP)
- MOVD R3, r3+24(FP)
- MOVD R3, r3_base+24(FP)
- MOVD R3, r3_len+32(FP)
- MOVB R3, r4+40(FP)
- MOVW R3, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
+++ /dev/null
-// Copyright 2016 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 mipsle
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), R1
- MOVBU y+1(FP), R2
- MOVH x+0(FP), R1 // ERROR "\[mipsle\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
- MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value"
- MOVW y+1(FP), R1 // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 8(R29), R1 // ERROR "8\(R29\) should be x\+0\(FP\)"
- MOVB 9(R29), R1 // ERROR "9\(R29\) should be y\+1\(FP\)"
- MOVB 10(R29), R1 // ERROR "use of 10\(R29\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+0(FP), R1
- MOVH y+2(FP), R2
- MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value"
- MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
- MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
- MOVW x_lo+0(FP), R1
- MOVW x_hi+4(FP), R1
- MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
- MOVW y_lo+8(FP), R1
- MOVW y_hi+12(FP), R1
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
- MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
- MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
- MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
- MOVW x+0(FP), R1
- MOVW y+4(FP), R1
- MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- MOVH c+8(FP), R1 // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
- MOVH m+12(FP), R1 // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
- MOVH f+16(FP), R1 // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
- RET
-
-TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
- MOVW x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
- MOVW x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
- MOVW x_len+4(FP), R1
- MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
- MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
- MOVW x+0(FP), R1
- MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
- MOVW x_base+0(FP), R1
- MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
- MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
- MOVW x_len+4(FP), R1
- MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
- MOVH x_cap+8(FP), R1 // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
- MOVW x_cap+8(FP), R1
- MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
- MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
- MOVW y_cap+8(FP), R1 // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-16
- MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
- MOVW x+0(FP), R1
- MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
- MOVW x_type+0(FP), R1
- MOVQ x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVQ x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
- MOVH x_data+4(FP), R1 // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
- MOVW x_data+4(FP), R1
- MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
- MOVW y+8(FP), R1
- MOVH y_itable+8(FP), R1 // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
- MOVW y_itable+8(FP), R1
- MOVW y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
- MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
- MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
- MOVW y_data+12(FP), AX
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVW x+0(FP), R1
- MOVB R1, ret+4(FP)
- MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
- MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-5
- MOVW x+0(FP), R1
- MOVB R1, ret+4(FP)
- MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
- MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
- MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-21
- MOVB x+0(FP), AX
- MOVW R1, r1+4(FP)
- MOVH R1, r2+8(FP)
- MOVW R1, r3+12(FP)
- MOVW R1, r3_base+12(FP)
- MOVW R1, r3_len+16(FP)
- MOVB R1, r4+20(FP)
- MOVB R1, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-4
- RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
+++ /dev/null
-// 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.
-
-// This file contains tests for the atomic checker.
-
-package testdata
-
-import (
- "sync/atomic"
-)
-
-type Counter uint64
-
-func AtomicTests() {
- x := uint64(1)
- x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
- _, x = 10, atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
- x, _ = atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
-
- y := &x
- *y = atomic.AddUint64(y, 1) // ERROR "direct assignment to atomic value"
-
- var su struct{ Counter uint64 }
- su.Counter = atomic.AddUint64(&su.Counter, 1) // ERROR "direct assignment to atomic value"
- z1 := atomic.AddUint64(&su.Counter, 1)
- _ = z1 // Avoid err "z declared and not used"
-
- var sp struct{ Counter *uint64 }
- *sp.Counter = atomic.AddUint64(sp.Counter, 1) // ERROR "direct assignment to atomic value"
- z2 := atomic.AddUint64(sp.Counter, 1)
- _ = z2 // Avoid err "z declared and not used"
-
- au := []uint64{10, 20}
- au[0] = atomic.AddUint64(&au[0], 1) // ERROR "direct assignment to atomic value"
- au[1] = atomic.AddUint64(&au[0], 1)
-
- ap := []*uint64{&au[0], &au[1]}
- *ap[0] = atomic.AddUint64(ap[0], 1) // ERROR "direct assignment to atomic value"
- *ap[1] = atomic.AddUint64(ap[0], 1)
-
- x = atomic.AddUint64() // Used to make vet crash; now silently ignored.
-
- {
- // A variable declaration creates a new variable in the current scope.
- x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at atomic.go:16"
-
- // Re-declaration assigns a new value.
- x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
- _ = w
- }
-}
-
-type T struct{}
-
-func (T) AddUint64(addr *uint64, delta uint64) uint64 { return 0 }
-
-func NonAtomic() {
- x := uint64(1)
- var atomic T
- x = atomic.AddUint64(&x, 1) // ok; not the imported pkg
-}
+++ /dev/null
-// Copyright 2014 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.
-
-// This file contains tests for the bool checker.
-
-package testdata
-
-import "io"
-
-type T int
-
-func (t T) Foo() int { return int(t) }
-
-type FT func() int
-
-var S []int
-
-func RatherStupidConditions() {
- var f, g func() int
- if f() == 0 || f() == 0 { // OK f might have side effects
- }
- var t T
- _ = t.Foo() == 2 || t.Foo() == 2 // OK Foo might have side effects
- if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w"
- }
- _ = f == nil || f == nil // ERROR "redundant or: f == nil || f == nil"
-
- _ = i == byte(1) || i == byte(1) // ERROR "redundant or: i == byte(1) || i == byte(1)"
- _ = i == T(2) || i == T(2) // ERROR "redundant or: i == T(2) || i == T(2)"
- _ = FT(f) == nil || FT(f) == nil // ERROR "redundant or: FT(f) == nil || FT(f) == nil"
-
- _ = (func() int)(f) == nil || (func() int)(f) == nil // ERROR "redundant or: (func() int)(f) == nil || (func() int)(f) == nil"
- _ = append(S, 3) == nil || append(S, 3) == nil // OK append has side effects
-
- var namedFuncVar FT
- _ = namedFuncVar() == namedFuncVar() // OK still func calls
-
- var c chan int
- _ = 0 == <-c || 0 == <-c // OK subsequent receives may yield different values
- for i, j := <-c, <-c; i == j || i == j; i, j = <-c, <-c { // ERROR "redundant or: i == j || i == j"
- }
-
- var i, j, k int
- _ = i+1 == 1 || i+1 == 1 // ERROR "redundant or: i\+1 == 1 || i\+1 == 1"
- _ = i == 1 || j+1 == i || i == 1 // ERROR "redundant or: i == 1 || i == 1"
-
- _ = i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || f() == 1 || i == 1 // OK f may alter i as a side effect
- _ = f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
-
- // Test partition edge cases
- _ = f() == 1 || i == 1 || i == 1 || j == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = f() == 1 || j == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || i == 1 || f() == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || i == 1 || j == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = j == 1 || i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || f() == 1 || f() == 1 || i == 1
-
- _ = i == 1 || (i == 1 || i == 2) // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || (f() == 1 || i == 1) // OK f may alter i as a side effect
- _ = i == 1 || (i == 1 || f() == 1) // ERROR "redundant or: i == 1 || i == 1"
- _ = i == 1 || (i == 2 || (i == 1 || i == 3)) // ERROR "redundant or: i == 1 || i == 1"
-
- var a, b bool
- _ = i == 1 || (a || (i == 1 || b)) // ERROR "redundant or: i == 1 || i == 1"
-
- // Check that all redundant ors are flagged
- _ = j == 0 ||
- i == 1 ||
- f() == 1 ||
- j == 0 || // ERROR "redundant or: j == 0 || j == 0"
- i == 1 || // ERROR "redundant or: i == 1 || i == 1"
- i == 1 || // ERROR "redundant or: i == 1 || i == 1"
- i == 1 ||
- j == 0 ||
- k == 0
-
- _ = i == 1*2*3 || i == 1*2*3 // ERROR "redundant or: i == 1\*2\*3 || i == 1\*2\*3"
-
- // These test that redundant, suspect expressions do not trigger multiple errors.
- _ = i != 0 || i != 0 // ERROR "redundant or: i != 0 || i != 0"
- _ = i == 0 && i == 0 // ERROR "redundant and: i == 0 && i == 0"
-
- // and is dual to or; check the basics and
- // let the or tests pull the rest of the weight.
- _ = 0 != <-c && 0 != <-c // OK subsequent receives may yield different values
- _ = f() != 0 && f() != 0 // OK f might have side effects
- _ = f != nil && f != nil // ERROR "redundant and: f != nil && f != nil"
- _ = i != 1 && i != 1 && f() != 1 // ERROR "redundant and: i != 1 && i != 1"
- _ = i != 1 && f() != 1 && i != 1 // OK f may alter i as a side effect
- _ = f() != 1 && i != 1 && i != 1 // ERROR "redundant and: i != 1 && i != 1"
-}
-
-func RoyallySuspectConditions() {
- var i, j int
-
- _ = i == 0 || i == 1 // OK
- _ = i != 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
- _ = i != 0 || 1 != i // ERROR "suspect or: i != 0 || 1 != i"
- _ = 0 != i || 1 != i // ERROR "suspect or: 0 != i || 1 != i"
- _ = 0 != i || i != 1 // ERROR "suspect or: 0 != i || i != 1"
-
- _ = (0 != i) || i != 1 // ERROR "suspect or: 0 != i || i != 1"
-
- _ = i+3 != 7 || j+5 == 0 || i+3 != 9 // ERROR "suspect or: i\+3 != 7 || i\+3 != 9"
-
- _ = i != 0 || j == 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
-
- _ = i != 0 || i != 1<<4 // ERROR "suspect or: i != 0 || i != 1<<4"
-
- _ = i != 0 || j != 0
- _ = 0 != i || 0 != j
-
- var s string
- _ = s != "one" || s != "the other" // ERROR "suspect or: s != .one. || s != .the other."
-
- _ = "et" != "alii" || "et" != "cetera" // ERROR "suspect or: .et. != .alii. || .et. != .cetera."
- _ = "me gustas" != "tu" || "le gustas" != "tu" // OK we could catch this case, but it's not worth the code
-
- var err error
- _ = err != nil || err != io.EOF // TODO catch this case?
-
- // Sanity check and.
- _ = i != 0 && i != 1 // OK
- _ = i == 0 && i == 1 // ERROR "suspect and: i == 0 && i == 1"
- _ = i == 0 && 1 == i // ERROR "suspect and: i == 0 && 1 == i"
- _ = 0 == i && 1 == i // ERROR "suspect and: 0 == i && 1 == i"
- _ = 0 == i && i == 1 // ERROR "suspect and: 0 == i && i == 1"
-}
+++ /dev/null
-// This file contains misplaced or malformed build constraints.
-// The Go tool will skip it, because the constraints are invalid.
-// It serves only to test the tag checker during make test.
-
-// Mention +build // ERROR "possible malformed \+build comment"
-
-// +build !!bang // ERROR "invalid double negative in build constraint"
-// +build @#$ // ERROR "invalid non-alphanumeric build constraint"
-
-// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
-package bad
-
-// This is package 'bad' rather than 'main' so the erroneous build
-// tag doesn't end up looking like a package doc for the vet command
-// when examined by godoc.
+++ /dev/null
-// 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.
-
-// This file contains tests for the cgo checker.
-
-package testdata
-
-// void f(void *);
-import "C"
-
-import "unsafe"
-
-func CgoTests() {
- var c chan bool
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer"
-
- var m map[string]string
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&m))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&m)) // ERROR "embedded pointer"
-
- var f func()
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&f))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&f)) // ERROR "embedded pointer"
-
- var s []int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&s)) // ERROR "embedded pointer"
-
- var a [1][]int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&a)) // ERROR "embedded pointer"
-
- var st struct{ f []int }
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&st)) // ERROR "embedded pointer"
-
- // The following cases are OK.
- var i int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&i)))
- C.f(unsafe.Pointer(&i))
-
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s[0])))
- C.f(unsafe.Pointer(&s[0]))
-
- var a2 [1]int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a2)))
- C.f(unsafe.Pointer(&a2))
-
- var st2 struct{ i int }
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2)))
- C.f(unsafe.Pointer(&st2))
-
- type cgoStruct struct{ p *cgoStruct }
- C.f(unsafe.Pointer(&cgoStruct{}))
-
- C.CBytes([]byte("hello"))
-}
+++ /dev/null
-// Copyright 2016 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.
-
-// Test the cgo checker on a file that doesn't use cgo.
-
-package testdata
-
-var _ = C.f(*p(**p))
-
-// Passing a pointer (via the slice), but C isn't cgo.
-var _ = C.f([]int{3})
+++ /dev/null
-// Copyright 2017 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.
-
-// Used by TestVetVerbose to test that vet -v doesn't fail because it
-// can't find "C".
-
-package testdata
-
-import "C"
-
-func F() {
-}
+++ /dev/null
-// Copyright 2017 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.
-
-// Test the cgo checker on a file that doesn't use cgo, but has an
-// import named "C".
-
-package testdata
-
-import C "fmt"
-
-var _ = C.Println(*p(**p))
-
-// Passing a pointer (via a slice), but C is fmt, not cgo.
-var _ = C.Println([]int{3})
+++ /dev/null
-// Copyright 2012 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.
-
-// This file contains the test for untagged struct literals.
-
-package testdata
-
-import (
- "flag"
- "go/scanner"
- "image"
- "unicode"
-
- "path/to/unknownpkg"
-)
-
-var Okay1 = []string{
- "Name",
- "Usage",
- "DefValue",
-}
-
-var Okay2 = map[string]bool{
- "Name": true,
- "Usage": true,
- "DefValue": true,
-}
-
-var Okay3 = struct {
- X string
- Y string
- Z string
-}{
- "Name",
- "Usage",
- "DefValue",
-}
-
-var Okay4 = []struct {
- A int
- B int
-}{
- {1, 2},
- {3, 4},
-}
-
-type MyStruct struct {
- X string
- Y string
- Z string
-}
-
-var Okay5 = &MyStruct{
- "Name",
- "Usage",
- "DefValue",
-}
-
-var Okay6 = []MyStruct{
- {"foo", "bar", "baz"},
- {"aa", "bb", "cc"},
-}
-
-var Okay7 = []*MyStruct{
- {"foo", "bar", "baz"},
- {"aa", "bb", "cc"},
-}
-
-// Testing is awkward because we need to reference things from a separate package
-// to trigger the warnings.
-
-var goodStructLiteral = flag.Flag{
- Name: "Name",
- Usage: "Usage",
-}
-var badStructLiteral = flag.Flag{ // ERROR "unkeyed fields"
- "Name",
- "Usage",
- nil, // Value
- "DefValue",
-}
-
-// SpecialCase is a named slice of CaseRange to test issue 9171.
-var goodNamedSliceLiteral = unicode.SpecialCase{
- {Lo: 1, Hi: 2},
- unicode.CaseRange{Lo: 1, Hi: 2},
-}
-var badNamedSliceLiteral = unicode.SpecialCase{
- {1, 2}, // ERROR "unkeyed fields"
- unicode.CaseRange{1, 2}, // ERROR "unkeyed fields"
-}
-
-// ErrorList is a named slice, so no warnings should be emitted.
-var goodScannerErrorList = scanner.ErrorList{
- &scanner.Error{Msg: "foobar"},
-}
-var badScannerErrorList = scanner.ErrorList{
- &scanner.Error{"foobar"}, // ERROR "unkeyed fields"
-}
-
-// Check whitelisted structs: if vet is run with --compositewhitelist=false,
-// this line triggers an error.
-var whitelistedPoint = image.Point{1, 2}
-
-// Do not check type from unknown package.
-// See issue 15408.
-var unknownPkgVar = unknownpkg.Foobar{"foo", "bar"}
-
-// A named pointer slice of CaseRange to test issue 23539. In
-// particular, we're interested in how some slice elements omit their
-// type.
-var goodNamedPointerSliceLiteral = []*unicode.CaseRange{
- {Lo: 1, Hi: 2},
- &unicode.CaseRange{Lo: 1, Hi: 2},
-}
-var badNamedPointerSliceLiteral = []*unicode.CaseRange{
- {1, 2}, // ERROR "unkeyed fields"
- &unicode.CaseRange{1, 2}, // ERROR "unkeyed fields"
-}
+++ /dev/null
-package testdata
-
-import (
- "sync"
- "sync/atomic"
- "unsafe"
- . "unsafe"
- unsafe1 "unsafe"
-)
-
-func OkFunc() {
- var x *sync.Mutex
- p := x
- var y sync.Mutex
- p = &y
-
- var z = sync.Mutex{}
- w := sync.Mutex{}
-
- w = sync.Mutex{}
- q := struct{ L sync.Mutex }{
- L: sync.Mutex{},
- }
-
- yy := []Tlock{
- Tlock{},
- Tlock{
- once: sync.Once{},
- },
- }
-
- nl := new(sync.Mutex)
- mx := make([]sync.Mutex, 10)
- xx := struct{ L *sync.Mutex }{
- L: new(sync.Mutex),
- }
-}
-
-type Tlock struct {
- once sync.Once
-}
-
-func BadFunc() {
- var x *sync.Mutex
- p := x
- var y sync.Mutex
- p = &y
- *p = *x // ERROR "assignment copies lock value to \*p: sync.Mutex"
-
- var t Tlock
- var tp *Tlock
- tp = &t
- *tp = t // ERROR "assignment copies lock value to \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
- t = *tp // ERROR "assignment copies lock value to t: testdata.Tlock contains sync.Once contains sync.Mutex"
-
- y := *x // ERROR "assignment copies lock value to y: sync.Mutex"
- var z = t // ERROR "variable declaration copies lock value to z: testdata.Tlock contains sync.Once contains sync.Mutex"
-
- w := struct{ L sync.Mutex }{
- L: *x, // ERROR "literal copies lock value from \*x: sync.Mutex"
- }
- var q = map[int]Tlock{
- 1: t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
- 2: *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
- }
- yy := []Tlock{
- t, // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
- *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
- }
-
- // override 'new' keyword
- new := func(interface{}) {}
- new(t) // ERROR "call of new copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
-
- // copy of array of locks
- var muA [5]sync.Mutex
- muB := muA // ERROR "assignment copies lock value to muB: sync.Mutex"
- muA = muB // ERROR "assignment copies lock value to muA: sync.Mutex"
- muSlice := muA[:] // OK
-
- // multidimensional array
- var mmuA [5][5]sync.Mutex
- mmuB := mmuA // ERROR "assignment copies lock value to mmuB: sync.Mutex"
- mmuA = mmuB // ERROR "assignment copies lock value to mmuA: sync.Mutex"
- mmuSlice := mmuA[:] // OK
-
- // slice copy is ok
- var fmuA [5][][5]sync.Mutex
- fmuB := fmuA // OK
- fmuA = fmuB // OK
- fmuSlice := fmuA[:] // OK
-}
-
-func LenAndCapOnLockArrays() {
- var a [5]sync.Mutex
- aLen := len(a) // OK
- aCap := cap(a) // OK
-
- // override 'len' and 'cap' keywords
-
- len := func(interface{}) {}
- len(a) // ERROR "call of len copies lock value: sync.Mutex"
-
- cap := func(interface{}) {}
- cap(a) // ERROR "call of cap copies lock value: sync.Mutex"
-}
-
-func SizeofMutex() {
- var mu sync.Mutex
- unsafe.Sizeof(mu) // OK
- unsafe1.Sizeof(mu) // OK
- Sizeof(mu) // OK
- unsafe := struct{ Sizeof func(interface{}) }{}
- unsafe.Sizeof(mu) // ERROR "call of unsafe.Sizeof copies lock value: sync.Mutex"
- Sizeof := func(interface{}) {}
- Sizeof(mu) // ERROR "call of Sizeof copies lock value: sync.Mutex"
-}
-
-// SyncTypesCheck checks copying of sync.* types except sync.Mutex
-func SyncTypesCheck() {
- // sync.RWMutex copying
- var rwmuX sync.RWMutex
- var rwmuXX = sync.RWMutex{}
- rwmuX1 := new(sync.RWMutex)
- rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
- rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
- var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex"
- rwmuP := &rwmuX
- rwmuZ := &sync.RWMutex{}
-
- // sync.Cond copying
- var condX sync.Cond
- var condXX = sync.Cond{}
- condX1 := new(sync.Cond)
- condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
- condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
- var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy"
- condP := &condX
- condZ := &sync.Cond{
- L: &sync.Mutex{},
- }
- condZ = sync.NewCond(&sync.Mutex{})
-
- // sync.WaitGroup copying
- var wgX sync.WaitGroup
- var wgXX = sync.WaitGroup{}
- wgX1 := new(sync.WaitGroup)
- wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
- wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
- var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy"
- wgP := &wgX
- wgZ := &sync.WaitGroup{}
-
- // sync.Pool copying
- var poolX sync.Pool
- var poolXX = sync.Pool{}
- poolX1 := new(sync.Pool)
- poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
- poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
- var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy"
- poolP := &poolX
- poolZ := &sync.Pool{}
-
- // sync.Once copying
- var onceX sync.Once
- var onceXX = sync.Once{}
- onceX1 := new(sync.Once)
- onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
- onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
- var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex"
- onceP := &onceX
- onceZ := &sync.Once{}
-}
-
-// AtomicTypesCheck checks copying of sync/atomic types
-func AtomicTypesCheck() {
- // atomic.Value copying
- var vX atomic.Value
- var vXX = atomic.Value{}
- vX1 := new(atomic.Value)
- // These are OK because the value has not been used yet.
- // (And vet can't tell whether it has been used, so they're always OK.)
- vY := vX
- vY = vX
- var vYY = vX
- vP := &vX
- vZ := &atomic.Value{}
-}
+++ /dev/null
-// 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.
-
-// This file contains tests for the copylock checker's
-// function declaration analysis.
-
-package testdata
-
-import "sync"
-
-func OkFunc(*sync.Mutex) {}
-func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex"
-func BadFunc2(sync.Map) {} // ERROR "BadFunc2 passes lock by value: sync.Map contains sync.Mutex"
-func OkRet() *sync.Mutex {}
-func BadRet() sync.Mutex {} // Don't warn about results
-
-var (
- OkClosure = func(*sync.Mutex) {}
- BadClosure = func(sync.Mutex) {} // ERROR "func passes lock by value: sync.Mutex"
- BadClosure2 = func(sync.Map) {} // ERROR "func passes lock by value: sync.Map contains sync.Mutex"
-)
-
-type EmbeddedRWMutex struct {
- sync.RWMutex
-}
-
-func (*EmbeddedRWMutex) OkMeth() {}
-func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.EmbeddedRWMutex"
-func OkFunc(e *EmbeddedRWMutex) {}
-func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex"
-func OkRet() *EmbeddedRWMutex {}
-func BadRet() EmbeddedRWMutex {} // Don't warn about results
-
-type FieldMutex struct {
- s sync.Mutex
-}
-
-func (*FieldMutex) OkMeth() {}
-func (FieldMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.FieldMutex contains sync.Mutex"
-func OkFunc(*FieldMutex) {}
-func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes lock by value: testdata.FieldMutex contains sync.Mutex"
-
-type L0 struct {
- L1
-}
-
-type L1 struct {
- l L2
-}
-
-type L2 struct {
- sync.Mutex
-}
-
-func (*L0) Ok() {}
-func (L0) Bad() {} // ERROR "Bad passes lock by value: testdata.L0 contains testdata.L1 contains testdata.L2"
-
-type EmbeddedMutexPointer struct {
- s *sync.Mutex // safe to copy this pointer
-}
-
-func (*EmbeddedMutexPointer) Ok() {}
-func (EmbeddedMutexPointer) AlsoOk() {}
-func StillOk(EmbeddedMutexPointer) {}
-func LookinGood() EmbeddedMutexPointer {}
-
-type EmbeddedLocker struct {
- sync.Locker // safe to copy interface values
-}
-
-func (*EmbeddedLocker) Ok() {}
-func (EmbeddedLocker) AlsoOk() {}
-
-type CustomLock struct{}
-
-func (*CustomLock) Lock() {}
-func (*CustomLock) Unlock() {}
-
-func Ok(*CustomLock) {}
-func Bad(CustomLock) {} // ERROR "Bad passes lock by value: testdata.CustomLock"
-
-// Passing lock values into interface function arguments
-func FuncCallInterfaceArg(f func(a int, b interface{})) {
- var m sync.Mutex
- var t struct{ lock sync.Mutex }
-
- f(1, "foo")
- f(2, &t)
- f(3, &sync.Mutex{})
- f(4, m) // ERROR "call of f copies lock value: sync.Mutex"
- f(5, t) // ERROR "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
- var fntab []func(t)
- fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
-}
-
-// Returning lock via interface value
-func ReturnViaInterface(x int) (int, interface{}) {
- var m sync.Mutex
- var t struct{ lock sync.Mutex }
-
- switch x % 4 {
- case 0:
- return 0, "qwe"
- case 1:
- return 1, &sync.Mutex{}
- case 2:
- return 2, m // ERROR "return copies lock value: sync.Mutex"
- default:
- return 3, t // ERROR "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex"
- }
-}
-
-// Some cases that we don't warn about.
-
-func AcceptedCases() {
- x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227)
- x = BadRet() // function call on RHS is OK (#16227)
- x = *OKRet() // indirection of function call on RHS is OK (#16227)
-}
-
-// TODO: Unfortunate cases
-
-// Non-ideal error message:
-// Since we're looking for Lock methods, sync.Once's underlying
-// sync.Mutex gets called out, but without any reference to the sync.Once.
-type LocalOnce sync.Once
-
-func (LocalOnce) Bad() {} // ERROR "Bad passes lock by value: testdata.LocalOnce contains sync.Mutex"
-
-// False negative:
-// LocalMutex doesn't have a Lock method.
-// Nevertheless, it is probably a bad idea to pass it by value.
-type LocalMutex sync.Mutex
-
-func (LocalMutex) Bad() {} // WANTED: An error here :(
+++ /dev/null
-// Copyright 2014 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.
-
-// This file contains tests for the copylock checker's
-// range statement analysis.
-
-package testdata
-
-import "sync"
-
-func rangeMutex() {
- var mu sync.Mutex
- var i int
-
- var s []sync.Mutex
- for range s {
- }
- for i = range s {
- }
- for i := range s {
- }
- for i, _ = range s {
- }
- for i, _ := range s {
- }
- for _, mu = range s { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for _, m := range s { // ERROR "range var m copies lock: sync.Mutex"
- }
- for i, mu = range s { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for i, m := range s { // ERROR "range var m copies lock: sync.Mutex"
- }
-
- var a [3]sync.Mutex
- for _, m := range a { // ERROR "range var m copies lock: sync.Mutex"
- }
-
- var m map[sync.Mutex]sync.Mutex
- for k := range m { // ERROR "range var k copies lock: sync.Mutex"
- }
- for mu, _ = range m { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for k, _ := range m { // ERROR "range var k copies lock: sync.Mutex"
- }
- for _, mu = range m { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for _, v := range m { // ERROR "range var v copies lock: sync.Mutex"
- }
-
- var c chan sync.Mutex
- for range c {
- }
- for mu = range c { // ERROR "range var mu copies lock: sync.Mutex"
- }
- for v := range c { // ERROR "range var v copies lock: sync.Mutex"
- }
-
- // Test non-idents in range variables
- var t struct {
- i int
- mu sync.Mutex
- }
- for t.i, t.mu = range s { // ERROR "range var t.mu copies lock: sync.Mutex"
- }
-}
+++ /dev/null
-// 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.
-
-// +build ignore
-
-// This file contains tests for the dead code checker.
-
-package testdata
-
-type T int
-
-var x interface{}
-var c chan int
-
-func external() int // ok
-
-func _() int {
-}
-
-func _() int {
- print(1)
-}
-
-func _() int {
- print(1)
- return 2
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- goto L
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-func _() int {
- var panic = func(int) {}
- print(1)
- panic(2)
- println() // ok
-}
-
-func _() int {
- {
- print(1)
- return 2
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- {
- print(1)
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- panic(2)
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- {
- print(1)
- return 2
- }
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- {
- print(1)
- goto L
- }
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- if x == nil {
- panic(2)
- } else {
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 2 {
- panic(3)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-// if-else chain missing final else is not okay, even if the
-// conditions cover every possible case.
-
-func _() int {
- print(1)
- if x == nil {
- panic(2)
- } else if x != nil {
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- if x == nil {
- panic(2)
- }
- println() // ok
-}
-
-func _() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 1 {
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- for {
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- for {
- for {
- break
- }
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- for {
- for {
- break
- println() // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- for {
- for {
- continue
- println() // ERROR "unreachable code"
- }
- }
-}
-
-func _() int {
- for {
- L:
- for {
- break L
- }
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- for {
- break
- }
- println() // ok
-}
-
-func _() int {
- for {
- for {
- }
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- for {
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- for x == nil {
- }
- println() // ok
-}
-
-func _() int {
- for x == nil {
- for {
- break
- }
- }
- println() // ok
-}
-
-func _() int {
- for x == nil {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- for true {
- }
- println() // ok
-}
-
-func _() int {
- for true {
- for {
- break
- }
- }
- println() // ok
-}
-
-func _() int {
- for true {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {}
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- case c <- 1:
- print(2)
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- default:
- select {}
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- select {}
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- }
- println() // ok
-}
-
-func _() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- goto L // ERROR "unreachable code"
- case c <- 1:
- print(2)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- print(2)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- default:
- break
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- for {
- break L
- }
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- break L
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- select {
- case <-c:
- print(1)
- panic("abc")
- default:
- select {}
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x {
- default:
- return 4
- println() // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x {
- default:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- case 2:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 2:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- case 2:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x {
- default:
- return 4
- break // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- println() // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- case float64:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case float64:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- case float64:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-func _() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- break // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-func _() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-// again, but without the leading print(1).
-// testing that everything works when the terminating statement is first.
-
-func _() int {
- println() // ok
-}
-
-func _() int {
- return 2
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- goto L
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-func _() int {
- var panic = func(int) {}
- panic(2)
- println() // ok
-}
-
-func _() int {
- {
- return 2
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- {
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
-L:
- {
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
-L:
- {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-func _() int {
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-func _() int {
- return 2
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- goto L
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- panic(2)
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- {
- return 2
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-func _() int {
-L:
- {
- goto L
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-func _() int {
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-func _() int {
- {
- return 2
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
-L:
- {
- goto L
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-func _() int {
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-// again, with func literals
-
-var _ = func() int {
-}
-
-var _ = func() int {
- print(1)
-}
-
-var _ = func() int {
- print(1)
- return 2
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- goto L
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-var _ = func() int {
- var panic = func(int) {}
- print(1)
- panic(2)
- println() // ok
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- println() // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- panic(2)
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- { // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- { // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- {
- print(1)
- return 2
- }
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- {
- print(1)
- goto L
- }
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- if x == nil {
- panic(2)
- } else {
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 2 {
- panic(3)
- } else {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-// if-else chain missing final else is not okay, even if the
-// conditions cover every possible case.
-
-var _ = func() int {
- print(1)
- if x == nil {
- panic(2)
- } else if x != nil {
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- if x == nil {
- panic(2)
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- print(1)
- if x == nil {
- panic(2)
- } else if x == 1 {
- return 0
- } else if x != 1 {
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- for {
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- for {
- for {
- break
- }
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- for {
- for {
- break
- println() // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- for {
- for {
- continue
- println() // ERROR "unreachable code"
- }
- }
-}
-
-var _ = func() int {
- for {
- L:
- for {
- break L
- }
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- for {
- break
- }
- println() // ok
-}
-
-var _ = func() int {
- for {
- for {
- }
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- for {
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- for x == nil {
- }
- println() // ok
-}
-
-var _ = func() int {
- for x == nil {
- for {
- break
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- for x == nil {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- for true {
- }
- println() // ok
-}
-
-var _ = func() int {
- for true {
- for {
- break
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- for true {
- L:
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {}
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- for {
- }
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- case c <- 1:
- print(2)
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- println() // ERROR "unreachable code"
- default:
- select {}
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- select {}
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- goto L // ERROR "unreachable code"
- case c <- 1:
- print(2)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- default:
- print(2)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- default:
- break
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(2)
- panic("abc")
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- for {
- break L
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- select {
- case <-c:
- print(2)
- panic("abc")
- case c <- 1:
- print(2)
- break L
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- select {
- case <-c:
- print(1)
- panic("abc")
- default:
- select {}
- break // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x {
- default:
- return 4
- println() // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x {
- default:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- case 2:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 2:
- return 4
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- fallthrough
- case 2:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x {
- default:
- return 4
- break // ERROR "unreachable code"
- case 1:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x {
- case 1:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- println() // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- default:
- return 4
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- print(1)
- switch {
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- case float64:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case float64:
- return 4
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- fallthrough
- case float64:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- panic(3)
- break L // ERROR "unreachable code"
- default:
- return 4
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
- switch x.(type) {
- default:
- return 4
- break // ERROR "unreachable code"
- case int:
- print(2)
- panic(3)
- }
- println() // ok
-}
-
-var _ = func() int {
- print(1)
-L:
- switch x.(type) {
- case int:
- print(2)
- for {
- break L
- }
- default:
- return 4
- }
- println() // ok
-}
-
-// again, but without the leading print(1).
-// testing that everything works when the terminating statement is first.
-
-var _ = func() int {
- println() // ok
-}
-
-var _ = func() int {
- return 2
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- goto L
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- panic(2)
- println() // ERROR "unreachable code"
-}
-
-// but only builtin panic
-var _ = func() int {
- var panic = func(int) {}
- panic(2)
- println() // ok
-}
-
-var _ = func() int {
- {
- return 2
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- {
- return 2
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
-L:
- {
- goto L
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
-L:
- {
- goto L
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- {
- panic(2)
- println() // ERROR "unreachable code"
- }
-}
-
-var _ = func() int {
- {
- panic(2)
- }
- println() // ERROR "unreachable code"
-}
-
-var _ = func() int {
- return 2
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- goto L
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- panic(2)
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- return 2
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- {
- goto L
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- panic(2)
- { // ERROR "unreachable code"
- }
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- return 2
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
-L:
- {
- goto L
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() int {
- {
- panic(2)
- }
- { // ERROR "unreachable code"
- }
- println() // ok
-}
-
-var _ = func() {
- // goto without label used to panic
- goto
-}
-
-func _() int {
- // Empty switch tag with non-bool case value used to panic.
- switch {
- case 1:
- println()
- }
- println()
-}
+++ /dev/null
-// Test of examples with divergent packages.
-
-// Package buf ...
-package buf
-
-// Buf is a ...
-type Buf []byte
-
-// Append ...
-func (*Buf) Append([]byte) {}
-
-func (Buf) Reset() {}
-
-func (Buf) Len() int { return 0 }
-
-// DefaultBuf is a ...
-var DefaultBuf Buf
+++ /dev/null
-// Test of examples with divergent packages.
-
-package buf_test
-
-func Example() {} // OK because is package-level.
-
-func Example_suffix() {} // OK because refers to suffix annotation.
-
-func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
-
-func ExampleBuf() {} // OK because refers to known top-level type.
-
-func ExampleBuf_Append() {} // OK because refers to known method.
-
-func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear"
-
-func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
-
-func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad"
-
-func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
-
-func ExampleDefaultBuf() {} // OK because refers to top-level identifier.
-
-func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
-
-func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
-
-// "Puffer" is German for "Buffer".
-
-func ExamplePuffer() {} // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
-
-func ExamplePuffer_Append() {} // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
-
-func ExamplePuffer_suffix() {} // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
+++ /dev/null
-package testdata
-
-import (
- "log"
- "net/http"
-)
-
-func goodHTTPGet() {
- res, err := http.Get("http://foo.com")
- if err != nil {
- log.Fatal(err)
- }
- defer res.Body.Close()
-}
-
-func badHTTPGet() {
- res, err := http.Get("http://foo.com")
- defer res.Body.Close() // ERROR "using res before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badHTTPHead() {
- res, err := http.Head("http://foo.com")
- defer res.Body.Close() // ERROR "using res before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func goodClientGet() {
- client := http.DefaultClient
- res, err := client.Get("http://foo.com")
- if err != nil {
- log.Fatal(err)
- }
- defer res.Body.Close()
-}
-
-func badClientPtrGet() {
- client := http.DefaultClient
- resp, err := client.Get("http://foo.com")
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badClientGet() {
- client := http.Client{}
- resp, err := client.Get("http://foo.com")
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badClientPtrDo() {
- client := http.DefaultClient
- req, err := http.NewRequest("GET", "http://foo.com", nil)
- if err != nil {
- log.Fatal(err)
- }
-
- resp, err := client.Do(req)
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func badClientDo() {
- var client http.Client
- req, err := http.NewRequest("GET", "http://foo.com", nil)
- if err != nil {
- log.Fatal(err)
- }
-
- resp, err := client.Do(req)
- defer resp.Body.Close() // ERROR "using resp before checking for errors"
- if err != nil {
- log.Fatal(err)
- }
-}
+++ /dev/null
-// Test of examples.
-
-package testdata
-
-func Example() {} // OK because is package-level.
-
-func Example_suffix() // OK because refers to suffix annotation.
-
-func Example_BadSuffix() // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf() // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_Append() {} // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_Clear() {} // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
-
-func ExampleBuf_Append_Bad() {} // OK because non-test package was excluded. No false positives wanted.
-
-func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
-
-func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
-
-func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
-
-// "Puffer" is German for "Buffer".
-
-func ExamplePuffer() // OK because non-test package was excluded. No false positives wanted.
-
-func ExamplePuffer_Append() // OK because non-test package was excluded. No false positives wanted.
-
-func ExamplePuffer_suffix() // OK because non-test package was excluded. No false positives wanted.
+++ /dev/null
-// Copyright 2016 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 testdata
-
-import (
- "context"
- "log"
- "os"
- "testing"
-)
-
-// Check the three functions and assignment forms (var, :=, =) we look for.
-// (Do these early: line numbers are fragile.)
-func _() {
- var ctx, cancel = context.WithCancel() // ERROR "the cancel function is not used on all paths \(possible context leak\)"
-} // ERROR "this return statement may be reached without using the cancel var defined on line 17"
-
-func _() {
- ctx, cancel2 := context.WithDeadline() // ERROR "the cancel2 function is not used..."
-} // ERROR "may be reached without using the cancel2 var defined on line 21"
-
-func _() {
- var ctx context.Context
- var cancel3 func()
- ctx, cancel3 = context.WithTimeout() // ERROR "function is not used..."
-} // ERROR "this return statement may be reached without using the cancel3 var defined on line 27"
-
-func _() {
- ctx, _ := context.WithCancel() // ERROR "the cancel function returned by context.WithCancel should be called, not discarded, to avoid a context leak"
- ctx, _ = context.WithTimeout() // ERROR "the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak"
- ctx, _ = context.WithDeadline() // ERROR "the cancel function returned by context.WithDeadline should be called, not discarded, to avoid a context leak"
-}
-
-func _() {
- ctx, cancel := context.WithCancel()
- defer cancel() // ok
-}
-
-func _() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- if condition {
- cancel()
- }
- return // ERROR "this return statement may be reached without using the cancel var"
-}
-
-func _() {
- ctx, cancel := context.WithCancel()
- if condition {
- cancel()
- } else {
- // ok: infinite loop
- for {
- print(0)
- }
- }
-}
-
-func _() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- if condition {
- cancel()
- } else {
- for i := 0; i < 10; i++ {
- print(0)
- }
- }
-} // ERROR "this return statement may be reached without using the cancel var"
-
-func _() {
- ctx, cancel := context.WithCancel()
- // ok: used on all paths
- switch someInt {
- case 0:
- new(testing.T).FailNow()
- case 1:
- log.Fatal()
- case 2:
- cancel()
- case 3:
- print("hi")
- fallthrough
- default:
- os.Exit(1)
- }
-}
-
-func _() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- switch someInt {
- case 0:
- new(testing.T).FailNow()
- case 1:
- log.Fatal()
- case 2:
- cancel()
- case 3:
- print("hi") // falls through to implicit return
- default:
- os.Exit(1)
- }
-} // ERROR "this return statement may be reached without using the cancel var"
-
-func _(ch chan int) int {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- select {
- case <-ch:
- new(testing.T).FailNow()
- case y <- ch:
- print("hi") // falls through to implicit return
- case ch <- 1:
- cancel()
- default:
- os.Exit(1)
- }
-} // ERROR "this return statement may be reached without using the cancel var"
-
-func _(ch chan int) int {
- ctx, cancel := context.WithCancel()
- // A blocking select must execute one of its cases.
- select {
- case <-ch:
- panic()
- }
-}
-
-func _() {
- go func() {
- ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
- print(ctx)
- }() // ERROR "may be reached without using the cancel var"
-}
-
-var condition bool
-var someInt int
-
-// Regression test for Go issue 16143.
-func _() {
- var x struct{ f func() }
- x.f()
-}
-
-// Regression test for Go issue 16230.
-func _() (ctx context.Context, cancel func()) {
- ctx, cancel = context.WithCancel()
- return // a naked return counts as a load of the named result values
-}
-
-// Same as above, but for literal function.
-var _ = func() (ctx context.Context, cancel func()) {
- ctx, cancel = context.WithCancel()
- return
-}
+++ /dev/null
-// 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 testdata
-
-func F() {}
-
-type T struct {
- F func()
-}
-
-func (T) M() {}
-
-var Fv = F
-
-func Comparison() {
- var t T
- var fn func()
- if fn == nil || Fv == nil || t.F == nil {
- // no error; these func vars or fields may be nil
- }
- if F == nil { // ERROR "comparison of function F == nil is always false"
- panic("can't happen")
- }
- if t.M == nil { // ERROR "comparison of function M == nil is always false"
- panic("can't happen")
- }
- if F != nil { // ERROR "comparison of function F != nil is always true"
- if t.M != nil { // ERROR "comparison of function M != nil is always true"
- return
- }
- }
- panic("can't happen")
-}
+++ /dev/null
-// Copyright 2012 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.
-
-// This file contains tests for the rangeloop checker.
-
-package testdata
-
-func RangeLoopTests() {
- var s []int
- for i, v := range s {
- go func() {
- println(i) // ERROR "loop variable i captured by func literal"
- println(v) // ERROR "loop variable v captured by func literal"
- }()
- }
- for i, v := range s {
- defer func() {
- println(i) // ERROR "loop variable i captured by func literal"
- println(v) // ERROR "loop variable v captured by func literal"
- }()
- }
- for i := range s {
- go func() {
- println(i) // ERROR "loop variable i captured by func literal"
- }()
- }
- for _, v := range s {
- go func() {
- println(v) // ERROR "loop variable v captured by func literal"
- }()
- }
- for i, v := range s {
- go func() {
- println(i, v)
- }()
- println("unfortunately, we don't catch the error above because of this statement")
- }
- for i, v := range s {
- go func(i, v int) {
- println(i, v)
- }(i, v)
- }
- for i, v := range s {
- i, v := i, v
- go func() {
- println(i, v)
- }()
- }
- // If the key of the range statement is not an identifier
- // the code should not panic (it used to).
- var x [2]int
- var f int
- for x[0], f = range s {
- go func() {
- _ = f // ERROR "loop variable f captured by func literal"
- }()
- }
- type T struct {
- v int
- }
- for _, v := range s {
- go func() {
- _ = T{v: 1}
- _ = []int{v: 1} // ERROR "loop variable v captured by func literal"
- }()
- }
-
- // ordinary for-loops
- for i := 0; i < 10; i++ {
- go func() {
- print(i) // ERROR "loop variable i captured by func literal"
- }()
- }
- for i, j := 0, 1; i < 100; i, j = j, i+j {
- go func() {
- print(j) // ERROR "loop variable j captured by func literal"
- }()
- }
- type cons struct {
- car int
- cdr *cons
- }
- var head *cons
- for p := head; p != nil; p = p.next {
- go func() {
- print(p.car) // ERROR "loop variable p captured by func literal"
- }()
- }
-}
+++ /dev/null
-// 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.
-
-// This file contains tests for the shadowed variable checker.
-// Some of these errors are caught by the compiler (shadowed return parameters for example)
-// but are nonetheless useful tests.
-
-package testdata
-
-import "os"
-
-func ShadowRead(f *os.File, buf []byte) (err error) {
- var x int
- if f != nil {
- err := 3 // OK - different type.
- _ = err
- }
- if f != nil {
- _, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13"
- if err != nil {
- return err
- }
- i := 3 // OK
- _ = i
- }
- if f != nil {
- x := one() // ERROR "declaration of .x. shadows declaration at shadow.go:14"
- var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at shadow.go:13"
- if x == 1 && err != nil {
- return err
- }
- }
- for i := 0; i < 10; i++ {
- i := i // OK: obviously intentional idiomatic redeclaration
- go func() {
- println(i)
- }()
- }
- var shadowTemp interface{}
- switch shadowTemp := shadowTemp.(type) { // OK: obviously intentional idiomatic redeclaration
- case int:
- println("OK")
- _ = shadowTemp
- }
- if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration
- var f *os.File // OK because f is not mentioned later in the function.
- // The declaration of x is a shadow because x is mentioned below.
- var x int // ERROR "declaration of .x. shadows declaration at shadow.go:14"
- _, _, _ = x, f, shadowTemp
- }
- // Use a couple of variables to trigger shadowing errors.
- _, _ = err, x
- return
-}
-
-func one() int {
- return 1
-}
-
-// Must not complain with an internal error for the
-// implicitly declared type switch variable v.
-func issue26725(x interface{}) int {
- switch v := x.(type) {
- case int, int32:
- if v, ok := x.(int); ok {
- return v
- }
- case int64:
- return int(v)
- }
- return 0
-}
-
-// Verify that implicitly declared variables from
-// type switches are considered in shadowing analysis.
-func shadowTypeSwitch(a interface{}) {
- switch t := a.(type) {
- case int:
- {
- t := 0 // ERROR "declaration of .t. shadows declaration at shadow.go:78"
- _ = t
- }
- _ = t
- case uint:
- {
- t := uint(0) // OK because t is not mentioned later in this function
- _ = t
- }
- }
-}
+++ /dev/null
-// Copyright 2014 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.
-
-// This file contains tests for the suspicious shift checker.
-
-package testdata
-
-import (
- "fmt"
- "unsafe"
-)
-
-func ShiftTest() {
- var i8 int8
- _ = i8 << 7
- _ = (i8 + 1) << 8 // ERROR ".i8 . 1. .8 bits. too small for shift of 8"
- _ = i8 << (7 + 1) // ERROR "i8 .8 bits. too small for shift of 8"
- _ = i8 >> 8 // ERROR "i8 .8 bits. too small for shift of 8"
- i8 <<= 8 // ERROR "i8 .8 bits. too small for shift of 8"
- i8 >>= 8 // ERROR "i8 .8 bits. too small for shift of 8"
- var i16 int16
- _ = i16 << 15
- _ = i16 << 16 // ERROR "i16 .16 bits. too small for shift of 16"
- _ = i16 >> 16 // ERROR "i16 .16 bits. too small for shift of 16"
- i16 <<= 16 // ERROR "i16 .16 bits. too small for shift of 16"
- i16 >>= 16 // ERROR "i16 .16 bits. too small for shift of 16"
- var i32 int32
- _ = i32 << 31
- _ = i32 << 32 // ERROR "i32 .32 bits. too small for shift of 32"
- _ = i32 >> 32 // ERROR "i32 .32 bits. too small for shift of 32"
- i32 <<= 32 // ERROR "i32 .32 bits. too small for shift of 32"
- i32 >>= 32 // ERROR "i32 .32 bits. too small for shift of 32"
- var i64 int64
- _ = i64 << 63
- _ = i64 << 64 // ERROR "i64 .64 bits. too small for shift of 64"
- _ = i64 >> 64 // ERROR "i64 .64 bits. too small for shift of 64"
- i64 <<= 64 // ERROR "i64 .64 bits. too small for shift of 64"
- i64 >>= 64 // ERROR "i64 .64 bits. too small for shift of 64"
- var u8 uint8
- _ = u8 << 7
- _ = u8 << 8 // ERROR "u8 .8 bits. too small for shift of 8"
- _ = u8 >> 8 // ERROR "u8 .8 bits. too small for shift of 8"
- u8 <<= 8 // ERROR "u8 .8 bits. too small for shift of 8"
- u8 >>= 8 // ERROR "u8 .8 bits. too small for shift of 8"
- var u16 uint16
- _ = u16 << 15
- _ = u16 << 16 // ERROR "u16 .16 bits. too small for shift of 16"
- _ = u16 >> 16 // ERROR "u16 .16 bits. too small for shift of 16"
- u16 <<= 16 // ERROR "u16 .16 bits. too small for shift of 16"
- u16 >>= 16 // ERROR "u16 .16 bits. too small for shift of 16"
- var u32 uint32
- _ = u32 << 31
- _ = u32 << 32 // ERROR "u32 .32 bits. too small for shift of 32"
- _ = u32 >> 32 // ERROR "u32 .32 bits. too small for shift of 32"
- u32 <<= 32 // ERROR "u32 .32 bits. too small for shift of 32"
- u32 >>= 32 // ERROR "u32 .32 bits. too small for shift of 32"
- var u64 uint64
- _ = u64 << 63
- _ = u64 << 64 // ERROR "u64 .64 bits. too small for shift of 64"
- _ = u64 >> 64 // ERROR "u64 .64 bits. too small for shift of 64"
- u64 <<= 64 // ERROR "u64 .64 bits. too small for shift of 64"
- u64 >>= 64 // ERROR "u64 .64 bits. too small for shift of 64"
- _ = u64 << u64 // Non-constant shifts should succeed.
-
- var i int
- _ = i << 31
- const in = 8 * unsafe.Sizeof(i)
- _ = i << in // ERROR "too small for shift"
- _ = i >> in // ERROR "too small for shift"
- i <<= in // ERROR "too small for shift"
- i >>= in // ERROR "too small for shift"
- const ix = 8*unsafe.Sizeof(i) - 1
- _ = i << ix
- _ = i >> ix
- i <<= ix
- i >>= ix
-
- var u uint
- _ = u << 31
- const un = 8 * unsafe.Sizeof(u)
- _ = u << un // ERROR "too small for shift"
- _ = u >> un // ERROR "too small for shift"
- u <<= un // ERROR "too small for shift"
- u >>= un // ERROR "too small for shift"
- const ux = 8*unsafe.Sizeof(u) - 1
- _ = u << ux
- _ = u >> ux
- u <<= ux
- u >>= ux
-
- var p uintptr
- _ = p << 31
- const pn = 8 * unsafe.Sizeof(p)
- _ = p << pn // ERROR "too small for shift"
- _ = p >> pn // ERROR "too small for shift"
- p <<= pn // ERROR "too small for shift"
- p >>= pn // ERROR "too small for shift"
- const px = 8*unsafe.Sizeof(p) - 1
- _ = p << px
- _ = p >> px
- p <<= px
- p >>= px
-
- const oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks
-
- var h uintptr
- h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
- h <<= 8 * unsafe.Sizeof(h) // ERROR "too small for shift"
- h >>= 7 * unsafe.Alignof(h)
- h >>= 8 * unsafe.Alignof(h) // ERROR "too small for shift"
-}
-
-func ShiftDeadCode() {
- var i int
- const iBits = 8 * unsafe.Sizeof(i)
-
- if iBits <= 32 {
- if iBits == 16 {
- _ = i >> 8
- } else {
- _ = i >> 16
- }
- } else {
- _ = i >> 32
- }
-
- if iBits >= 64 {
- _ = i << 32
- if iBits == 128 {
- _ = i << 64
- }
- } else {
- _ = i << 16
- }
-
- if iBits == 64 {
- _ = i << 32
- }
-
- switch iBits {
- case 128, 64:
- _ = i << 32
- default:
- _ = i << 16
- }
-
- switch {
- case iBits < 32:
- _ = i << 16
- case iBits > 64:
- _ = i << 64
- default:
- _ = i << 64 // ERROR "too small for shift"
- }
-
- // Make sure other vet checks work in dead code.
- if iBits == 1024 {
- _ = i << 512 // OK
- fmt.Printf("foo %s bar", 123) // ERROR "Printf"
- }
-}
--- /dev/null
+// 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.
+
+// This file contains declarations to test the assembly in asm1.s.
+
+package testdata
+
+func arg1(x int8, y uint8)
--- /dev/null
+// 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.
+
+// +build amd64
+
+TEXT ·arg1(SB),0,$0-2
+ MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
// This file contains tests for the useless-assignment checker.
-package testdata
+package assign
import "math/rand"
--- /dev/null
+// 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.
+
+// This file contains tests for the atomic checker.
+
+package atomic
+
+import "sync/atomic"
+
+func AtomicTests() {
+ x := uint64(1)
+ x = atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
+}
--- /dev/null
+// Copyright 2014 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.
+
+// This file contains tests for the bool checker.
+
+package bool
+
+func _() {
+ var f, g func() int
+
+ if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w"
+ }
+}
--- /dev/null
+// 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.
+
+// This file contains tests for the cgo checker.
+
+package testdata
+
+// void f(void *p) {}
+import "C"
+
+import "unsafe"
+
+func CgoTests() {
+ var c chan bool
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer"
+}
--- /dev/null
+// Copyright 2012 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.
+
+// This file contains the test for untagged struct literals.
+
+package composite
+
+import "flag"
+
+// Testing is awkward because we need to reference things from a separate package
+// to trigger the warnings.
+
+var goodStructLiteral = flag.Flag{
+ Name: "Name",
+ Usage: "Usage",
+}
+
+var badStructLiteral = flag.Flag{ // ERROR "unkeyed fields"
+ "Name",
+ "Usage",
+ nil, // Value
+ "DefValue",
+}
--- /dev/null
+package copylock
+
+import "sync"
+
+func BadFunc() {
+ var x *sync.Mutex
+ p := x
+ var y sync.Mutex
+ p = &y
+ *p = *x // ERROR "assignment copies lock value to \*p: sync.Mutex"
+}
--- /dev/null
+// 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.
+
+// This file contains tests for the dead code checker.
+
+package deadcode
+
+func _() int {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+ return 3
+}
--- /dev/null
+package httpresponse
+
+import (
+ "log"
+ "net/http"
+)
+
+func goodHTTPGet() {
+ res, err := http.Get("http://foo.com")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer res.Body.Close()
+}
+
+func badHTTPGet() {
+ res, err := http.Get("http://foo.com")
+ defer res.Body.Close() // ERROR "using res before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
--- /dev/null
+// Copyright 2016 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 lostcancel
+
+import "context"
+
+func _() {
+ var _, cancel = context.WithCancel(context.Background()) // ERROR "the cancel function is not used on all paths \(possible context leak\)"
+ if false {
+ _ = cancel
+ }
+} // ERROR "this return statement may be reached without using the cancel var defined on line 10"
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file contains tests for the canonical method checker.
-
// This file contains the code to check canonical methods.
-package testdata
+package method
-import (
- "fmt"
-)
+import "fmt"
type MethodTest int
func (t *MethodTest) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan\(fmt\.ScanState, rune\) error"
}
-
-type MethodTestInterface interface {
- ReadByte() byte // ERROR "should have signature ReadByte\(\) \(byte, error\)"
-}
--- /dev/null
+// 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 nilfunc
+
+func F() {}
+
+func Comparison() {
+ if F == nil { // ERROR "comparison of function F == nil is always false"
+ panic("can't happen")
+ }
+}
// This file contains tests for the printf checker.
-package testdata
+package print
import (
"fmt"
fmt.Printf("%U", x) // ERROR "Printf format %U has arg x of wrong type float64"
fmt.Printf("%x", nil) // ERROR "Printf format %x has arg nil of wrong type untyped nil"
fmt.Printf("%X", 2.3) // ERROR "Printf format %X has arg 2.3 of wrong type float64"
- fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type testdata.ptrStringer"
- fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type testdata.ptrStringer"
- fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type testdata.embeddedStringer"
- fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type testdata.embeddedStringer"
- fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type testdata.notstringer"
- fmt.Printf("%t", notstringerv) // ERROR "Printf format %t has arg notstringerv of wrong type testdata.notstringer"
- fmt.Printf("%t", stringerarrayv) // ERROR "Printf format %t has arg stringerarrayv of wrong type testdata.stringerarray"
- fmt.Printf("%t", notstringerarrayv) // ERROR "Printf format %t has arg notstringerarrayv of wrong type testdata.notstringerarray"
- fmt.Printf("%q", notstringerarrayv) // ERROR "Printf format %q has arg notstringerarrayv of wrong type testdata.notstringerarray"
- fmt.Printf("%d", BoolFormatter(true)) // ERROR "Printf format %d has arg BoolFormatter\(true\) of wrong type testdata.BoolFormatter"
+ fmt.Printf("%s", stringerv) // ERROR "Printf format %s has arg stringerv of wrong type print.ptrStringer"
+ fmt.Printf("%t", stringerv) // ERROR "Printf format %t has arg stringerv of wrong type print.ptrStringer"
+ fmt.Printf("%s", embeddedStringerv) // ERROR "Printf format %s has arg embeddedStringerv of wrong type print.embeddedStringer"
+ fmt.Printf("%t", embeddedStringerv) // ERROR "Printf format %t has arg embeddedStringerv of wrong type print.embeddedStringer"
+ fmt.Printf("%q", notstringerv) // ERROR "Printf format %q has arg notstringerv of wrong type print.notstringer"
+ fmt.Printf("%t", notstringerv) // ERROR "Printf format %t has arg notstringerv of wrong type print.notstringer"
+ fmt.Printf("%t", stringerarrayv) // ERROR "Printf format %t has arg stringerarrayv of wrong type print.stringerarray"
+ fmt.Printf("%t", notstringerarrayv) // ERROR "Printf format %t has arg notstringerarrayv of wrong type print.notstringerarray"
+ fmt.Printf("%q", notstringerarrayv) // ERROR "Printf format %q has arg notstringerarrayv of wrong type print.notstringerarray"
+ fmt.Printf("%d", BoolFormatter(true)) // ERROR "Printf format %d has arg BoolFormatter\(true\) of wrong type print.BoolFormatter"
fmt.Printf("%z", FormatterVal(true)) // correct (the type is responsible for formatting)
fmt.Printf("%d", FormatterVal(true)) // correct (the type is responsible for formatting)
fmt.Printf("%s", nonemptyinterface) // correct (the type is responsible for formatting)
Printf("d%", 2) // ERROR "Printf format % is missing verb at end of string"
Printf("%d", percentDV)
Printf("%d", &percentDV)
- Printf("%d", notPercentDV) // ERROR "Printf format %d has arg notPercentDV of wrong type testdata.notPercentDStruct"
- Printf("%d", ¬PercentDV) // ERROR "Printf format %d has arg ¬PercentDV of wrong type \*testdata.notPercentDStruct"
+ Printf("%d", notPercentDV) // ERROR "Printf format %d has arg notPercentDV of wrong type print.notPercentDStruct"
+ Printf("%d", ¬PercentDV) // ERROR "Printf format %d has arg ¬PercentDV of wrong type \*print.notPercentDStruct"
Printf("%p", ¬PercentDV) // Works regardless: we print it as a pointer.
- Printf("%q", &percentDV) // ERROR "Printf format %q has arg &percentDV of wrong type \*testdata.percentDStruct"
+ Printf("%q", &percentDV) // ERROR "Printf format %q has arg &percentDV of wrong type \*print.percentDStruct"
Printf("%s", percentSV)
Printf("%s", &percentSV)
// Good argument reorderings.
Printf("%T", someFunction) // ok: maybe someone wants to see the type
// Bug: used to recur forever.
Printf("%p %x", recursiveStructV, recursiveStructV.next)
- Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next) // ERROR "Printf format %x has arg recursiveStruct1V\.next of wrong type \*testdata\.RecursiveStruct2"
+ Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next) // ERROR "Printf format %x has arg recursiveStruct1V\.next of wrong type \*print\.RecursiveStruct2"
Printf("%p %x", recursiveSliceV, recursiveSliceV)
Printf("%p %x", recursiveMapV, recursiveMapV)
// Special handling for Log.
// Multiple string arguments before variadic args
errorf("WARNING", "foobar") // OK
errorf("INFO", "s=%s, n=%d", "foo", 1) // OK
- errorf("ERROR", "%d") // no error "errorf format %d reads arg #1, but call has 0 args"
+ errorf("ERROR", "%d") // ERROR "errorf format %d reads arg #1, but call has 0 args"
// Printf from external package
// externalprintf.Printf("%d", 42) // OK
fmt.Printf("%s", unexportedInterface{3}) // ok; we can't see the problem
us := unexportedStringer{}
- fmt.Printf("%s", us) // ERROR "Printf format %s has arg us of wrong type testdata.unexportedStringer"
- fmt.Printf("%s", &us) // ERROR "Printf format %s has arg &us of wrong type [*]testdata.unexportedStringer"
+ fmt.Printf("%s", us) // ERROR "Printf format %s has arg us of wrong type print.unexportedStringer"
+ fmt.Printf("%s", &us) // ERROR "Printf format %s has arg &us of wrong type [*]print.unexportedStringer"
usf := unexportedStringerOtherFields{
s: "foo",
S: "bar",
}
- fmt.Printf("%s", usf) // ERROR "Printf format %s has arg usf of wrong type testdata.unexportedStringerOtherFields"
- fmt.Printf("%s", &usf) // ERROR "Printf format %s has arg &usf of wrong type [*]testdata.unexportedStringerOtherFields"
+ fmt.Printf("%s", usf) // ERROR "Printf format %s has arg usf of wrong type print.unexportedStringerOtherFields"
+ fmt.Printf("%s", &usf) // ERROR "Printf format %s has arg &usf of wrong type [*]print.unexportedStringerOtherFields"
ue := unexportedError{
e: &errorer{},
}
- fmt.Printf("%s", ue) // ERROR "Printf format %s has arg ue of wrong type testdata.unexportedError"
- fmt.Printf("%s", &ue) // ERROR "Printf format %s has arg &ue of wrong type [*]testdata.unexportedError"
+ fmt.Printf("%s", ue) // ERROR "Printf format %s has arg ue of wrong type print.unexportedError"
+ fmt.Printf("%s", &ue) // ERROR "Printf format %s has arg &ue of wrong type [*]print.unexportedError"
uef := unexportedErrorOtherFields{
s: "foo",
e: &errorer{},
S: "bar",
}
- fmt.Printf("%s", uef) // ERROR "Printf format %s has arg uef of wrong type testdata.unexportedErrorOtherFields"
- fmt.Printf("%s", &uef) // ERROR "Printf format %s has arg &uef of wrong type [*]testdata.unexportedErrorOtherFields"
+ fmt.Printf("%s", uef) // ERROR "Printf format %s has arg uef of wrong type print.unexportedErrorOtherFields"
+ fmt.Printf("%s", &uef) // ERROR "Printf format %s has arg &uef of wrong type [*]print.unexportedErrorOtherFields"
uce := unexportedCustomError{
e: errorer{},
}
- fmt.Printf("%s", uce) // ERROR "Printf format %s has arg uce of wrong type testdata.unexportedCustomError"
+ fmt.Printf("%s", uce) // ERROR "Printf format %s has arg uce of wrong type print.unexportedCustomError"
uei := unexportedErrorInterface{}
- fmt.Printf("%s", uei) // ERROR "Printf format %s has arg uei of wrong type testdata.unexportedErrorInterface"
+ fmt.Printf("%s", uei) // ERROR "Printf format %s has arg uei of wrong type print.unexportedErrorInterface"
fmt.Println("foo\n", "bar") // not an error
fmt.Println("foo\n") // ERROR "Println arg list ends with redundant newline"
intSlice := []int{3, 4}
fmt.Printf("%s", intSlice) // ERROR "Printf format %s has arg intSlice of wrong type \[\]int"
nonStringerArray := [1]unexportedStringer{{}}
- fmt.Printf("%s", nonStringerArray) // ERROR "Printf format %s has arg nonStringerArray of wrong type \[1\]testdata.unexportedStringer"
+ fmt.Printf("%s", nonStringerArray) // ERROR "Printf format %s has arg nonStringerArray of wrong type \[1\]print.unexportedStringer"
fmt.Printf("%s", []stringer{3, 4}) // not an error
fmt.Printf("%s", [2]stringer{3, 4}) // not an error
}
type T1 struct {
X *T2
}
- fmt.Printf("%s\n", T1{&T2{"x"}}) // ERROR "Printf format %s has arg T1{&T2{.x.}} of wrong type testdata\.T1"
+ fmt.Printf("%s\n", T1{&T2{"x"}}) // ERROR "Printf format %s has arg T1{&T2{.x.}} of wrong type print\.T1"
}
--- /dev/null
+// Copyright 2012 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.
+
+// This file contains tests for the rangeloop checker.
+
+package rangeloop
+
+func RangeLoopTests() {
+ var s []int
+ for i, v := range s {
+ go func() {
+ println(i) // ERROR "loop variable i captured by func literal"
+ println(v) // ERROR "loop variable v captured by func literal"
+ }()
+ }
+}
--- /dev/null
+// Copyright 2014 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.
+
+// This file contains tests for the suspicious shift checker.
+
+package shift
+
+func ShiftTest() {
+ var i8 int8
+ _ = i8 << 7
+ _ = (i8 + 1) << 8 // ERROR ".i8 . 1. .8 bits. too small for shift of 8"
+}
--- /dev/null
+// 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.
+
+// This file contains the test for canonical struct tags.
+
+package structtag
+
+type StructTagTest struct {
+ A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
+}
package main
+import "fmt"
+
func main() {
+ fmt.Printf("%s", 0)
}
package main
-func ignore() {
+import "fmt"
+
+func main() {
+ fmt.Printf("%s", 0)
}
--- /dev/null
+package testdata
+
+func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
--- /dev/null
+// Copyright 2018 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.
+
+// This file contains tests for the unmarshal checker.
+
+package unmarshal
+
+import "encoding/json"
+
+func _() {
+ type t struct {
+ a int
+ }
+ var v t
+
+ json.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument"
+}
--- /dev/null
+// Copyright 2014 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 unsafeptr
+
+import "unsafe"
+
+func _() {
+ var x unsafe.Pointer
+ var y uintptr
+ x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
+ _ = x
+}
--- /dev/null
+// 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.
+
+// This file contains tests for the unusedresult checker.
+
+package unused
+
+import "fmt"
+
+func _() {
+ fmt.Errorf("") // ERROR "result of fmt.Errorf call not used"
+}
+++ /dev/null
-// 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.
-
-// This file contains the test for canonical struct tags.
-
-package testdata
-
-import "encoding/xml"
-
-type StructTagTest struct {
- A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
- B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
- C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get"
- D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
- E int "ct\brl:\"char\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
- F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
- G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
- H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
- I int `x:"foo",y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
- J int `x:"foo"y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
- OK0 int `x:"y" u:"v" w:""`
- OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
- OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
- OK3 int `under_scores:"and" CAPS:"ARE_OK"`
-}
-
-type UnexportedEncodingTagTest struct {
- x int `json:"xx"` // ERROR "struct field x has json tag but is not exported"
- y int `xml:"yy"` // ERROR "struct field y has xml tag but is not exported"
- z int
- A int `json:"aa" xml:"bb"`
-}
-
-type unexp struct{}
-
-type JSONEmbeddedField struct {
- UnexportedEncodingTagTest `is:"embedded"`
- unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
-}
-
-type AnonymousJSON struct{}
-type AnonymousXML struct{}
-
-type AnonymousJSONField struct {
- DuplicateAnonJSON int `json:"a"`
-
- A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
-}
-
-type DuplicateJSONFields struct {
- JSON int `json:"a"`
- DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:52"
- IgnoredJSON int `json:"-"`
- OtherIgnoredJSON int `json:"-"`
- OmitJSON int `json:",omitempty"`
- OtherOmitJSON int `json:",omitempty"`
- DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:52"
- NonJSON int `foo:"a"`
- DuplicateNonJSON int `foo:"a"`
- Embedded struct {
- DuplicateJSON int `json:"a"` // OK because it's not in the same struct type
- }
- AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:52"
-
- AnonymousJSONField // ERROR "struct field DuplicateAnonJSON repeats json tag .a. also at structtag.go:52"
-
- XML int `xml:"a"`
- DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:68"
- IgnoredXML int `xml:"-"`
- OtherIgnoredXML int `xml:"-"`
- OmitXML int `xml:",omitempty"`
- OtherOmitXML int `xml:",omitempty"`
- DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:68"
- NonXML int `foo:"a"`
- DuplicateNonXML int `foo:"a"`
- Embedded2 struct {
- DuplicateXML int `xml:"a"` // OK because it's not in the same struct type
- }
- AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:68"
- Attribute struct {
- XMLName xml.Name `xml:"b"`
- NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct.
- Attr int `xml:"b,attr"` // OK because <b b="0"><b>0</b></b> is valid.
- DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:84"
- DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:84"
-
- AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:84"
- }
-
- AnonymousJSONField `json:"not_anon"` // ok; fields aren't embedded in JSON
- AnonymousJSONField `json:"-"` // ok; entire field is ignored in JSON
-}
-
-type UnexpectedSpacetest struct {
- A int `json:"a,omitempty"`
- B int `json:"b, omitempty"` // ERROR "suspicious space in struct tag value"
- C int `json:"c ,omitempty"`
- D int `json:"d,omitempty, string"` // ERROR "suspicious space in struct tag value"
- E int `xml:"e local"`
- F int `xml:"f "` // ERROR "suspicious space in struct tag value"
- G int `xml:" g"` // ERROR "suspicious space in struct tag value"
- H int `xml:"h ,omitempty"` // ERROR "suspicious space in struct tag value"
- I int `xml:"i, omitempty"` // ERROR "suspicious space in struct tag value"
- J int `xml:"j local ,omitempty"` // ERROR "suspicious space in struct tag value"
- K int `xml:"k local, omitempty"` // ERROR "suspicious space in struct tag value"
- L int `xml:" l local,omitempty"` // ERROR "suspicious space in struct tag value"
- M int `xml:"m local,omitempty"` // ERROR "suspicious space in struct tag value"
- N int `xml:" "` // ERROR "suspicious space in struct tag value"
- O int `xml:""`
- P int `xml:","`
- Q int `foo:" doesn't care "`
-}
+++ /dev/null
-package testdata
-
-import (
- "testing"
-)
-
-// Buf is a ...
-type Buf []byte
-
-// Append ...
-func (*Buf) Append([]byte) {}
-
-func (Buf) Reset() {}
-
-func (Buf) Len() int { return 0 }
-
-// DefaultBuf is a ...
-var DefaultBuf Buf
-
-func Example() {} // OK because is package-level.
-
-func Example_goodSuffix() // OK because refers to suffix annotation.
-
-func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
-
-func ExampleBuf() // OK because refers to known top-level type.
-
-func ExampleBuf_Append() {} // OK because refers to known method.
-
-func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear"
-
-func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
-
-func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad"
-
-func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
-
-func ExampleDefaultBuf() {} // OK because refers to top-level identifier.
-
-func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
-
-func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
-
-// "Puffer" is German for "Buffer".
-
-func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
-
-func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
-
-func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
-
-func nonTest() {} // OK because it doesn't start with "Test".
-
-func (Buf) TesthasReceiver() {} // OK because it has a receiver.
-
-func TestOKSuffix(*testing.T) {} // OK because first char after "Test" is Uppercase.
-
-func TestÜnicodeWorks(*testing.T) {} // OK because the first char after "Test" is Uppercase.
-
-func TestbadSuffix(*testing.T) {} // ERROR "first letter after 'Test' must not be lowercase"
-
-func TestemptyImportBadSuffix(*T) {} // ERROR "first letter after 'Test' must not be lowercase"
-
-func Test(*testing.T) {} // OK "Test" on its own is considered a test.
-
-func Testify() {} // OK because it takes no parameters.
-
-func TesttooManyParams(*testing.T, string) {} // OK because it takes too many parameters.
-
-func TesttooManyNames(a, b *testing.T) {} // OK because it takes too many names.
-
-func TestnoTParam(string) {} // OK because it doesn't take a *testing.T
-
-func BenchmarkbadSuffix(*testing.B) {} // ERROR "first letter after 'Benchmark' must not be lowercase"
+++ /dev/null
-// Copyright 2018 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.
-
-// This file contains tests for the unmarshal checker.
-
-package testdata
-
-import (
- "bytes"
- "encoding/gob"
- "encoding/json"
- "encoding/xml"
- "errors"
- "fmt"
-)
-
-func _() {
- type t struct {
- a int
- }
- var v t
- var r io.Reader
-
- json.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument"
- json.Unmarshal([]byte{}, &v)
- json.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer"
- json.NewDecoder(r).Decode(&v)
- gob.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer"
- gob.NewDecoder(r).Decode(&v)
- xml.Unmarshal([]byte{}, v) // ERROR "call of Unmarshal passes non-pointer as second argument"
- xml.Unmarshal([]byte{}, &v)
- xml.NewDecoder(r).Decode(v) // ERROR "call of Decode passes non-pointer"
- xml.NewDecoder(r).Decode(&v)
-
- var p *t
- json.Unmarshal([]byte{}, p)
- json.Unmarshal([]byte{}, *p) // ERROR "call of Unmarshal passes non-pointer as second argument"
- json.NewDecoder(r).Decode(p)
- json.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer"
- gob.NewDecoder(r).Decode(p)
- gob.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer"
- xml.Unmarshal([]byte{}, p)
- xml.Unmarshal([]byte{}, *p) // ERROR "call of Unmarshal passes non-pointer as second argument"
- xml.NewDecoder(r).Decode(p)
- xml.NewDecoder(r).Decode(*p) // ERROR "call of Decode passes non-pointer"
-
- var i interface{}
- json.Unmarshal([]byte{}, i)
- json.NewDecoder(r).Decode(i)
-
- json.Unmarshal([]byte{}, nil) // ERROR "call of Unmarshal passes non-pointer as second argument"
- json.Unmarshal([]byte{}, []t{}) // ERROR "call of Unmarshal passes non-pointer as second argument"
- json.Unmarshal([]byte{}, map[string]int{}) // ERROR "call of Unmarshal passes non-pointer as second argument"
- json.NewDecoder(r).Decode(nil) // ERROR "call of Decode passes non-pointer"
- json.NewDecoder(r).Decode([]t{}) // ERROR "call of Decode passes non-pointer"
- json.NewDecoder(r).Decode(map[string]int{}) // ERROR "call of Decode passes non-pointer"
-
- json.Unmarshal(func() ([]byte, interface{}) { return []byte{}, v }())
-}
+++ /dev/null
-// Copyright 2014 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 testdata
-
-import (
- "reflect"
- "unsafe"
-)
-
-func f() {
- var x unsafe.Pointer
- var y uintptr
- x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
- y = uintptr(x)
-
- // only allowed pointer arithmetic is ptr +/-/&^ num.
- // num+ptr is technically okay but still flagged: write ptr+num instead.
- x = unsafe.Pointer(uintptr(x) + 1)
- x = unsafe.Pointer(1 + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(uintptr(x) - 1)
- x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(uintptr(x) &^ 3)
- x = unsafe.Pointer(1 &^ uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
-
- // certain uses of reflect are okay
- var v reflect.Value
- x = unsafe.Pointer(v.Pointer())
- x = unsafe.Pointer(v.UnsafeAddr())
- var s1 *reflect.StringHeader
- x = unsafe.Pointer(s1.Data)
- var s2 *reflect.SliceHeader
- x = unsafe.Pointer(s2.Data)
- var s3 reflect.StringHeader
- x = unsafe.Pointer(s3.Data) // ERROR "possible misuse of unsafe.Pointer"
- var s4 reflect.SliceHeader
- x = unsafe.Pointer(s4.Data) // ERROR "possible misuse of unsafe.Pointer"
-
- // but only in reflect
- var vv V
- x = unsafe.Pointer(vv.Pointer()) // ERROR "possible misuse of unsafe.Pointer"
- x = unsafe.Pointer(vv.UnsafeAddr()) // ERROR "possible misuse of unsafe.Pointer"
- var ss1 *StringHeader
- x = unsafe.Pointer(ss1.Data) // ERROR "possible misuse of unsafe.Pointer"
- var ss2 *SliceHeader
- x = unsafe.Pointer(ss2.Data) // ERROR "possible misuse of unsafe.Pointer"
-
-}
-
-type V interface {
- Pointer() uintptr
- UnsafeAddr() uintptr
-}
-
-type StringHeader struct {
- Data uintptr
-}
-
-type SliceHeader struct {
- Data uintptr
-}
+++ /dev/null
-// 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.
-
-// This file contains tests for the unusedresult checker.
-
-package testdata
-
-import (
- "bytes"
- "errors"
- "fmt"
-)
-
-func _() {
- fmt.Errorf("") // ERROR "result of fmt.Errorf call not used"
- _ = fmt.Errorf("")
-
- errors.New("") // ERROR "result of errors.New call not used"
-
- err := errors.New("")
- err.Error() // ERROR "result of \(error\).Error call not used"
-
- var buf bytes.Buffer
- buf.String() // ERROR "result of \(bytes.Buffer\).String call not used"
-
- fmt.Sprint("") // ERROR "result of fmt.Sprint call not used"
- fmt.Sprintf("") // ERROR "result of fmt.Sprintf call not used"
-}
+++ /dev/null
-// 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.
-
-package main
-
-import (
- "go/ast"
- "go/types"
- "strings"
- "unicode"
- "unicode/utf8"
-)
-
-func init() {
- register("tests",
- "check for common mistaken usages of tests/documentation examples",
- checkTestFunctions,
- funcDecl)
-}
-
-func isExampleSuffix(s string) bool {
- r, size := utf8.DecodeRuneInString(s)
- return size > 0 && unicode.IsLower(r)
-}
-
-func isTestSuffix(name string) bool {
- if len(name) == 0 {
- // "Test" is ok.
- return true
- }
- r, _ := utf8.DecodeRuneInString(name)
- return !unicode.IsLower(r)
-}
-
-func isTestParam(typ ast.Expr, wantType string) bool {
- ptr, ok := typ.(*ast.StarExpr)
- if !ok {
- // Not a pointer.
- return false
- }
- // No easy way of making sure it's a *testing.T or *testing.B:
- // ensure the name of the type matches.
- if name, ok := ptr.X.(*ast.Ident); ok {
- return name.Name == wantType
- }
- if sel, ok := ptr.X.(*ast.SelectorExpr); ok {
- return sel.Sel.Name == wantType
- }
- return false
-}
-
-func lookup(name string, scopes []*types.Scope) types.Object {
- for _, scope := range scopes {
- if o := scope.Lookup(name); o != nil {
- return o
- }
- }
- return nil
-}
-
-func extendedScope(f *File) []*types.Scope {
- scopes := []*types.Scope{f.pkg.typesPkg.Scope()}
- if f.basePkg != nil {
- scopes = append(scopes, f.basePkg.typesPkg.Scope())
- } else {
- // If basePkg is not specified (e.g. when checking a single file) try to
- // find it among imports.
- pkgName := f.pkg.typesPkg.Name()
- if strings.HasSuffix(pkgName, "_test") {
- basePkgName := strings.TrimSuffix(pkgName, "_test")
- for _, p := range f.pkg.typesPkg.Imports() {
- if p.Name() == basePkgName {
- scopes = append(scopes, p.Scope())
- break
- }
- }
- }
- }
- return scopes
-}
-
-func checkExample(fn *ast.FuncDecl, f *File, report reporter) {
- fnName := fn.Name.Name
- if params := fn.Type.Params; len(params.List) != 0 {
- report("%s should be niladic", fnName)
- }
- if results := fn.Type.Results; results != nil && len(results.List) != 0 {
- report("%s should return nothing", fnName)
- }
-
- if filesRun && !includesNonTest {
- // The coherence checks between a test and the package it tests
- // will report false positives if no non-test files have
- // been provided.
- return
- }
-
- if fnName == "Example" {
- // Nothing more to do.
- return
- }
-
- var (
- exName = strings.TrimPrefix(fnName, "Example")
- elems = strings.SplitN(exName, "_", 3)
- ident = elems[0]
- obj = lookup(ident, extendedScope(f))
- )
- if ident != "" && obj == nil {
- // Check ExampleFoo and ExampleBadFoo.
- report("%s refers to unknown identifier: %s", fnName, ident)
- // Abort since obj is absent and no subsequent checks can be performed.
- return
- }
- if len(elems) < 2 {
- // Nothing more to do.
- return
- }
-
- if ident == "" {
- // Check Example_suffix and Example_BadSuffix.
- if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) {
- report("%s has malformed example suffix: %s", fnName, residual)
- }
- return
- }
-
- mmbr := elems[1]
- if !isExampleSuffix(mmbr) {
- // Check ExampleFoo_Method and ExampleFoo_BadMethod.
- if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
- report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
- }
- }
- if len(elems) == 3 && !isExampleSuffix(elems[2]) {
- // Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix.
- report("%s has malformed example suffix: %s", fnName, elems[2])
- }
-}
-
-func checkTest(fn *ast.FuncDecl, prefix string, report reporter) {
- // Want functions with 0 results and 1 parameter.
- if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
- fn.Type.Params == nil ||
- len(fn.Type.Params.List) != 1 ||
- len(fn.Type.Params.List[0].Names) > 1 {
- return
- }
-
- // The param must look like a *testing.T or *testing.B.
- if !isTestParam(fn.Type.Params.List[0].Type, prefix[:1]) {
- return
- }
-
- if !isTestSuffix(fn.Name.Name[len(prefix):]) {
- report("%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix)
- }
-}
-
-type reporter func(format string, args ...interface{})
-
-// checkTestFunctions walks Test, Benchmark and Example functions checking
-// malformed names, wrong signatures and examples documenting nonexistent
-// identifiers.
-func checkTestFunctions(f *File, node ast.Node) {
- if !strings.HasSuffix(f.name, "_test.go") {
- return
- }
-
- fn, ok := node.(*ast.FuncDecl)
- if !ok || fn.Recv != nil {
- // Ignore non-functions or functions with receivers.
- return
- }
-
- report := func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) }
-
- switch {
- case strings.HasPrefix(fn.Name.Name, "Example"):
- checkExample(fn, f, report)
- case strings.HasPrefix(fn.Name.Name, "Test"):
- checkTest(fn, "Test", report)
- case strings.HasPrefix(fn.Name.Name, "Benchmark"):
- checkTest(fn, "Benchmark", report)
- }
-}
+++ /dev/null
-// 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.
-
-// This file contains the pieces of the tool that use typechecking from the go/types package.
-
-package main
-
-import (
- "go/ast"
- "go/build"
- "go/importer"
- "go/token"
- "go/types"
-)
-
-// stdImporter is the importer we use to import packages.
-// It is shared so that all packages are imported by the same importer.
-var stdImporter types.Importer
-
-var (
- errorType *types.Interface
- stringerType *types.Interface // possibly nil
- formatterType *types.Interface // possibly nil
-)
-
-func inittypes() {
- errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
-
- if typ := importType("fmt", "Stringer"); typ != nil {
- stringerType = typ.Underlying().(*types.Interface)
- }
- if typ := importType("fmt", "Formatter"); typ != nil {
- formatterType = typ.Underlying().(*types.Interface)
- }
-}
-
-// isNamedType reports whether t is the named type path.name.
-func isNamedType(t types.Type, path, name string) bool {
- n, ok := t.(*types.Named)
- if !ok {
- return false
- }
- obj := n.Obj()
- return obj.Name() == name && obj.Pkg() != nil && obj.Pkg().Path() == path
-}
-
-// importType returns the type denoted by the qualified identifier
-// path.name, and adds the respective package to the imports map
-// as a side effect. In case of an error, importType returns nil.
-func importType(path, name string) types.Type {
- pkg, err := stdImporter.Import(path)
- if err != nil {
- // This can happen if the package at path hasn't been compiled yet.
- warnf("import failed: %v", err)
- return nil
- }
- if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok {
- return obj.Type()
- }
- warnf("invalid type name %q", name)
- return nil
-}
-
-func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) []error {
- if stdImporter == nil {
- if *source {
- stdImporter = importer.For("source", nil)
- } else {
- stdImporter = importer.Default()
- }
- inittypes()
- }
- pkg.defs = make(map[*ast.Ident]types.Object)
- pkg.uses = make(map[*ast.Ident]types.Object)
- pkg.implicits = make(map[ast.Node]types.Object)
- pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection)
- pkg.spans = make(map[types.Object]Span)
- pkg.types = make(map[ast.Expr]types.TypeAndValue)
-
- var allErrors []error
- config := types.Config{
- // We use the same importer for all imports to ensure that
- // everybody sees identical packages for the given paths.
- Importer: stdImporter,
- // By providing a Config with our own error function, it will continue
- // past the first error. We collect them all for printing later.
- Error: func(e error) {
- allErrors = append(allErrors, e)
- },
-
- Sizes: archSizes,
- }
- info := &types.Info{
- Selections: pkg.selectors,
- Types: pkg.types,
- Defs: pkg.defs,
- Uses: pkg.uses,
- Implicits: pkg.implicits,
- }
- typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
- if len(allErrors) == 0 && err != nil {
- allErrors = append(allErrors, err)
- }
- pkg.typesPkg = typesPkg
- // update spans
- for id, obj := range pkg.defs {
- // Ignore identifiers that don't denote objects
- // (package names, symbolic variables such as t
- // in t := x.(type) of type switch headers).
- if obj != nil {
- pkg.growSpan(obj, id.Pos(), id.End())
- }
- }
- for id, obj := range pkg.uses {
- pkg.growSpan(obj, id.Pos(), id.End())
- }
- for node, obj := range pkg.implicits {
- // A type switch with a short variable declaration
- // such as t := x.(type) doesn't declare the symbolic
- // variable (t in the example) at the switch header;
- // instead a new variable t (with specific type) is
- // declared implicitly for each case. Such variables
- // are found in the types.Info.Implicits (not Defs)
- // map. Add them here, assuming they are declared at
- // the type cases' colon ":".
- if cc, ok := node.(*ast.CaseClause); ok {
- pkg.growSpan(obj, cc.Colon, cc.Colon)
- }
- }
- return allErrors
-}
-
-// matchArgType reports an error if printf verb t is not appropriate
-// for operand arg.
-//
-// typ is used only for recursive calls; external callers must supply nil.
-//
-// (Recursion arises from the compound types {map,chan,slice} which
-// may be printed with %d etc. if that is appropriate for their element
-// types.)
-func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool {
- return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool))
-}
-
-// matchArgTypeInternal is the internal version of matchArgType. It carries a map
-// remembering what types are in progress so we don't recur when faced with recursive
-// types or mutually recursive types.
-func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool {
- // %v, %T accept any argument type.
- if t == anyType {
- return true
- }
- if typ == nil {
- // external call
- typ = f.pkg.types[arg].Type
- if typ == nil {
- return true // probably a type check problem
- }
- }
- // If the type implements fmt.Formatter, we have nothing to check.
- if f.isFormatter(typ) {
- return true
- }
- // If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
- if t&argString != 0 && isConvertibleToString(typ) {
- return true
- }
-
- typ = typ.Underlying()
- if inProgress[typ] {
- // We're already looking at this type. The call that started it will take care of it.
- return true
- }
- inProgress[typ] = true
-
- switch typ := typ.(type) {
- case *types.Signature:
- return t&argPointer != 0
-
- case *types.Map:
- // Recur: map[int]int matches %d.
- return t&argPointer != 0 ||
- (f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress))
-
- case *types.Chan:
- return t&argPointer != 0
-
- case *types.Array:
- // Same as slice.
- if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
- return true // %s matches []byte
- }
- // Recur: []int matches %d.
- return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
-
- case *types.Slice:
- // Same as array.
- if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
- return true // %s matches []byte
- }
- // Recur: []int matches %d. But watch out for
- // type T []T
- // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below.
- return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
-
- case *types.Pointer:
- // Ugly, but dealing with an edge case: a known pointer to an invalid type,
- // probably something from a failed import.
- if typ.Elem().String() == "invalid type" {
- if *verbose {
- f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg))
- }
- return true // special case
- }
- // If it's actually a pointer with %p, it prints as one.
- if t == argPointer {
- return true
- }
- under := typ.Elem().Underlying()
- switch under.(type) {
- case *types.Struct: // see below
- case *types.Array: // see below
- case *types.Slice: // see below
- case *types.Map: // see below
- default:
- // Check whether the rest can print pointers.
- return t&argPointer != 0
- }
- // If it's a top-level pointer to a struct, array, slice, or
- // map, that's equivalent in our analysis to whether we can
- // print the type being pointed to. Pointers in nested levels
- // are not supported to minimize fmt running into loops.
- if len(inProgress) > 1 {
- return false
- }
- return f.matchArgTypeInternal(t, under, arg, inProgress)
-
- case *types.Struct:
- return f.matchStructArgType(t, typ, arg, inProgress)
-
- case *types.Interface:
- // There's little we can do.
- // Whether any particular verb is valid depends on the argument.
- // The user may have reasonable prior knowledge of the contents of the interface.
- return true
-
- case *types.Basic:
- switch typ.Kind() {
- case types.UntypedBool,
- types.Bool:
- return t&argBool != 0
-
- case types.UntypedInt,
- types.Int,
- types.Int8,
- types.Int16,
- types.Int32,
- types.Int64,
- types.Uint,
- types.Uint8,
- types.Uint16,
- types.Uint32,
- types.Uint64,
- types.Uintptr:
- return t&argInt != 0
-
- case types.UntypedFloat,
- types.Float32,
- types.Float64:
- return t&argFloat != 0
-
- case types.UntypedComplex,
- types.Complex64,
- types.Complex128:
- return t&argComplex != 0
-
- case types.UntypedString,
- types.String:
- return t&argString != 0
-
- case types.UnsafePointer:
- return t&(argPointer|argInt) != 0
-
- case types.UntypedRune:
- return t&(argInt|argRune) != 0
-
- case types.UntypedNil:
- return false
-
- case types.Invalid:
- if *verbose {
- f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg))
- }
- return true // Probably a type check problem.
- }
- panic("unreachable")
- }
-
- return false
-}
-
-func isConvertibleToString(typ types.Type) bool {
- if bt, ok := typ.(*types.Basic); ok && bt.Kind() == types.UntypedNil {
- // We explicitly don't want untyped nil, which is
- // convertible to both of the interfaces below, as it
- // would just panic anyway.
- return false
- }
- if types.ConvertibleTo(typ, errorType) {
- return true // via .Error()
- }
- if stringerType != nil && types.ConvertibleTo(typ, stringerType) {
- return true // via .String()
- }
- return false
-}
-
-// hasBasicType reports whether x's type is a types.Basic with the given kind.
-func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool {
- t := f.pkg.types[x].Type
- if t != nil {
- t = t.Underlying()
- }
- b, ok := t.(*types.Basic)
- return ok && b.Kind() == kind
-}
-
-// matchStructArgType reports whether all the elements of the struct match the expected
-// type. For instance, with "%d" all the elements must be printable with the "%d" format.
-func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool {
- for i := 0; i < typ.NumFields(); i++ {
- typf := typ.Field(i)
- if !f.matchArgTypeInternal(t, typf.Type(), arg, inProgress) {
- return false
- }
- if t&argString != 0 && !typf.Exported() && isConvertibleToString(typf.Type()) {
- // Issue #17798: unexported Stringer or error cannot be properly fomatted.
- return false
- }
- }
- return true
-}
-
-var archSizes = types.SizesFor("gc", build.Default.GOARCH)
+++ /dev/null
-// Copyright 2018 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.
-
-// This file defines the check for passing non-pointer or non-interface
-// types to unmarshal and decode functions.
-
-package main
-
-import (
- "go/ast"
- "go/types"
- "strings"
-)
-
-func init() {
- register("unmarshal",
- "check for passing non-pointer or non-interface types to unmarshal and decode functions",
- checkUnmarshalArg,
- callExpr)
-}
-
-var pointerArgFuncs = map[string]int{
- "encoding/json.Unmarshal": 1,
- "(*encoding/json.Decoder).Decode": 0,
- "(*encoding/gob.Decoder).Decode": 0,
- "encoding/xml.Unmarshal": 1,
- "(*encoding/xml.Decoder).Decode": 0,
-}
-
-func checkUnmarshalArg(f *File, n ast.Node) {
- call, ok := n.(*ast.CallExpr)
- if !ok {
- return // not a call statement
- }
- fun := unparen(call.Fun)
-
- if f.pkg.types[fun].IsType() {
- return // a conversion, not a call
- }
-
- info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors}
- name := callName(info, call)
-
- arg, ok := pointerArgFuncs[name]
- if !ok {
- return // not a function we are interested in
- }
-
- if len(call.Args) < arg+1 {
- return // not enough arguments, e.g. called with return values of another function
- }
-
- typ := f.pkg.types[call.Args[arg]]
-
- if typ.Type == nil {
- return // type error prevents further analysis
- }
-
- switch typ.Type.Underlying().(type) {
- case *types.Pointer, *types.Interface:
- return
- }
-
- shortname := name[strings.LastIndexByte(name, '.')+1:]
- switch arg {
- case 0:
- f.Badf(call.Lparen, "call of %s passes non-pointer", shortname)
- case 1:
- f.Badf(call.Lparen, "call of %s passes non-pointer as second argument", shortname)
- }
-}
+++ /dev/null
-// Copyright 2014 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.
-
-// Check for invalid uintptr -> unsafe.Pointer conversions.
-
-package main
-
-import (
- "go/ast"
- "go/token"
- "go/types"
-)
-
-func init() {
- register("unsafeptr",
- "check for misuse of unsafe.Pointer",
- checkUnsafePointer,
- callExpr)
-}
-
-func checkUnsafePointer(f *File, node ast.Node) {
- x := node.(*ast.CallExpr)
- if len(x.Args) != 1 {
- return
- }
- if f.hasBasicType(x.Fun, types.UnsafePointer) && f.hasBasicType(x.Args[0], types.Uintptr) && !f.isSafeUintptr(x.Args[0]) {
- f.Badf(x.Pos(), "possible misuse of unsafe.Pointer")
- }
-}
-
-// isSafeUintptr reports whether x - already known to be a uintptr -
-// is safe to convert to unsafe.Pointer. It is safe if x is itself derived
-// directly from an unsafe.Pointer via conversion and pointer arithmetic
-// or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr
-// or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader.
-func (f *File) isSafeUintptr(x ast.Expr) bool {
- switch x := x.(type) {
- case *ast.ParenExpr:
- return f.isSafeUintptr(x.X)
-
- case *ast.SelectorExpr:
- switch x.Sel.Name {
- case "Data":
- // reflect.SliceHeader and reflect.StringHeader are okay,
- // but only if they are pointing at a real slice or string.
- // It's not okay to do:
- // var x SliceHeader
- // x.Data = uintptr(unsafe.Pointer(...))
- // ... use x ...
- // p := unsafe.Pointer(x.Data)
- // because in the middle the garbage collector doesn't
- // see x.Data as a pointer and so x.Data may be dangling
- // by the time we get to the conversion at the end.
- // For now approximate by saying that *Header is okay
- // but Header is not.
- pt, ok := f.pkg.types[x.X].Type.(*types.Pointer)
- if ok {
- t, ok := pt.Elem().(*types.Named)
- if ok && t.Obj().Pkg().Path() == "reflect" {
- switch t.Obj().Name() {
- case "StringHeader", "SliceHeader":
- return true
- }
- }
- }
- }
-
- case *ast.CallExpr:
- switch len(x.Args) {
- case 0:
- // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr.
- sel, ok := x.Fun.(*ast.SelectorExpr)
- if !ok {
- break
- }
- switch sel.Sel.Name {
- case "Pointer", "UnsafeAddr":
- t, ok := f.pkg.types[sel.X].Type.(*types.Named)
- if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
- return true
- }
- }
-
- case 1:
- // maybe conversion of uintptr to unsafe.Pointer
- return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer)
- }
-
- case *ast.BinaryExpr:
- switch x.Op {
- case token.ADD, token.SUB, token.AND_NOT:
- return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y)
- }
- }
- return false
-}
+++ /dev/null
-// 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.
-
-// This file defines the check for unused results of calls to certain
-// pure functions.
-
-package main
-
-import (
- "flag"
- "go/ast"
- "go/token"
- "go/types"
- "strings"
-)
-
-var unusedFuncsFlag = flag.String("unusedfuncs",
- "errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse",
- "comma-separated list of functions whose results must be used")
-
-var unusedStringMethodsFlag = flag.String("unusedstringmethods",
- "Error,String",
- "comma-separated list of names of methods of type func() string whose results must be used")
-
-func init() {
- register("unusedresult",
- "check for unused result of calls to functions in -unusedfuncs list and methods in -unusedstringmethods list",
- checkUnusedResult,
- exprStmt)
-}
-
-// func() string
-var sigNoArgsStringResult = types.NewSignature(nil, nil,
- types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])),
- false)
-
-var unusedFuncs = make(map[string]bool)
-var unusedStringMethods = make(map[string]bool)
-
-func initUnusedFlags() {
- commaSplit := func(s string, m map[string]bool) {
- if s != "" {
- for _, name := range strings.Split(s, ",") {
- if len(name) == 0 {
- flag.Usage()
- }
- m[name] = true
- }
- }
- }
- commaSplit(*unusedFuncsFlag, unusedFuncs)
- commaSplit(*unusedStringMethodsFlag, unusedStringMethods)
-}
-
-func checkUnusedResult(f *File, n ast.Node) {
- call, ok := unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
- if !ok {
- return // not a call statement
- }
- fun := unparen(call.Fun)
-
- if f.pkg.types[fun].IsType() {
- return // a conversion, not a call
- }
-
- selector, ok := fun.(*ast.SelectorExpr)
- if !ok {
- return // neither a method call nor a qualified ident
- }
-
- sel, ok := f.pkg.selectors[selector]
- if ok && sel.Kind() == types.MethodVal {
- // method (e.g. foo.String())
- obj := sel.Obj().(*types.Func)
- sig := sel.Type().(*types.Signature)
- if types.Identical(sig, sigNoArgsStringResult) {
- if unusedStringMethods[obj.Name()] {
- f.Badf(call.Lparen, "result of (%s).%s call not used",
- sig.Recv().Type(), obj.Name())
- }
- }
- } else if !ok {
- // package-qualified function (e.g. fmt.Errorf)
- obj := f.pkg.uses[selector.Sel]
- if obj, ok := obj.(*types.Func); ok {
- qname := obj.Pkg().Path() + "." + obj.Name()
- if unusedFuncs[qname] {
- f.Badf(call.Lparen, "result of %v call not used", qname)
- }
- }
- }
-}
"os/exec"
"path/filepath"
"regexp"
- "runtime"
"strconv"
"strings"
"sync"
built = true
}
-func Vet(t *testing.T, files []string) {
- flags := []string{
- "-printfuncs=Warn:1,Warnf:1",
- "-all",
- "-shadow",
+func vetCmd(t *testing.T, args ...string) *exec.Cmd {
+ cmd := exec.Command(testenv.GoToolPath(t), "vet", "-vettool="+binary)
+ cmd.Args = append(cmd.Args, args...)
+ testdata, err := filepath.Abs("testdata")
+ if err != nil {
+ t.Fatal(err)
}
- cmd := exec.Command(binary, append(flags, files...)...)
- errchk(cmd, files, t)
+ cmd.Env = append(os.Environ(), "GOPATH="+testdata)
+ return cmd
}
// 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
+// errorCheck the output of ./testvet -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",
+ for _, pkg := range []string{
+ "asm",
+ "assign",
+ "atomic",
+ "bool",
"buildtag",
- "incomplete", // incomplete examples
"cgo",
+ "composite",
+ "copylock",
+ "deadcode",
+ "httpresponse",
+ "lostcancel",
+ "method",
+ "nilfunc",
+ "print",
+ "rangeloop",
+ "shift",
+ "structtag",
+ "testingpkg",
+ // "testtag" has its own test
+ "unmarshal",
+ "unsafeptr",
+ "unused",
} {
- dir := dir
- t.Run(dir, func(t *testing.T) {
+ pkg := pkg
+ t.Run(pkg, func(t *testing.T) {
t.Parallel()
- gos, err := filepath.Glob(filepath.Join("testdata", dir, "*.go"))
+
+ cmd := vetCmd(t, "-printfuncs=Warn,Warnf", pkg)
+
+ dir := filepath.Join("testdata/src", pkg)
+ gos, err := filepath.Glob(filepath.Join(dir, "*.go"))
if err != nil {
t.Fatal(err)
}
- Vet(t, gos)
+ asms, err := filepath.Glob(filepath.Join(dir, "*.s"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ var files []string
+ files = append(files, gos...)
+ files = append(files, asms...)
+
+ errchk(cmd, files, t)
})
}
}
func TestTags(t *testing.T) {
t.Parallel()
Build(t)
- for _, tag := range []string{"testtag", "x testtag y", "x,testtag,y"} {
- tag := tag
+ for tag, wantFile := range map[string]int{
+ "testtag": 1, // file1
+ "x testtag y": 1,
+ "othertag": 2,
+ } {
+ tag, wantFile := tag, wantFile
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...)
+ cmd := vetCmd(t, "-tags="+tag, "tagtest")
output, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatal(err)
- }
+
+ want := fmt.Sprintf("file%d.go", wantFile)
+ dontwant := fmt.Sprintf("file%d.go", 3-wantFile)
+
// 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", want))) {
+ t.Errorf("%s: %s was excluded, should be included", tag, want)
}
- if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
- t.Error("file2 was included, should be excluded")
+ if bytes.Contains(output, []byte(filepath.Join("tagtest", dontwant))) {
+ t.Errorf("%s: %s was included, should be excluded", tag, dontwant)
+ }
+ if t.Failed() {
+ t.Logf("err=%s, output=<<%s>>", err, output)
}
})
}
}
-// 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.