update dependencies

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-12-22 16:48:26 +08:00
parent 4a11a50544
commit fe6c5de00f
2857 changed files with 252134 additions and 115656 deletions

28
vendor/honnef.co/go/tools/lint/LICENSE vendored Normal file
View File

@@ -0,0 +1,28 @@
Copyright (c) 2013 The Go Authors. All rights reserved.
Copyright (c) 2016 Dominik Honnef. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

539
vendor/honnef.co/go/tools/lint/lint.go vendored Normal file
View File

@@ -0,0 +1,539 @@
// Package lint provides the foundation for tools like staticcheck
package lint // import "honnef.co/go/tools/lint"
import (
"bytes"
"encoding/gob"
"fmt"
"go/scanner"
"go/token"
"go/types"
"path/filepath"
"sort"
"strings"
"sync"
"sync/atomic"
"unicode"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/packages"
"honnef.co/go/tools/config"
"honnef.co/go/tools/internal/cache"
)
type Documentation struct {
Title string
Text string
Since string
NonDefault bool
Options []string
}
func (doc *Documentation) String() string {
b := &strings.Builder{}
fmt.Fprintf(b, "%s\n\n", doc.Title)
if doc.Text != "" {
fmt.Fprintf(b, "%s\n\n", doc.Text)
}
fmt.Fprint(b, "Available since\n ")
if doc.Since == "" {
fmt.Fprint(b, "unreleased")
} else {
fmt.Fprintf(b, "%s", doc.Since)
}
if doc.NonDefault {
fmt.Fprint(b, ", non-default")
}
fmt.Fprint(b, "\n")
if len(doc.Options) > 0 {
fmt.Fprintf(b, "\nOptions\n")
for _, opt := range doc.Options {
fmt.Fprintf(b, " %s", opt)
}
fmt.Fprint(b, "\n")
}
return b.String()
}
type Ignore interface {
Match(p Problem) bool
}
type LineIgnore struct {
File string
Line int
Checks []string
Matched bool
Pos token.Position
}
func (li *LineIgnore) Match(p Problem) bool {
pos := p.Pos
if pos.Filename != li.File || pos.Line != li.Line {
return false
}
for _, c := range li.Checks {
if m, _ := filepath.Match(c, p.Check); m {
li.Matched = true
return true
}
}
return false
}
func (li *LineIgnore) String() string {
matched := "not matched"
if li.Matched {
matched = "matched"
}
return fmt.Sprintf("%s:%d %s (%s)", li.File, li.Line, strings.Join(li.Checks, ", "), matched)
}
type FileIgnore struct {
File string
Checks []string
}
func (fi *FileIgnore) Match(p Problem) bool {
if p.Pos.Filename != fi.File {
return false
}
for _, c := range fi.Checks {
if m, _ := filepath.Match(c, p.Check); m {
return true
}
}
return false
}
type Severity uint8
const (
Error Severity = iota
Warning
Ignored
)
// Problem represents a problem in some source code.
type Problem struct {
Pos token.Position
End token.Position
Message string
Check string
Severity Severity
Related []Related
}
type Related struct {
Pos token.Position
End token.Position
Message string
}
func (p Problem) Equal(o Problem) bool {
return p.Pos == o.Pos &&
p.End == o.End &&
p.Message == o.Message &&
p.Check == o.Check &&
p.Severity == o.Severity
}
func (p *Problem) String() string {
return fmt.Sprintf("%s (%s)", p.Message, p.Check)
}
// A Linter lints Go source code.
type Linter struct {
Checkers []*analysis.Analyzer
CumulativeCheckers []CumulativeChecker
GoVersion int
Config config.Config
Stats Stats
RepeatAnalyzers uint
}
type CumulativeChecker interface {
Analyzer() *analysis.Analyzer
Result() []types.Object
ProblemObject(*token.FileSet, types.Object) Problem
}
func (l *Linter) Lint(cfg *packages.Config, patterns []string) ([]Problem, error) {
var allAnalyzers []*analysis.Analyzer
allAnalyzers = append(allAnalyzers, l.Checkers...)
for _, cum := range l.CumulativeCheckers {
allAnalyzers = append(allAnalyzers, cum.Analyzer())
}
// The -checks command line flag overrules all configuration
// files, which means that for `-checks="foo"`, no check other
// than foo can ever be reported to the user. Make use of this
// fact to cull the list of analyses we need to run.
// replace "inherit" with "all", as we don't want to base the
// list of all checks on the default configuration, which
// disables certain checks.
checks := make([]string, len(l.Config.Checks))
copy(checks, l.Config.Checks)
for i, c := range checks {
if c == "inherit" {
checks[i] = "all"
}
}
allowed := FilterChecks(allAnalyzers, checks)
var allowedAnalyzers []*analysis.Analyzer
for _, c := range l.Checkers {
if allowed[c.Name] {
allowedAnalyzers = append(allowedAnalyzers, c)
}
}
hasCumulative := false
for _, cum := range l.CumulativeCheckers {
a := cum.Analyzer()
if allowed[a.Name] {
hasCumulative = true
allowedAnalyzers = append(allowedAnalyzers, a)
}
}
r, err := NewRunner(&l.Stats)
if err != nil {
return nil, err
}
r.goVersion = l.GoVersion
r.repeatAnalyzers = l.RepeatAnalyzers
pkgs, err := r.Run(cfg, patterns, allowedAnalyzers, hasCumulative)
if err != nil {
return nil, err
}
tpkgToPkg := map[*types.Package]*Package{}
for _, pkg := range pkgs {
tpkgToPkg[pkg.Types] = pkg
for _, e := range pkg.errs {
switch e := e.(type) {
case types.Error:
p := Problem{
Pos: e.Fset.PositionFor(e.Pos, false),
Message: e.Msg,
Severity: Error,
Check: "compile",
}
pkg.problems = append(pkg.problems, p)
case packages.Error:
msg := e.Msg
if len(msg) != 0 && msg[0] == '\n' {
// TODO(dh): See https://github.com/golang/go/issues/32363
msg = msg[1:]
}
var pos token.Position
if e.Pos == "" {
// Under certain conditions (malformed package
// declarations, multiple packages in the same
// directory), go list emits an error on stderr
// instead of JSON. Those errors do not have
// associated position information in
// go/packages.Error, even though the output on
// stderr may contain it.
if p, n, err := parsePos(msg); err == nil {
if abs, err := filepath.Abs(p.Filename); err == nil {
p.Filename = abs
}
pos = p
msg = msg[n+2:]
}
} else {
var err error
pos, _, err = parsePos(e.Pos)
if err != nil {
panic(fmt.Sprintf("internal error: %s", e))
}
}
p := Problem{
Pos: pos,
Message: msg,
Severity: Error,
Check: "compile",
}
pkg.problems = append(pkg.problems, p)
case scanner.ErrorList:
for _, e := range e {
p := Problem{
Pos: e.Pos,
Message: e.Msg,
Severity: Error,
Check: "compile",
}
pkg.problems = append(pkg.problems, p)
}
case error:
p := Problem{
Pos: token.Position{},
Message: e.Error(),
Severity: Error,
Check: "compile",
}
pkg.problems = append(pkg.problems, p)
}
}
}
atomic.StoreUint32(&r.stats.State, StateCumulative)
for _, cum := range l.CumulativeCheckers {
for _, res := range cum.Result() {
pkg := tpkgToPkg[res.Pkg()]
if pkg == nil {
panic(fmt.Sprintf("analyzer %s flagged object %s in package %s, a package that we aren't tracking", cum.Analyzer(), res, res.Pkg()))
}
allowedChecks := FilterChecks(allowedAnalyzers, pkg.cfg.Merge(l.Config).Checks)
if allowedChecks[cum.Analyzer().Name] {
pos := DisplayPosition(pkg.Fset, res.Pos())
// FIXME(dh): why are we ignoring generated files
// here? Surely this is specific to 'unused', not all
// cumulative checkers
if _, ok := pkg.gen[pos.Filename]; ok {
continue
}
p := cum.ProblemObject(pkg.Fset, res)
pkg.problems = append(pkg.problems, p)
}
}
}
for _, pkg := range pkgs {
if !pkg.fromSource {
// Don't cache packages that we loaded from the cache
continue
}
cpkg := cachedPackage{
Problems: pkg.problems,
Ignores: pkg.ignores,
Config: pkg.cfg,
}
buf := &bytes.Buffer{}
if err := gob.NewEncoder(buf).Encode(cpkg); err != nil {
return nil, err
}
id := cache.Subkey(pkg.actionID, "data "+r.problemsCacheKey)
if err := r.cache.PutBytes(id, buf.Bytes()); err != nil {
return nil, err
}
}
var problems []Problem
// Deduplicate line ignores. When U1000 processes a package and
// its test variant, it will only emit a single problem for an
// unused object, not two problems. We will, however, have two
// line ignores, one per package. Without deduplication, one line
// ignore will be marked as matched, while the other one won't,
// subsequently reporting a "this linter directive didn't match
// anything" error.
ignores := map[token.Position]Ignore{}
for _, pkg := range pkgs {
for _, ig := range pkg.ignores {
if lig, ok := ig.(*LineIgnore); ok {
ig = ignores[lig.Pos]
if ig == nil {
ignores[lig.Pos] = lig
ig = lig
}
}
for i := range pkg.problems {
p := &pkg.problems[i]
if ig.Match(*p) {
p.Severity = Ignored
}
}
}
if pkg.cfg == nil {
// The package failed to load, otherwise we would have a
// valid config. Pass through all errors.
problems = append(problems, pkg.problems...)
} else {
for _, p := range pkg.problems {
allowedChecks := FilterChecks(allowedAnalyzers, pkg.cfg.Merge(l.Config).Checks)
allowedChecks["compile"] = true
if allowedChecks[p.Check] {
problems = append(problems, p)
}
}
}
for _, ig := range pkg.ignores {
ig, ok := ig.(*LineIgnore)
if !ok {
continue
}
ig = ignores[ig.Pos].(*LineIgnore)
if ig.Matched {
continue
}
couldveMatched := false
allowedChecks := FilterChecks(allowedAnalyzers, pkg.cfg.Merge(l.Config).Checks)
for _, c := range ig.Checks {
if !allowedChecks[c] {
continue
}
couldveMatched = true
break
}
if !couldveMatched {
// The ignored checks were disabled for the containing package.
// Don't flag the ignore for not having matched.
continue
}
p := Problem{
Pos: ig.Pos,
Message: "this linter directive didn't match anything; should it be removed?",
Check: "",
}
problems = append(problems, p)
}
}
if len(problems) == 0 {
return nil, nil
}
sort.Slice(problems, func(i, j int) bool {
pi := problems[i].Pos
pj := problems[j].Pos
if pi.Filename != pj.Filename {
return pi.Filename < pj.Filename
}
if pi.Line != pj.Line {
return pi.Line < pj.Line
}
if pi.Column != pj.Column {
return pi.Column < pj.Column
}
return problems[i].Message < problems[j].Message
})
var out []Problem
out = append(out, problems[0])
for i, p := range problems[1:] {
// We may encounter duplicate problems because one file
// can be part of many packages.
if !problems[i].Equal(p) {
out = append(out, p)
}
}
return out, nil
}
func FilterChecks(allChecks []*analysis.Analyzer, checks []string) map[string]bool {
// OPT(dh): this entire computation could be cached per package
allowedChecks := map[string]bool{}
for _, check := range checks {
b := true
if len(check) > 1 && check[0] == '-' {
b = false
check = check[1:]
}
if check == "*" || check == "all" {
// Match all
for _, c := range allChecks {
allowedChecks[c.Name] = b
}
} else if strings.HasSuffix(check, "*") {
// Glob
prefix := check[:len(check)-1]
isCat := strings.IndexFunc(prefix, func(r rune) bool { return unicode.IsNumber(r) }) == -1
for _, c := range allChecks {
idx := strings.IndexFunc(c.Name, func(r rune) bool { return unicode.IsNumber(r) })
if isCat {
// Glob is S*, which should match S1000 but not SA1000
cat := c.Name[:idx]
if prefix == cat {
allowedChecks[c.Name] = b
}
} else {
// Glob is S1*
if strings.HasPrefix(c.Name, prefix) {
allowedChecks[c.Name] = b
}
}
}
} else {
// Literal check name
allowedChecks[check] = b
}
}
return allowedChecks
}
func DisplayPosition(fset *token.FileSet, p token.Pos) token.Position {
if p == token.NoPos {
return token.Position{}
}
// Only use the adjusted position if it points to another Go file.
// This means we'll point to the original file for cgo files, but
// we won't point to a YACC grammar file.
pos := fset.PositionFor(p, false)
adjPos := fset.PositionFor(p, true)
if filepath.Ext(adjPos.Filename) == ".go" {
return adjPos
}
return pos
}
var bufferPool = &sync.Pool{
New: func() interface{} {
buf := bytes.NewBuffer(nil)
buf.Grow(64)
return buf
},
}
func FuncName(f *types.Func) string {
buf := bufferPool.Get().(*bytes.Buffer)
buf.Reset()
if f.Type() != nil {
sig := f.Type().(*types.Signature)
if recv := sig.Recv(); recv != nil {
buf.WriteByte('(')
if _, ok := recv.Type().(*types.Interface); ok {
// gcimporter creates abstract methods of
// named interfaces using the interface type
// (not the named type) as the receiver.
// Don't print it in full.
buf.WriteString("interface")
} else {
types.WriteType(buf, recv.Type(), nil)
}
buf.WriteByte(')')
buf.WriteByte('.')
} else if f.Pkg() != nil {
writePackage(buf, f.Pkg())
}
}
buf.WriteString(f.Name())
s := buf.String()
bufferPool.Put(buf)
return s
}
func writePackage(buf *bytes.Buffer, pkg *types.Package) {
if pkg == nil {
return
}
s := pkg.Path()
if s != "" {
buf.WriteString(s)
buf.WriteByte('.')
}
}

View File

@@ -0,0 +1,58 @@
// Package lintdsl provides helpers for implementing static analysis
// checks. Dot-importing this package is encouraged.
package lintdsl
import (
"bytes"
"fmt"
"go/ast"
"go/format"
"golang.org/x/tools/go/analysis"
"honnef.co/go/tools/pattern"
)
func Inspect(node ast.Node, fn func(node ast.Node) bool) {
if node == nil {
return
}
ast.Inspect(node, fn)
}
func Match(pass *analysis.Pass, q pattern.Pattern, node ast.Node) (*pattern.Matcher, bool) {
// Note that we ignore q.Relevant callers of Match usually use
// AST inspectors that already filter on nodes we're interested
// in.
m := &pattern.Matcher{TypesInfo: pass.TypesInfo}
ok := m.Match(q.Root, node)
return m, ok
}
func MatchAndEdit(pass *analysis.Pass, before, after pattern.Pattern, node ast.Node) (*pattern.Matcher, []analysis.TextEdit, bool) {
m, ok := Match(pass, before, node)
if !ok {
return m, nil, false
}
r := pattern.NodeToAST(after.Root, m.State)
buf := &bytes.Buffer{}
format.Node(buf, pass.Fset, r)
edit := []analysis.TextEdit{{
Pos: node.Pos(),
End: node.End(),
NewText: buf.Bytes(),
}}
return m, edit, true
}
func Selector(x, sel string) *ast.SelectorExpr {
return &ast.SelectorExpr{
X: &ast.Ident{Name: x},
Sel: &ast.Ident{Name: sel},
}
}
// ExhaustiveTypeSwitch panics when called. It can be used to ensure
// that type switches are exhaustive.
func ExhaustiveTypeSwitch(v interface{}) {
panic(fmt.Sprintf("internal error: unhandled case %T", v))
}

View File

@@ -0,0 +1,162 @@
// Package format provides formatters for linter problems.
package format
import (
"encoding/json"
"fmt"
"go/token"
"io"
"os"
"path/filepath"
"text/tabwriter"
"honnef.co/go/tools/lint"
)
func shortPath(path string) string {
cwd, err := os.Getwd()
if err != nil {
return path
}
if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
return rel
}
return path
}
func relativePositionString(pos token.Position) string {
s := shortPath(pos.Filename)
if pos.IsValid() {
if s != "" {
s += ":"
}
s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
}
if s == "" {
s = "-"
}
return s
}
type Statter interface {
Stats(total, errors, warnings, ignored int)
}
type Formatter interface {
Format(p lint.Problem)
}
type Text struct {
W io.Writer
}
func (o Text) Format(p lint.Problem) {
fmt.Fprintf(o.W, "%s: %s\n", relativePositionString(p.Pos), p.String())
for _, r := range p.Related {
fmt.Fprintf(o.W, "\t%s: %s\n", relativePositionString(r.Pos), r.Message)
}
}
type JSON struct {
W io.Writer
}
func severity(s lint.Severity) string {
switch s {
case lint.Error:
return "error"
case lint.Warning:
return "warning"
case lint.Ignored:
return "ignored"
}
return ""
}
func (o JSON) Format(p lint.Problem) {
type location struct {
File string `json:"file"`
Line int `json:"line"`
Column int `json:"column"`
}
type related struct {
Location location `json:"location"`
End location `json:"end"`
Message string `json:"message"`
}
jp := struct {
Code string `json:"code"`
Severity string `json:"severity,omitempty"`
Location location `json:"location"`
End location `json:"end"`
Message string `json:"message"`
Related []related `json:"related,omitempty"`
}{
Code: p.Check,
Severity: severity(p.Severity),
Location: location{
File: p.Pos.Filename,
Line: p.Pos.Line,
Column: p.Pos.Column,
},
End: location{
File: p.End.Filename,
Line: p.End.Line,
Column: p.End.Column,
},
Message: p.Message,
}
for _, r := range p.Related {
jp.Related = append(jp.Related, related{
Location: location{
File: r.Pos.Filename,
Line: r.Pos.Line,
Column: r.Pos.Column,
},
End: location{
File: r.End.Filename,
Line: r.End.Line,
Column: r.End.Column,
},
Message: r.Message,
})
}
_ = json.NewEncoder(o.W).Encode(jp)
}
type Stylish struct {
W io.Writer
prevFile string
tw *tabwriter.Writer
}
func (o *Stylish) Format(p lint.Problem) {
pos := p.Pos
if pos.Filename == "" {
pos.Filename = "-"
}
if pos.Filename != o.prevFile {
if o.prevFile != "" {
o.tw.Flush()
fmt.Fprintln(o.W)
}
fmt.Fprintln(o.W, pos.Filename)
o.prevFile = pos.Filename
o.tw = tabwriter.NewWriter(o.W, 0, 4, 2, ' ', 0)
}
fmt.Fprintf(o.tw, " (%d, %d)\t%s\t%s\n", pos.Line, pos.Column, p.Check, p.Message)
for _, r := range p.Related {
fmt.Fprintf(o.tw, " (%d, %d)\t\t %s\n", r.Pos.Line, r.Pos.Column, r.Message)
}
}
func (o *Stylish) Stats(total, errors, warnings, ignored int) {
if o.tw != nil {
o.tw.Flush()
fmt.Fprintln(o.W)
}
fmt.Fprintf(o.W, " ✖ %d problems (%d errors, %d warnings, %d ignored)\n",
total, errors, warnings, ignored)
}

View File

@@ -0,0 +1,7 @@
// +build !aix,!android,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
package lintutil
import "os"
var infoSignals = []os.Signal{}

View File

@@ -0,0 +1,10 @@
// +build darwin dragonfly freebsd netbsd openbsd
package lintutil
import (
"os"
"syscall"
)
var infoSignals = []os.Signal{syscall.SIGINFO}

View File

@@ -0,0 +1,10 @@
// +build aix android linux solaris
package lintutil
import (
"os"
"syscall"
)
var infoSignals = []os.Signal{syscall.SIGUSR1}

View File

@@ -0,0 +1,444 @@
// Copyright (c) 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 or at
// https://developers.google.com/open-source/licenses/bsd.
// Package lintutil provides helpers for writing linter command lines.
package lintutil // import "honnef.co/go/tools/lint/lintutil"
import (
"crypto/sha256"
"errors"
"flag"
"fmt"
"go/build"
"go/token"
"io"
"log"
"os"
"os/signal"
"regexp"
"runtime"
"runtime/pprof"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"honnef.co/go/tools/config"
"honnef.co/go/tools/internal/cache"
"honnef.co/go/tools/lint"
"honnef.co/go/tools/lint/lintutil/format"
"honnef.co/go/tools/version"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/buildutil"
"golang.org/x/tools/go/packages"
)
func NewVersionFlag() flag.Getter {
tags := build.Default.ReleaseTags
v := tags[len(tags)-1][2:]
version := new(VersionFlag)
if err := version.Set(v); err != nil {
panic(fmt.Sprintf("internal error: %s", err))
}
return version
}
type VersionFlag int
func (v *VersionFlag) String() string {
return fmt.Sprintf("1.%d", *v)
}
func (v *VersionFlag) Set(s string) error {
if len(s) < 3 {
return errors.New("invalid Go version")
}
if s[0] != '1' {
return errors.New("invalid Go version")
}
if s[1] != '.' {
return errors.New("invalid Go version")
}
i, err := strconv.Atoi(s[2:])
*v = VersionFlag(i)
return err
}
func (v *VersionFlag) Get() interface{} {
return int(*v)
}
func usage(name string, flags *flag.FlagSet) func() {
return func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", name)
fmt.Fprintf(os.Stderr, "\t%s [flags] # runs on package in current directory\n", name)
fmt.Fprintf(os.Stderr, "\t%s [flags] packages\n", name)
fmt.Fprintf(os.Stderr, "\t%s [flags] directory\n", name)
fmt.Fprintf(os.Stderr, "\t%s [flags] files... # must be a single package\n", name)
fmt.Fprintf(os.Stderr, "Flags:\n")
flags.PrintDefaults()
}
}
type list []string
func (list *list) String() string {
return `"` + strings.Join(*list, ",") + `"`
}
func (list *list) Set(s string) error {
if s == "" {
*list = nil
return nil
}
*list = strings.Split(s, ",")
return nil
}
func FlagSet(name string) *flag.FlagSet {
flags := flag.NewFlagSet("", flag.ExitOnError)
flags.Usage = usage(name, flags)
flags.String("tags", "", "List of `build tags`")
flags.Bool("tests", true, "Include tests")
flags.Bool("version", false, "Print version and exit")
flags.Bool("show-ignored", false, "Don't filter ignored problems")
flags.String("f", "text", "Output `format` (valid choices are 'stylish', 'text' and 'json')")
flags.String("explain", "", "Print description of `check`")
flags.String("debug.cpuprofile", "", "Write CPU profile to `file`")
flags.String("debug.memprofile", "", "Write memory profile to `file`")
flags.Bool("debug.version", false, "Print detailed version information about this program")
flags.Bool("debug.no-compile-errors", false, "Don't print compile errors")
flags.String("debug.measure-analyzers", "", "Write analysis measurements to `file`. `file` will be opened for appending if it already exists.")
flags.Uint("debug.repeat-analyzers", 0, "Run analyzers `num` times")
checks := list{"inherit"}
fail := list{"all"}
flags.Var(&checks, "checks", "Comma-separated list of `checks` to enable.")
flags.Var(&fail, "fail", "Comma-separated list of `checks` that can cause a non-zero exit status.")
tags := build.Default.ReleaseTags
v := tags[len(tags)-1][2:]
version := new(VersionFlag)
if err := version.Set(v); err != nil {
panic(fmt.Sprintf("internal error: %s", err))
}
flags.Var(version, "go", "Target Go `version` in the format '1.x'")
return flags
}
func findCheck(cs []*analysis.Analyzer, check string) (*analysis.Analyzer, bool) {
for _, c := range cs {
if c.Name == check {
return c, true
}
}
return nil, false
}
func ProcessFlagSet(cs []*analysis.Analyzer, cums []lint.CumulativeChecker, fs *flag.FlagSet) {
tags := fs.Lookup("tags").Value.(flag.Getter).Get().(string)
tests := fs.Lookup("tests").Value.(flag.Getter).Get().(bool)
goVersion := fs.Lookup("go").Value.(flag.Getter).Get().(int)
formatter := fs.Lookup("f").Value.(flag.Getter).Get().(string)
printVersion := fs.Lookup("version").Value.(flag.Getter).Get().(bool)
showIgnored := fs.Lookup("show-ignored").Value.(flag.Getter).Get().(bool)
explain := fs.Lookup("explain").Value.(flag.Getter).Get().(string)
cpuProfile := fs.Lookup("debug.cpuprofile").Value.(flag.Getter).Get().(string)
memProfile := fs.Lookup("debug.memprofile").Value.(flag.Getter).Get().(string)
debugVersion := fs.Lookup("debug.version").Value.(flag.Getter).Get().(bool)
debugNoCompile := fs.Lookup("debug.no-compile-errors").Value.(flag.Getter).Get().(bool)
debugRepeat := fs.Lookup("debug.repeat-analyzers").Value.(flag.Getter).Get().(uint)
var measureAnalyzers func(analysis *analysis.Analyzer, pkg *lint.Package, d time.Duration)
if path := fs.Lookup("debug.measure-analyzers").Value.(flag.Getter).Get().(string); path != "" {
f, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
log.Fatal(err)
}
mu := &sync.Mutex{}
measureAnalyzers = func(analysis *analysis.Analyzer, pkg *lint.Package, d time.Duration) {
mu.Lock()
defer mu.Unlock()
if _, err := fmt.Fprintf(f, "%s\t%s\t%d\n", analysis.Name, pkg.ID, d.Nanoseconds()); err != nil {
log.Println("error writing analysis measurements:", err)
}
}
}
cfg := config.Config{}
cfg.Checks = *fs.Lookup("checks").Value.(*list)
exit := func(code int) {
if cpuProfile != "" {
pprof.StopCPUProfile()
}
if memProfile != "" {
f, err := os.Create(memProfile)
if err != nil {
panic(err)
}
runtime.GC()
pprof.WriteHeapProfile(f)
}
os.Exit(code)
}
if cpuProfile != "" {
f, err := os.Create(cpuProfile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
}
if debugVersion {
version.Verbose()
exit(0)
}
if printVersion {
version.Print()
exit(0)
}
// Validate that the tags argument is well-formed. go/packages
// doesn't detect malformed build flags and returns unhelpful
// errors.
tf := buildutil.TagsFlag{}
if err := tf.Set(tags); err != nil {
fmt.Fprintln(os.Stderr, fmt.Errorf("invalid value %q for flag -tags: %s", tags, err))
exit(1)
}
if explain != "" {
var haystack []*analysis.Analyzer
haystack = append(haystack, cs...)
for _, cum := range cums {
haystack = append(haystack, cum.Analyzer())
}
check, ok := findCheck(haystack, explain)
if !ok {
fmt.Fprintln(os.Stderr, "Couldn't find check", explain)
exit(1)
}
if check.Doc == "" {
fmt.Fprintln(os.Stderr, explain, "has no documentation")
exit(1)
}
fmt.Println(check.Doc)
exit(0)
}
ps, err := Lint(cs, cums, fs.Args(), &Options{
Tags: tags,
LintTests: tests,
GoVersion: goVersion,
Config: cfg,
PrintAnalyzerMeasurement: measureAnalyzers,
RepeatAnalyzers: debugRepeat,
})
if err != nil {
fmt.Fprintln(os.Stderr, err)
exit(1)
}
var f format.Formatter
switch formatter {
case "text":
f = format.Text{W: os.Stdout}
case "stylish":
f = &format.Stylish{W: os.Stdout}
case "json":
f = format.JSON{W: os.Stdout}
default:
fmt.Fprintf(os.Stderr, "unsupported output format %q\n", formatter)
exit(2)
}
var (
total int
errors int
warnings int
ignored int
)
fail := *fs.Lookup("fail").Value.(*list)
analyzers := make([]*analysis.Analyzer, len(cs), len(cs)+len(cums))
copy(analyzers, cs)
for _, cum := range cums {
analyzers = append(analyzers, cum.Analyzer())
}
shouldExit := lint.FilterChecks(analyzers, fail)
shouldExit["compile"] = true
total = len(ps)
for _, p := range ps {
if p.Check == "compile" && debugNoCompile {
continue
}
if p.Severity == lint.Ignored && !showIgnored {
ignored++
continue
}
if shouldExit[p.Check] {
errors++
} else {
p.Severity = lint.Warning
warnings++
}
f.Format(p)
}
if f, ok := f.(format.Statter); ok {
f.Stats(total, errors, warnings, ignored)
}
if errors > 0 {
exit(1)
}
exit(0)
}
type Options struct {
Config config.Config
Tags string
LintTests bool
GoVersion int
PrintAnalyzerMeasurement func(analysis *analysis.Analyzer, pkg *lint.Package, d time.Duration)
RepeatAnalyzers uint
}
func computeSalt() ([]byte, error) {
if version.Version != "devel" {
return []byte(version.Version), nil
}
p, err := os.Executable()
if err != nil {
return nil, err
}
f, err := os.Open(p)
if err != nil {
return nil, err
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return nil, err
}
return h.Sum(nil), nil
}
func Lint(cs []*analysis.Analyzer, cums []lint.CumulativeChecker, paths []string, opt *Options) ([]lint.Problem, error) {
salt, err := computeSalt()
if err != nil {
return nil, fmt.Errorf("could not compute salt for cache: %s", err)
}
cache.SetSalt(salt)
if opt == nil {
opt = &Options{}
}
l := &lint.Linter{
Checkers: cs,
CumulativeCheckers: cums,
GoVersion: opt.GoVersion,
Config: opt.Config,
RepeatAnalyzers: opt.RepeatAnalyzers,
}
l.Stats.PrintAnalyzerMeasurement = opt.PrintAnalyzerMeasurement
cfg := &packages.Config{}
if opt.LintTests {
cfg.Tests = true
}
if opt.Tags != "" {
cfg.BuildFlags = append(cfg.BuildFlags, "-tags", opt.Tags)
}
printStats := func() {
// Individual stats are read atomically, but overall there
// is no synchronisation. For printing rough progress
// information, this doesn't matter.
switch atomic.LoadUint32(&l.Stats.State) {
case lint.StateInitializing:
fmt.Fprintln(os.Stderr, "Status: initializing")
case lint.StateGraph:
fmt.Fprintln(os.Stderr, "Status: loading package graph")
case lint.StateProcessing:
fmt.Fprintf(os.Stderr, "Packages: %d/%d initial, %d/%d total; Workers: %d/%d; Problems: %d\n",
atomic.LoadUint32(&l.Stats.ProcessedInitialPackages),
atomic.LoadUint32(&l.Stats.InitialPackages),
atomic.LoadUint32(&l.Stats.ProcessedPackages),
atomic.LoadUint32(&l.Stats.TotalPackages),
atomic.LoadUint32(&l.Stats.ActiveWorkers),
atomic.LoadUint32(&l.Stats.TotalWorkers),
atomic.LoadUint32(&l.Stats.Problems),
)
case lint.StateCumulative:
fmt.Fprintln(os.Stderr, "Status: processing cumulative checkers")
}
}
if len(infoSignals) > 0 {
ch := make(chan os.Signal, 1)
signal.Notify(ch, infoSignals...)
defer signal.Stop(ch)
go func() {
for range ch {
printStats()
}
}()
}
ps, err := l.Lint(cfg, paths)
return ps, err
}
var posRe = regexp.MustCompile(`^(.+?):(\d+)(?::(\d+)?)?$`)
func parsePos(pos string) token.Position {
if pos == "-" || pos == "" {
return token.Position{}
}
parts := posRe.FindStringSubmatch(pos)
if parts == nil {
panic(fmt.Sprintf("internal error: malformed position %q", pos))
}
file := parts[1]
line, _ := strconv.Atoi(parts[2])
col, _ := strconv.Atoi(parts[3])
return token.Position{
Filename: file,
Line: line,
Column: col,
}
}
func InitializeAnalyzers(docs map[string]*lint.Documentation, analyzers map[string]*analysis.Analyzer) map[string]*analysis.Analyzer {
out := make(map[string]*analysis.Analyzer, len(analyzers))
for k, v := range analyzers {
vc := *v
out[k] = &vc
vc.Name = k
doc, ok := docs[k]
if !ok {
panic(fmt.Sprintf("missing documentation for check %s", k))
}
vc.Doc = doc.String()
if vc.Flags.Usage == nil {
fs := flag.NewFlagSet("", flag.PanicOnError)
fs.Var(NewVersionFlag(), "go", "Target Go version")
vc.Flags = *fs
}
}
return out
}

1114
vendor/honnef.co/go/tools/lint/runner.go vendored Normal file

File diff suppressed because it is too large Load Diff

38
vendor/honnef.co/go/tools/lint/stats.go vendored Normal file
View File

@@ -0,0 +1,38 @@
package lint
import (
"time"
"golang.org/x/tools/go/analysis"
)
const (
StateInitializing = 0
StateGraph = 1
StateProcessing = 2
StateCumulative = 3
)
type Stats struct {
State uint32
InitialPackages uint32
TotalPackages uint32
ProcessedPackages uint32
ProcessedInitialPackages uint32
Problems uint32
ActiveWorkers uint32
TotalWorkers uint32
PrintAnalyzerMeasurement func(*analysis.Analyzer, *Package, time.Duration)
}
type AnalysisMeasurementKey struct {
Analysis string
Pkg string
}
func (s *Stats) MeasureAnalyzer(analysis *analysis.Analyzer, pkg *Package, d time.Duration) {
if s.PrintAnalyzerMeasurement != nil {
s.PrintAnalyzerMeasurement(analysis, pkg, d)
}
}