diff --git a/vendor/manifest b/vendor/manifest index 830d3e2d..72a03662 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -10,7 +10,7 @@ { "importpath": "github.com/alecthomas/gometalinter", "repository": "https://github.com/alecthomas/gometalinter", - "revision": "0262fb20957a4c2d3bb7c834a6a125ae3884a2c6", + "revision": "212b1b91e362ea0b0e441c9b53ce31e81405c240", "branch": "master" }, { diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/golang.org/x/tools/refactor/importgraph/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/golang.org/x/tools/refactor/importgraph/LICENSE new file mode 100644 index 00000000..6a66aea5 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/golang.org/x/tools/refactor/importgraph/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. 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. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/golang.org/x/tools/refactor/importgraph/graph.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/golang.org/x/tools/refactor/importgraph/graph.go new file mode 100644 index 00000000..d2d8f098 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/golang.org/x/tools/refactor/importgraph/graph.go @@ -0,0 +1,167 @@ +// 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 importgraph computes the forward and reverse import +// dependency graphs for all packages in a Go workspace. +package importgraph // import "golang.org/x/tools/refactor/importgraph" + +import ( + "go/build" + "sync" + + "golang.org/x/tools/go/buildutil" +) + +// A Graph is an import dependency graph, either forward or reverse. +// +// The graph maps each node (a package import path) to the set of its +// successors in the graph. For a forward graph, this is the set of +// imported packages (prerequisites); for a reverse graph, it is the set +// of importing packages (clients). +// +// Graph construction inspects all imports in each package's directory, +// including those in _test.go files, so the resulting graph may be cyclic. +type Graph map[string]map[string]bool + +func (g Graph) addEdge(from, to string) { + edges := g[from] + if edges == nil { + edges = make(map[string]bool) + g[from] = edges + } + edges[to] = true +} + +// Search returns all the nodes of the graph reachable from +// any of the specified roots, by following edges forwards. +// Relationally, this is the reflexive transitive closure. +func (g Graph) Search(roots ...string) map[string]bool { + seen := make(map[string]bool) + var visit func(x string) + visit = func(x string) { + if !seen[x] { + seen[x] = true + for y := range g[x] { + visit(y) + } + } + } + for _, root := range roots { + visit(root) + } + return seen +} + +// Build scans the specified Go workspace and builds the forward and +// reverse import dependency graphs for all its packages. +// It also returns a mapping from canonical import paths to errors for packages +// whose loading was not entirely successful. +// A package may appear in the graph and in the errors mapping. +// All package paths are canonical and may contain "/vendor/". +func Build(ctxt *build.Context) (forward, reverse Graph, errors map[string]error) { + type importEdge struct { + from, to string + } + type pathError struct { + path string + err error + } + + ch := make(chan interface{}) + + go func() { + sema := make(chan int, 20) // I/O concurrency limiting semaphore + var wg sync.WaitGroup + buildutil.ForEachPackage(ctxt, func(path string, err error) { + if err != nil { + ch <- pathError{path, err} + return + } + + wg.Add(1) + go func() { + defer wg.Done() + + sema <- 1 + bp, err := ctxt.Import(path, "", 0) + <-sema + + if err != nil { + if _, ok := err.(*build.NoGoError); ok { + // empty directory is not an error + } else { + ch <- pathError{path, err} + } + // Even in error cases, Import usually returns a package. + } + + // absolutize resolves an import path relative + // to the current package bp. + // The absolute form may contain "vendor". + // + // The vendoring feature slows down Build by 3×. + // Here are timings from a 1400 package workspace: + // 1100ms: current code (with vendor check) + // 880ms: with a nonblocking cache around ctxt.IsDir + // 840ms: nonblocking cache with duplicate suppression + // 340ms: original code (no vendor check) + // TODO(adonovan): optimize, somehow. + memo := make(map[string]string) + absolutize := func(path string) string { + canon, ok := memo[path] + if !ok { + sema <- 1 + bp2, _ := ctxt.Import(path, bp.Dir, build.FindOnly) + <-sema + + if bp2 != nil { + canon = bp2.ImportPath + } else { + canon = path + } + memo[path] = canon + } + return canon + } + + if bp != nil { + for _, imp := range bp.Imports { + ch <- importEdge{path, absolutize(imp)} + } + for _, imp := range bp.TestImports { + ch <- importEdge{path, absolutize(imp)} + } + for _, imp := range bp.XTestImports { + ch <- importEdge{path, absolutize(imp)} + } + } + + }() + }) + wg.Wait() + close(ch) + }() + + forward = make(Graph) + reverse = make(Graph) + + for e := range ch { + switch e := e.(type) { + case pathError: + if errors == nil { + errors = make(map[string]error) + } + errors[e.path] = e.err + + case importEdge: + if e.to == "C" { + continue // "C" is fake + } + forward.addEdge(e.from, e.to) + reverse.addEdge(e.to, e.from) + } + } + + return forward, reverse, errors +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/callgraph/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/LICENSE similarity index 100% rename from vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/callgraph/LICENSE rename to vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/LICENSE diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/errcheck-ng/errcheck-ng.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/errcheck-ng/errcheck-ng.go new file mode 100644 index 00000000..cb5bab94 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/errcheck-ng/errcheck-ng.go @@ -0,0 +1,16 @@ +package main // import "honnef.co/go/tools/cmd/errcheck-ng" + +import ( + "os" + + "honnef.co/go/tools/errcheck" + "honnef.co/go/tools/lint/lintutil" +) + +func main() { + c := lintutil.CheckerConfig{ + Checker: errcheck.NewChecker(), + ExitNonZero: true, + } + lintutil.ProcessArgs("errcheck-ng", []lintutil.CheckerConfig{c}, os.Args[1:]) +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/gosimple/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/gosimple/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/gosimple/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go index a939a278..6ea1d79b 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/gosimple/gosimple.go @@ -13,6 +13,9 @@ func main() { fs.Parse(os.Args[1:]) c := simple.NewChecker() c.CheckGenerated = *gen - - lintutil.ProcessFlagSet(c, fs) + cfg := lintutil.CheckerConfig{ + Checker: c, + ExitNonZero: true, + } + lintutil.ProcessFlagSet([]lintutil.CheckerConfig{cfg}, fs) } diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/keyify/keyify.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/keyify/keyify.go new file mode 100644 index 00000000..5e18724b --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/keyify/keyify.go @@ -0,0 +1,401 @@ +// keyify transforms unkeyed struct literals into a keyed ones. +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "go/ast" + "go/build" + "go/constant" + "go/printer" + "go/token" + "go/types" + "log" + "os" + "path/filepath" + + "honnef.co/go/tools/version" + + "golang.org/x/tools/go/ast/astutil" + "golang.org/x/tools/go/buildutil" + "golang.org/x/tools/go/loader" +) + +var ( + fRecursive bool + fOneLine bool + fJSON bool + fMinify bool + fModified bool + fVersion bool +) + +func init() { + flag.BoolVar(&fRecursive, "r", false, "keyify struct initializers recursively") + flag.BoolVar(&fOneLine, "o", false, "print new struct initializer on a single line") + flag.BoolVar(&fJSON, "json", false, "print new struct initializer as JSON") + flag.BoolVar(&fMinify, "m", false, "omit fields that are set to their zero value") + flag.BoolVar(&fModified, "modified", false, "read an archive of modified files from standard input") + flag.BoolVar(&fVersion, "version", false, "Print version and exit") +} + +func usage() { + fmt.Printf("Usage: %s [flags] \n\n", os.Args[0]) + flag.PrintDefaults() +} + +func main() { + log.SetFlags(0) + flag.Usage = usage + flag.Parse() + + if fVersion { + version.Print() + os.Exit(0) + } + + if flag.NArg() != 1 { + flag.Usage() + os.Exit(2) + } + pos := flag.Args()[0] + name, start, _, err := parsePos(pos) + if err != nil { + log.Fatal(err) + } + eval, err := filepath.EvalSymlinks(name) + if err != nil { + log.Fatal(err) + } + name, err = filepath.Abs(eval) + if err != nil { + log.Fatal(err) + } + cwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + ctx := &build.Default + if fModified { + overlay, err := buildutil.ParseOverlayArchive(os.Stdin) + if err != nil { + log.Fatal(err) + } + ctx = buildutil.OverlayContext(ctx, overlay) + } + bpkg, err := buildutil.ContainingPackage(ctx, cwd, name) + if err != nil { + log.Fatal(err) + } + conf := &loader.Config{ + Build: ctx, + } + conf.TypeCheckFuncBodies = func(s string) bool { + return s == bpkg.ImportPath || s == bpkg.ImportPath+"_test" + } + conf.ImportWithTests(bpkg.ImportPath) + lprog, err := conf.Load() + if err != nil { + log.Fatal(err) + } + var tf *token.File + var af *ast.File + pkg := lprog.InitialPackages()[0] + for _, ff := range pkg.Files { + file := lprog.Fset.File(ff.Pos()) + if file.Name() == name { + af = ff + tf = file + break + } + } + tstart, tend, err := fileOffsetToPos(tf, start, start) + if err != nil { + log.Fatal(err) + } + path, _ := astutil.PathEnclosingInterval(af, tstart, tend) + var complit *ast.CompositeLit + for _, p := range path { + if p, ok := p.(*ast.CompositeLit); ok { + complit = p + break + } + } + if complit == nil { + log.Fatal("no composite literal found near point") + } + if len(complit.Elts) == 0 { + printComplit(complit, complit, lprog.Fset, lprog.Fset) + return + } + if _, ok := complit.Elts[0].(*ast.KeyValueExpr); ok { + lit := complit + if fOneLine { + lit = copyExpr(complit, 1).(*ast.CompositeLit) + } + printComplit(complit, lit, lprog.Fset, lprog.Fset) + return + } + _, ok := pkg.TypeOf(complit).Underlying().(*types.Struct) + if !ok { + log.Fatal("not a struct initialiser") + return + } + + newComplit, lines := keyify(pkg, complit) + newFset := token.NewFileSet() + newFile := newFset.AddFile("", -1, lines) + for i := 1; i <= lines; i++ { + newFile.AddLine(i) + } + printComplit(complit, newComplit, lprog.Fset, newFset) +} + +func keyify( + pkg *loader.PackageInfo, + complit *ast.CompositeLit, +) (*ast.CompositeLit, int) { + var calcPos func(int) token.Pos + if fOneLine { + calcPos = func(int) token.Pos { return token.Pos(1) } + } else { + calcPos = func(i int) token.Pos { return token.Pos(2 + i) } + } + + st, _ := pkg.TypeOf(complit).Underlying().(*types.Struct) + newComplit := &ast.CompositeLit{ + Type: complit.Type, + Lbrace: 1, + Rbrace: token.Pos(st.NumFields() + 2), + } + if fOneLine { + newComplit.Rbrace = 1 + } + numLines := 2 + st.NumFields() + n := 0 + for i := 0; i < st.NumFields(); i++ { + field := st.Field(i) + val := complit.Elts[i] + if fRecursive { + if val2, ok := val.(*ast.CompositeLit); ok { + if _, ok := pkg.TypeOf(val2.Type).Underlying().(*types.Struct); ok { + var lines int + numLines += lines + val, lines = keyify(pkg, val2) + } + } + } + _, isIface := st.Field(i).Type().Underlying().(*types.Interface) + if fMinify && (isNil(val, pkg) || (!isIface && isZero(val, pkg))) { + continue + } + elt := &ast.KeyValueExpr{ + Key: &ast.Ident{NamePos: calcPos(n), Name: field.Name()}, + Value: copyExpr(val, calcPos(n)), + } + newComplit.Elts = append(newComplit.Elts, elt) + n++ + } + return newComplit, numLines +} + +func isNil(val ast.Expr, pkg *loader.PackageInfo) bool { + ident, ok := val.(*ast.Ident) + if !ok { + return false + } + if _, ok := pkg.ObjectOf(ident).(*types.Nil); ok { + return true + } + if c, ok := pkg.ObjectOf(ident).(*types.Const); ok { + if c.Val().Kind() != constant.Bool { + return false + } + return !constant.BoolVal(c.Val()) + } + return false +} + +func isZero(val ast.Expr, pkg *loader.PackageInfo) bool { + switch val := val.(type) { + case *ast.BasicLit: + switch val.Value { + case `""`, "``", "0", "0.0", "0i", "0.": + return true + default: + return false + } + case *ast.Ident: + return isNil(val, pkg) + case *ast.CompositeLit: + typ := pkg.TypeOf(val.Type) + if typ == nil { + return false + } + isIface := false + switch typ := typ.Underlying().(type) { + case *types.Struct: + case *types.Array: + _, isIface = typ.Elem().Underlying().(*types.Interface) + default: + return false + } + for _, elt := range val.Elts { + if isNil(elt, pkg) || (!isIface && !isZero(elt, pkg)) { + return false + } + } + return true + } + return false +} + +func printComplit(oldlit, newlit *ast.CompositeLit, oldfset, newfset *token.FileSet) { + buf := &bytes.Buffer{} + cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8} + _ = cfg.Fprint(buf, newfset, newlit) + if fJSON { + output := struct { + Start int `json:"start"` + End int `json:"end"` + Replacement string `json:"replacement"` + }{ + oldfset.Position(oldlit.Pos()).Offset, + oldfset.Position(oldlit.End()).Offset, + buf.String(), + } + _ = json.NewEncoder(os.Stdout).Encode(output) + } else { + fmt.Println(buf.String()) + } +} + +func copyExpr(expr ast.Expr, line token.Pos) ast.Expr { + switch expr := expr.(type) { + case *ast.BasicLit: + cp := *expr + cp.ValuePos = 0 + return &cp + case *ast.BinaryExpr: + cp := *expr + cp.X = copyExpr(cp.X, line) + cp.OpPos = 0 + cp.Y = copyExpr(cp.Y, line) + return &cp + case *ast.CallExpr: + cp := *expr + cp.Fun = copyExpr(cp.Fun, line) + cp.Lparen = 0 + for i, v := range cp.Args { + cp.Args[i] = copyExpr(v, line) + } + if cp.Ellipsis != 0 { + cp.Ellipsis = line + } + cp.Rparen = 0 + return &cp + case *ast.CompositeLit: + cp := *expr + cp.Type = copyExpr(cp.Type, line) + cp.Lbrace = 0 + for i, v := range cp.Elts { + cp.Elts[i] = copyExpr(v, line) + } + cp.Rbrace = 0 + return &cp + case *ast.Ident: + cp := *expr + cp.NamePos = 0 + return &cp + case *ast.IndexExpr: + cp := *expr + cp.X = copyExpr(cp.X, line) + cp.Lbrack = 0 + cp.Index = copyExpr(cp.Index, line) + cp.Rbrack = 0 + return &cp + case *ast.KeyValueExpr: + cp := *expr + cp.Key = copyExpr(cp.Key, line) + cp.Colon = 0 + cp.Value = copyExpr(cp.Value, line) + return &cp + case *ast.ParenExpr: + cp := *expr + cp.Lparen = 0 + cp.X = copyExpr(cp.X, line) + cp.Rparen = 0 + return &cp + case *ast.SelectorExpr: + cp := *expr + cp.X = copyExpr(cp.X, line) + cp.Sel = copyExpr(cp.Sel, line).(*ast.Ident) + return &cp + case *ast.SliceExpr: + cp := *expr + cp.X = copyExpr(cp.X, line) + cp.Lbrack = 0 + cp.Low = copyExpr(cp.Low, line) + cp.High = copyExpr(cp.High, line) + cp.Max = copyExpr(cp.Max, line) + cp.Rbrack = 0 + return &cp + case *ast.StarExpr: + cp := *expr + cp.Star = 0 + cp.X = copyExpr(cp.X, line) + return &cp + case *ast.TypeAssertExpr: + cp := *expr + cp.X = copyExpr(cp.X, line) + cp.Lparen = 0 + cp.Type = copyExpr(cp.Type, line) + cp.Rparen = 0 + return &cp + case *ast.UnaryExpr: + cp := *expr + cp.OpPos = 0 + cp.X = copyExpr(cp.X, line) + return &cp + case *ast.MapType: + cp := *expr + cp.Map = 0 + cp.Key = copyExpr(cp.Key, line) + cp.Value = copyExpr(cp.Value, line) + return &cp + case *ast.ArrayType: + cp := *expr + cp.Lbrack = 0 + cp.Len = copyExpr(cp.Len, line) + cp.Elt = copyExpr(cp.Elt, line) + return &cp + case *ast.Ellipsis: + cp := *expr + cp.Elt = copyExpr(cp.Elt, line) + cp.Ellipsis = line + return &cp + case *ast.InterfaceType: + cp := *expr + cp.Interface = 0 + return &cp + case *ast.StructType: + cp := *expr + cp.Struct = 0 + return &cp + case *ast.FuncLit: + return expr + case *ast.ChanType: + cp := *expr + cp.Arrow = 0 + cp.Begin = 0 + cp.Value = copyExpr(cp.Value, line) + return &cp + case nil: + return nil + default: + panic(fmt.Sprintf("shouldn't happen: unknown ast.Expr of type %T", expr)) + } + return nil +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/keyify/position.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/keyify/position.go new file mode 100644 index 00000000..b9578760 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/keyify/position.go @@ -0,0 +1,71 @@ +// 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 ( + "fmt" + "go/token" + "strconv" + "strings" +) + +func parseOctothorpDecimal(s string) int { + if s != "" && s[0] == '#' { + if s, err := strconv.ParseInt(s[1:], 10, 32); err == nil { + return int(s) + } + } + return -1 +} + +func parsePos(pos string) (filename string, startOffset, endOffset int, err error) { + if pos == "" { + err = fmt.Errorf("no source position specified") + return + } + + colon := strings.LastIndex(pos, ":") + if colon < 0 { + err = fmt.Errorf("bad position syntax %q", pos) + return + } + filename, offset := pos[:colon], pos[colon+1:] + startOffset = -1 + endOffset = -1 + if hyphen := strings.Index(offset, ","); hyphen < 0 { + // e.g. "foo.go:#123" + startOffset = parseOctothorpDecimal(offset) + endOffset = startOffset + } else { + // e.g. "foo.go:#123,#456" + startOffset = parseOctothorpDecimal(offset[:hyphen]) + endOffset = parseOctothorpDecimal(offset[hyphen+1:]) + } + if startOffset < 0 || endOffset < 0 { + err = fmt.Errorf("invalid offset %q in query position", offset) + return + } + return +} + +func fileOffsetToPos(file *token.File, startOffset, endOffset int) (start, end token.Pos, err error) { + // Range check [start..end], inclusive of both end-points. + + if 0 <= startOffset && startOffset <= file.Size() { + start = file.Pos(int(startOffset)) + } else { + err = fmt.Errorf("start position is beyond end of file") + return + } + + if 0 <= endOffset && endOffset <= file.Size() { + end = file.Pos(int(endOffset)) + } else { + err = fmt.Errorf("end position is beyond end of file") + return + } + + return +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/megacheck/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/megacheck/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/megacheck/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/megacheck/megacheck.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/megacheck/megacheck.go index 8477df65..4c0b97c8 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/megacheck/megacheck.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/megacheck/megacheck.go @@ -4,42 +4,23 @@ package main // import "honnef.co/go/tools/cmd/megacheck" import ( "os" - "honnef.co/go/tools/lint" "honnef.co/go/tools/lint/lintutil" "honnef.co/go/tools/simple" "honnef.co/go/tools/staticcheck" "honnef.co/go/tools/unused" ) -type Checker struct { - Checkers []lint.Checker -} - -func (c *Checker) Init(prog *lint.Program) { - for _, cc := range c.Checkers { - cc.Init(prog) - } -} - -func (c *Checker) Funcs() map[string]lint.Func { - fns := map[string]lint.Func{} - for _, cc := range c.Checkers { - for k, v := range cc.Funcs() { - fns[k] = v - } - } - return fns -} - func main() { var flags struct { staticcheck struct { - enabled bool - generated bool + enabled bool + generated bool + exitNonZero bool } gosimple struct { - enabled bool - generated bool + enabled bool + generated bool + exitNonZero bool } unused struct { enabled bool @@ -51,6 +32,7 @@ func main() { debug string wholeProgram bool reflection bool + exitNonZero bool } } fs := lintutil.FlagSet("megacheck") @@ -58,11 +40,15 @@ func main() { "simple.enabled", true, "Run gosimple") fs.BoolVar(&flags.gosimple.generated, "simple.generated", false, "Check generated code") + fs.BoolVar(&flags.gosimple.exitNonZero, + "simple.exit-non-zero", false, "Exit non-zero if any problems were found") fs.BoolVar(&flags.staticcheck.enabled, "staticcheck.enabled", true, "Run staticcheck") fs.BoolVar(&flags.staticcheck.generated, "staticcheck.generated", false, "Check generated code (only applies to a subset of checks)") + fs.BoolVar(&flags.staticcheck.exitNonZero, + "staticcheck.exit-non-zero", true, "Exit non-zero if any problems were found") fs.BoolVar(&flags.unused.enabled, "unused.enabled", true, "Run unused") @@ -78,22 +64,31 @@ func main() { "unused.vars", true, "Report unused variables") fs.BoolVar(&flags.unused.wholeProgram, "unused.exported", false, "Treat arguments as a program and report unused exported identifiers") - fs.BoolVar(&flags.unused.reflection, "unused.reflect", true, "Consider identifiers as used when it's likely they'll be accessed via reflection") + fs.BoolVar(&flags.unused.reflection, + "unused.reflect", true, "Consider identifiers as used when it's likely they'll be accessed via reflection") + fs.BoolVar(&flags.unused.exitNonZero, + "unused.exit-non-zero", true, "Exit non-zero if any problems were found") fs.Parse(os.Args[1:]) - c := &Checker{} + var checkers []lintutil.CheckerConfig if flags.staticcheck.enabled { sac := staticcheck.NewChecker() sac.CheckGenerated = flags.staticcheck.generated - c.Checkers = append(c.Checkers, sac) + checkers = append(checkers, lintutil.CheckerConfig{ + Checker: sac, + ExitNonZero: flags.staticcheck.exitNonZero, + }) } if flags.gosimple.enabled { sc := simple.NewChecker() sc.CheckGenerated = flags.gosimple.generated - c.Checkers = append(c.Checkers, sc) + checkers = append(checkers, lintutil.CheckerConfig{ + Checker: sc, + ExitNonZero: flags.gosimple.exitNonZero, + }) } if flags.unused.enabled { @@ -116,8 +111,12 @@ func main() { uc := unused.NewChecker(mode) uc.WholeProgram = flags.unused.wholeProgram uc.ConsiderReflection = flags.unused.reflection - c.Checkers = append(c.Checkers, unused.NewLintChecker(uc)) + checkers = append(checkers, lintutil.CheckerConfig{ + Checker: unused.NewLintChecker(uc), + ExitNonZero: flags.unused.exitNonZero, + }) + } - lintutil.ProcessFlagSet(c, fs) + lintutil.ProcessFlagSet(checkers, fs) } diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/rdeps/rdeps.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/rdeps/rdeps.go new file mode 100644 index 00000000..f4a3d0c7 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/rdeps/rdeps.go @@ -0,0 +1,86 @@ +// rdeps scans GOPATH for all reverse dependencies of a set of Go +// packages. +// +// rdeps will not sort its output, and the order of the output is +// undefined. Pipe its output through sort if you need stable output. +package main + +import ( + "bufio" + "flag" + "fmt" + "go/build" + "os" + + "honnef.co/go/tools/version" + + "github.com/kisielk/gotool" + "golang.org/x/tools/go/buildutil" + "golang.org/x/tools/refactor/importgraph" +) + +func main() { + var tags buildutil.TagsFlag + flag.Var(&tags, "tags", "List of build tags") + stdin := flag.Bool("stdin", false, "Read packages from stdin instead of the command line") + recursive := flag.Bool("r", false, "Print reverse dependencies recursively") + printVersion := flag.Bool("version", false, "Print version and exit") + flag.Parse() + + if *printVersion { + version.Print() + os.Exit(0) + } + + ctx := build.Default + ctx.BuildTags = tags + var args []string + if *stdin { + s := bufio.NewScanner(os.Stdin) + for s.Scan() { + args = append(args, s.Text()) + } + } else { + args = flag.Args() + } + if len(args) == 0 { + return + } + wd, err := os.Getwd() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + pkgs := gotool.ImportPaths(args) + for i, pkg := range pkgs { + bpkg, err := ctx.Import(pkg, wd, build.FindOnly) + if err != nil { + continue + } + pkgs[i] = bpkg.ImportPath + } + _, reverse, errors := importgraph.Build(&ctx) + _ = errors + + seen := map[string]bool{} + var printRDeps func(pkg string) + printRDeps = func(pkg string) { + for rdep := range reverse[pkg] { + if seen[rdep] { + continue + } + seen[rdep] = true + fmt.Println(rdep) + if *recursive { + printRDeps(rdep) + } + } + } + + for _, pkg := range pkgs { + printRDeps(pkg) + } + for pkg, err := range errors { + fmt.Fprintf(os.Stderr, "error in package %s: %s\n", pkg, err) + } +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/staticcheck/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/staticcheck/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/staticcheck/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go index 46f496c4..5e6d6f9c 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/staticcheck/staticcheck.go @@ -15,5 +15,9 @@ func main() { fs.Parse(os.Args[1:]) c := staticcheck.NewChecker() c.CheckGenerated = *gen - lintutil.ProcessFlagSet(c, fs) + cfg := lintutil.CheckerConfig{ + Checker: c, + ExitNonZero: true, + } + lintutil.ProcessFlagSet([]lintutil.CheckerConfig{cfg}, fs) } diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout-optimize/main.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout-optimize/main.go new file mode 100644 index 00000000..dd9c1f3b --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout-optimize/main.go @@ -0,0 +1,205 @@ +// structlayout-optimize reorders struct fields to minimize the amount +// of padding. +package main + +import ( + "encoding/json" + "flag" + "fmt" + "log" + "os" + "sort" + "strings" + + st "honnef.co/go/tools/structlayout" + "honnef.co/go/tools/version" +) + +var ( + fJSON bool + fRecurse bool + fVersion bool +) + +func init() { + flag.BoolVar(&fJSON, "json", false, "Format data as JSON") + flag.BoolVar(&fRecurse, "r", false, "Break up structs and reorder their fields freely") + flag.BoolVar(&fVersion, "version", false, "Print version and exit") +} + +func main() { + log.SetFlags(0) + flag.Parse() + + if fVersion { + version.Print() + os.Exit(0) + } + + var in []st.Field + if err := json.NewDecoder(os.Stdin).Decode(&in); err != nil { + log.Fatal(err) + } + if len(in) == 0 { + return + } + if !fRecurse { + in = combine(in) + } + var fields []st.Field + for _, field := range in { + if field.IsPadding { + continue + } + fields = append(fields, field) + } + optimize(fields) + fields = pad(fields) + + if fJSON { + json.NewEncoder(os.Stdout).Encode(fields) + } else { + for _, field := range fields { + fmt.Println(field) + } + } +} + +func combine(fields []st.Field) []st.Field { + new := st.Field{} + cur := "" + var out []st.Field + wasPad := true + for _, field := range fields { + var prefix string + if field.IsPadding { + wasPad = true + continue + } + p := strings.Split(field.Name, ".") + prefix = strings.Join(p[:2], ".") + if field.Align > new.Align { + new.Align = field.Align + } + if !wasPad { + new.End = field.Start + new.Size = new.End - new.Start + } + if prefix != cur { + if cur != "" { + out = append(out, new) + } + cur = prefix + new = field + new.Name = prefix + } else { + new.Type = "struct" + } + wasPad = false + } + new.Size = new.End - new.Start + out = append(out, new) + return out +} + +func optimize(fields []st.Field) { + sort.Sort(&byAlignAndSize{fields}) +} + +func pad(fields []st.Field) []st.Field { + if len(fields) == 0 { + return nil + } + var out []st.Field + pos := int64(0) + offsets := offsetsof(fields) + alignment := int64(1) + for i, field := range fields { + if field.Align > alignment { + alignment = field.Align + } + if offsets[i] > pos { + padding := offsets[i] - pos + out = append(out, st.Field{ + IsPadding: true, + Start: pos, + End: pos + padding, + Size: padding, + }) + pos += padding + } + field.Start = pos + field.End = pos + field.Size + out = append(out, field) + pos += field.Size + } + sz := size(out) + pad := align(sz, alignment) - sz + if pad > 0 { + field := out[len(out)-1] + out = append(out, st.Field{ + IsPadding: true, + Start: field.End, + End: field.End + pad, + Size: pad, + }) + } + return out +} + +func size(fields []st.Field) int64 { + n := int64(0) + for _, field := range fields { + n += field.Size + } + return n +} + +type byAlignAndSize struct { + fields []st.Field +} + +func (s *byAlignAndSize) Len() int { return len(s.fields) } +func (s *byAlignAndSize) Swap(i, j int) { + s.fields[i], s.fields[j] = s.fields[j], s.fields[i] +} + +func (s *byAlignAndSize) Less(i, j int) bool { + // Place zero sized objects before non-zero sized objects. + if s.fields[i].Size == 0 && s.fields[j].Size != 0 { + return true + } + if s.fields[j].Size == 0 && s.fields[i].Size != 0 { + return false + } + + // Next, place more tightly aligned objects before less tightly aligned objects. + if s.fields[i].Align != s.fields[j].Align { + return s.fields[i].Align > s.fields[j].Align + } + + // Lastly, order by size. + if s.fields[i].Size != s.fields[j].Size { + return s.fields[i].Size > s.fields[j].Size + } + + return false +} + +func offsetsof(fields []st.Field) []int64 { + offsets := make([]int64, len(fields)) + var o int64 + for i, f := range fields { + a := f.Align + o = align(o, a) + offsets[i] = o + o += f.Size + } + return offsets +} + +// align returns the smallest y >= x such that y % a == 0. +func align(x, a int64) int64 { + y := x + a - 1 + return y - y%a +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout-pretty/main.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout-pretty/main.go new file mode 100644 index 00000000..a75192c9 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout-pretty/main.go @@ -0,0 +1,72 @@ +// structlayout-pretty formats the output of structlayout with ASCII +// art. +package main + +import ( + "encoding/json" + "flag" + "fmt" + "log" + "os" + "strings" + + st "honnef.co/go/tools/structlayout" + "honnef.co/go/tools/version" +) + +var ( + fVerbose bool + fVersion bool +) + +func init() { + flag.BoolVar(&fVerbose, "v", false, "Do not compact consecutive bytes of fields") + flag.BoolVar(&fVersion, "version", false, "Print version and exit") +} + +func main() { + log.SetFlags(0) + flag.Parse() + + if fVersion { + version.Print() + os.Exit(0) + } + + var fields []st.Field + if err := json.NewDecoder(os.Stdin).Decode(&fields); err != nil { + log.Fatal(err) + } + if len(fields) == 0 { + return + } + max := fields[len(fields)-1].End + maxLength := len(fmt.Sprintf("%d", max)) + padding := strings.Repeat(" ", maxLength+2) + format := fmt.Sprintf(" %%%dd ", maxLength) + pos := int64(0) + fmt.Println(padding + "+--------+") + for _, field := range fields { + name := field.Name + " " + field.Type + if field.IsPadding { + name = "padding" + } + fmt.Printf(format+"| | <- %s (size %d, align %d)\n", pos, name, field.Size, field.Align) + fmt.Println(padding + "+--------+") + + if fVerbose { + for i := int64(0); i < field.Size-1; i++ { + fmt.Printf(format+"| |\n", pos+i+1) + fmt.Println(padding + "+--------+") + } + } else { + if field.Size > 2 { + fmt.Println(padding + "-........-") + fmt.Println(padding + "+--------+") + fmt.Printf(format+"| |\n", pos+field.Size-1) + fmt.Println(padding + "+--------+") + } + } + pos += field.Size + } +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout/main.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout/main.go new file mode 100644 index 00000000..0cdf7c2c --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/structlayout/main.go @@ -0,0 +1,149 @@ +// structlayout displays the layout (field sizes and padding) of structs. +package main + +import ( + "encoding/json" + "flag" + "fmt" + "go/build" + "go/types" + "log" + "os" + + "honnef.co/go/tools/gcsizes" + st "honnef.co/go/tools/structlayout" + "honnef.co/go/tools/version" + + "golang.org/x/tools/go/loader" +) + +var ( + fJSON bool + fVersion bool +) + +func init() { + flag.BoolVar(&fJSON, "json", false, "Format data as JSON") + flag.BoolVar(&fVersion, "version", false, "Print version and exit") +} + +func main() { + log.SetFlags(0) + flag.Parse() + + if fVersion { + version.Print() + os.Exit(0) + } + + if len(flag.Args()) != 2 { + flag.Usage() + os.Exit(1) + } + + conf := loader.Config{ + Build: &build.Default, + } + + var pkg string + var typName string + pkg = flag.Args()[0] + typName = flag.Args()[1] + conf.Import(pkg) + + lprog, err := conf.Load() + if err != nil { + log.Fatal(err) + } + var typ types.Type + obj := lprog.Package(pkg).Pkg.Scope().Lookup(typName) + if obj == nil { + log.Fatal("couldn't find type") + } + typ = obj.Type() + + st, ok := typ.Underlying().(*types.Struct) + if !ok { + log.Fatal("identifier is not a struct type") + } + + fields := sizes(st, typ.(*types.Named).Obj().Name(), 0, nil) + if fJSON { + emitJSON(fields) + } else { + emitText(fields) + } +} + +func emitJSON(fields []st.Field) { + if fields == nil { + fields = []st.Field{} + } + json.NewEncoder(os.Stdout).Encode(fields) +} + +func emitText(fields []st.Field) { + for _, field := range fields { + fmt.Println(field) + } +} +func sizes(typ *types.Struct, prefix string, base int64, out []st.Field) []st.Field { + s := gcsizes.ForArch(build.Default.GOARCH) + n := typ.NumFields() + var fields []*types.Var + for i := 0; i < n; i++ { + fields = append(fields, typ.Field(i)) + } + offsets := s.Offsetsof(fields) + for i := range offsets { + offsets[i] += base + } + + pos := base + for i, field := range fields { + if offsets[i] > pos { + padding := offsets[i] - pos + out = append(out, st.Field{ + IsPadding: true, + Start: pos, + End: pos + padding, + Size: padding, + }) + pos += padding + } + size := s.Sizeof(field.Type()) + if typ2, ok := field.Type().Underlying().(*types.Struct); ok && typ2.NumFields() != 0 { + out = sizes(typ2, prefix+"."+field.Name(), pos, out) + } else { + out = append(out, st.Field{ + Name: prefix + "." + field.Name(), + Type: field.Type().String(), + Start: offsets[i], + End: offsets[i] + size, + Size: size, + Align: s.Alignof(field.Type()), + }) + } + pos += size + } + + if len(out) == 0 { + return out + } + field := &out[len(out)-1] + if field.Size == 0 { + field.Size = 1 + field.End++ + } + pad := s.Sizeof(typ) - field.End + if pad > 0 { + out = append(out, st.Field{ + IsPadding: true, + Start: field.End, + End: field.End + pad, + Size: pad, + }) + } + + return out +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/unused/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/unused/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/unused/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/unused/main.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/unused/main.go index 9d0abfb6..9698db50 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/unused/main.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/cmd/unused/main.go @@ -70,5 +70,9 @@ func main() { checker := newChecker(mode) l := unused.NewLintChecker(checker) - lintutil.ProcessFlagSet(l, fs) + cfg := lintutil.CheckerConfig{ + Checker: l, + ExitNonZero: true, + } + lintutil.ProcessFlagSet([]lintutil.CheckerConfig{cfg}, fs) } diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/deprecated/stdlib.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/deprecated/stdlib.go new file mode 100644 index 00000000..b6b217c3 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/deprecated/stdlib.go @@ -0,0 +1,54 @@ +package deprecated + +type Deprecation struct { + DeprecatedSince int + AlternativeAvailableSince int +} + +var Stdlib = map[string]Deprecation{ + "image/jpeg.Reader": {4, 0}, + // FIXME(dh): AllowBinary isn't being detected as deprecated + // because the comment has a newline right after "Deprecated:" + "go/build.AllowBinary": {7, 7}, + "(archive/zip.FileHeader).CompressedSize": {1, 1}, + "(archive/zip.FileHeader).UncompressedSize": {1, 1}, + "(go/doc.Package).Bugs": {1, 1}, + "os.SEEK_SET": {7, 7}, + "os.SEEK_CUR": {7, 7}, + "os.SEEK_END": {7, 7}, + "(net.Dialer).Cancel": {7, 7}, + "runtime.CPUProfile": {9, 0}, + "compress/flate.ReadError": {6, 6}, + "compress/flate.WriteError": {6, 6}, + "path/filepath.HasPrefix": {0, 0}, + "(net/http.Transport).Dial": {7, 7}, + "(*net/http.Transport).CancelRequest": {6, 5}, + "net/http.ErrWriteAfterFlush": {7, 0}, + "net/http.ErrHeaderTooLong": {8, 0}, + "net/http.ErrShortBody": {8, 0}, + "net/http.ErrMissingContentLength": {8, 0}, + "net/http/httputil.ErrPersistEOF": {0, 0}, + "net/http/httputil.ErrClosed": {0, 0}, + "net/http/httputil.ErrPipeline": {0, 0}, + "net/http/httputil.ServerConn": {0, 0}, + "net/http/httputil.NewServerConn": {0, 0}, + "net/http/httputil.ClientConn": {0, 0}, + "net/http/httputil.NewClientConn": {0, 0}, + "net/http/httputil.NewProxyClientConn": {0, 0}, + "(net/http.Request).Cancel": {7, 7}, + "(text/template/parse.PipeNode).Line": {1, 1}, + "(text/template/parse.ActionNode).Line": {1, 1}, + "(text/template/parse.BranchNode).Line": {1, 1}, + "(text/template/parse.TemplateNode).Line": {1, 1}, + "database/sql/driver.ColumnConverter": {9, 9}, + "database/sql/driver.Execer": {8, 8}, + "database/sql/driver.Queryer": {8, 8}, + "(database/sql/driver.Conn).Begin": {8, 8}, + "(database/sql/driver.Stmt).Exec": {8, 8}, + "(database/sql/driver.Stmt).Query": {8, 8}, + "syscall.StringByteSlice": {1, 1}, + "syscall.StringBytePtr": {1, 1}, + "syscall.StringSlicePtr": {1, 1}, + "syscall.StringToUTF16": {1, 1}, + "syscall.StringToUTF16Ptr": {1, 1}, +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/errcheck/errcheck.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/errcheck/errcheck.go new file mode 100644 index 00000000..d9004de3 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/errcheck/errcheck.go @@ -0,0 +1,157 @@ +package errcheck + +import ( + "go/types" + + "honnef.co/go/tools/functions" + "honnef.co/go/tools/lint" + "honnef.co/go/tools/ssa" +) + +type Checker struct { + funcDescs *functions.Descriptions +} + +func NewChecker() *Checker { + return &Checker{} +} + +func (*Checker) Name() string { return "errcheck" } +func (*Checker) Prefix() string { return "ERR" } + +func (c *Checker) Funcs() map[string]lint.Func { + return map[string]lint.Func{ + "ERR1000": c.CheckErrcheck, + } +} + +func (c *Checker) Init(prog *lint.Program) { + c.funcDescs = functions.NewDescriptions(prog.SSA) +} + +func (c *Checker) CheckErrcheck(j *lint.Job) { + for _, ssafn := range j.Program.InitialFunctions { + for _, b := range ssafn.Blocks { + for _, ins := range b.Instrs { + ssacall, ok := ins.(ssa.CallInstruction) + if !ok { + continue + } + + switch lint.CallName(ssacall.Common()) { + case "fmt.Print", "fmt.Println", "fmt.Printf": + continue + } + isRecover := false + if builtin, ok := ssacall.Common().Value.(*ssa.Builtin); ok { + isRecover = ok && builtin.Name() == "recover" + } + + switch ins := ins.(type) { + case ssa.Value: + refs := ins.Referrers() + if refs == nil || len(lint.FilterDebug(*refs)) != 0 { + continue + } + case ssa.Instruction: + // will be a 'go' or 'defer', neither of which has usable return values + default: + // shouldn't happen + continue + } + + if ssacall.Common().IsInvoke() { + if sc, ok := ssacall.Common().Value.(*ssa.Call); ok { + // TODO(dh): support multiple levels of + // interfaces, not just one + ssafn := sc.Common().StaticCallee() + if ssafn != nil { + ct := c.funcDescs.Get(ssafn).ConcreteReturnTypes + // TODO(dh): support >1 concrete types + if ct != nil && len(ct) == 1 { + // TODO(dh): do we have access to a + // cached method set somewhere? + ms := types.NewMethodSet(ct[0].At(ct[0].Len() - 1).Type()) + // TODO(dh): where can we get the pkg + // for Lookup? Passing nil works fine + // for exported methods, but will fail + // on unexported ones + // TODO(dh): holy nesting and poor + // variable names, clean this up + fn, _ := ms.Lookup(nil, ssacall.Common().Method.Name()).Obj().(*types.Func) + if fn != nil { + ssafn := j.Program.SSA.FuncValue(fn) + if ssafn != nil { + if c.funcDescs.Get(ssafn).NilError { + continue + } + } + } + } + } + } + } else { + ssafn := ssacall.Common().StaticCallee() + if ssafn != nil { + if c.funcDescs.Get(ssafn).NilError { + // Don't complain when the error is known to be nil + continue + } + } + } + switch lint.CallName(ssacall.Common()) { + case "(*os.File).Close": + recv := ssacall.Common().Args[0] + if isReadOnlyFile(recv, nil) { + continue + } + } + + res := ssacall.Common().Signature().Results() + if res.Len() == 0 { + continue + } + if !isRecover { + last := res.At(res.Len() - 1) + if types.TypeString(last.Type(), nil) != "error" { + continue + } + } + j.Errorf(ins, "unchecked error") + } + } + } +} + +func isReadOnlyFile(val ssa.Value, seen map[ssa.Value]bool) bool { + if seen == nil { + seen = map[ssa.Value]bool{} + } + if seen[val] { + return true + } + seen[val] = true + switch val := val.(type) { + case *ssa.Phi: + for _, edge := range val.Edges { + if !isReadOnlyFile(edge, seen) { + return false + } + } + return true + case *ssa.Extract: + call, ok := val.Tuple.(*ssa.Call) + if !ok { + return false + } + switch lint.CallName(call.Common()) { + case "os.Open": + return true + case "os.OpenFile": + flags, ok := call.Common().Args[1].(*ssa.Const) + return ok && flags.Uint64() == 0 + } + return false + } + return false +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/functions.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/functions.go index 9213600c..c5fe2d72 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/functions.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/functions.go @@ -48,6 +48,8 @@ var stdlibDescs = map[string]Description{ type Description struct { // The function is known to be pure Pure bool + // The function is known to be a stub + Stub bool // The function is known to never return (panics notwithstanding) Infinite bool // Variable ranges @@ -90,6 +92,7 @@ func (d *Descriptions) Get(fn *ssa.Function) Description { { fd.result = stdlibDescs[fn.RelString(nil)] fd.result.Pure = fd.result.Pure || d.IsPure(fn) + fd.result.Stub = fd.result.Stub || d.IsStub(fn) fd.result.Infinite = fd.result.Infinite || !terminates(fn) fd.result.Ranges = vrp.BuildGraph(fn).Solve() fd.result.Loops = findLoops(fn) diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/pure.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/pure.go index 5b99c479..d1c4d036 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/pure.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/functions/pure.go @@ -5,9 +5,41 @@ import ( "go/types" "honnef.co/go/tools/callgraph" + "honnef.co/go/tools/lint" "honnef.co/go/tools/ssa" ) +// IsStub reports whether a function is a stub. A function is +// considered a stub if it has no instructions or exactly one +// instruction, which must be either returning only constant values or +// a panic. +func (d *Descriptions) IsStub(fn *ssa.Function) bool { + if len(fn.Blocks) == 0 { + return true + } + if len(fn.Blocks) > 1 { + return false + } + instrs := lint.FilterDebug(fn.Blocks[0].Instrs) + if len(instrs) != 1 { + return false + } + + switch instrs[0].(type) { + case *ssa.Return: + // Since this is the only instruction, the return value must + // be a constant. We consider all constants as stubs, not just + // the zero value. This does not, unfortunately, cover zero + // initialised structs, as these cause additional + // instructions. + return true + case *ssa.Panic: + return true + default: + return false + } +} + func (d *Descriptions) IsPure(fn *ssa.Function) bool { if fn.Signature.Results().Len() == 0 { // A function with no return values is empty or is doing some diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/gcsizes/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/gcsizes/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/gcsizes/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/internal/sharedcheck/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/internal/sharedcheck/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/internal/sharedcheck/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lint.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lint.go index db1f6cdd..75a5198f 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lint.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lint.go @@ -11,6 +11,7 @@ import ( "bytes" "fmt" "go/ast" + "go/build" "go/constant" "go/printer" "go/token" @@ -20,6 +21,7 @@ import ( "sort" "strings" "sync" + "unicode" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/go/loader" @@ -30,15 +32,85 @@ import ( type Job struct { Program *Program + checker string check string problems []Problem } -type Ignore struct { +type Ignore interface { + Match(p Problem) bool +} + +type LineIgnore struct { + File string + Line int + Checks []string + matched bool + pos token.Pos +} + +func (li *LineIgnore) Match(p Problem) bool { + if p.Position.Filename != li.File || p.Position.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.Position.Filename != fi.File { + return false + } + for _, c := range fi.Checks { + if m, _ := filepath.Match(c, p.Check); m { + return true + } + } + return false +} + +type GlobIgnore struct { Pattern string Checks []string } +func (gi *GlobIgnore) Match(p Problem) bool { + if gi.Pattern != "*" { + pkgpath := p.Package.Path() + if strings.HasSuffix(pkgpath, "_test") { + pkgpath = pkgpath[:len(pkgpath)-len("_test")] + } + name := filepath.Join(pkgpath, filepath.Base(p.Position.Filename)) + if m, _ := filepath.Match(gi.Pattern, name); !m { + return false + } + } + for _, c := range gi.Checks { + if m, _ := filepath.Match(c, p.Check); m { + return true + } + } + return false +} + type Program struct { SSA *ssa.Program Prog *loader.Program @@ -58,51 +130,70 @@ type Func func(*Job) // Problem represents a problem in some source code. type Problem struct { - Position token.Pos // position in source file - Text string // the prose that describes the problem + pos token.Pos + Position token.Position // position in source file + Text string // the prose that describes the problem + Check string + Checker string + Package *types.Package + Ignored bool } func (p *Problem) String() string { - return p.Text + if p.Check == "" { + return p.Text + } + return fmt.Sprintf("%s (%s)", p.Text, p.Check) } type Checker interface { + Name() string + Prefix() string Init(*Program) Funcs() map[string]Func } // A Linter lints Go source code. type Linter struct { - Checker Checker - Ignores []Ignore - GoVersion int + Checker Checker + Ignores []Ignore + GoVersion int + ReturnIgnored bool + + automaticIgnores []Ignore } -func (l *Linter) ignore(j *Job, p Problem) bool { - tf := j.Program.SSA.Fset.File(p.Position) - f := j.Program.tokenFileMap[tf] - pkg := j.Program.astFileMap[f].Pkg - - for _, ig := range l.Ignores { - pkgpath := pkg.Path() - if strings.HasSuffix(pkgpath, "_test") { - pkgpath = pkgpath[:len(pkgpath)-len("_test")] - } - name := filepath.Join(pkgpath, filepath.Base(tf.Name())) - if m, _ := filepath.Match(ig.Pattern, name); !m { - continue - } - for _, c := range ig.Checks { - if m, _ := filepath.Match(c, j.check); m { - return true - } +func (l *Linter) ignore(p Problem) bool { + ignored := false + for _, ig := range l.automaticIgnores { + // We cannot short-circuit these, as we want to record, for + // each ignore, whether it matched or not. + if ig.Match(p) { + ignored = true } } + if ignored { + // no need to execute other ignores if we've already had a + // match. + return true + } + for _, ig := range l.Ignores { + // We can short-circuit here, as we aren't tracking any + // information. + if ig.Match(p) { + return true + } + } + return false } +func (prog *Program) File(node Positioner) *ast.File { + return prog.tokenFileMap[prog.SSA.Fset.File(node.Pos())] +} + func (j *Job) File(node Positioner) *ast.File { - return j.Program.tokenFileMap[j.Program.SSA.Fset.File(node.Pos())] + return j.Program.File(node) } // TODO(dh): switch to sort.Slice when Go 1.9 lands. @@ -116,7 +207,7 @@ func (ps byPosition) Len() int { } func (ps byPosition) Less(i int, j int) bool { - pi, pj := ps.fset.Position(ps.ps[i].Position), ps.fset.Position(ps.ps[j].Position) + pi, pj := ps.ps[i].Position, ps.ps[j].Position if pi.Filename != pj.Filename { return pi.Filename < pj.Filename @@ -135,16 +226,40 @@ func (ps byPosition) Swap(i int, j int) { ps.ps[i], ps.ps[j] = ps.ps[j], ps.ps[i] } -func (l *Linter) Lint(lprog *loader.Program) []Problem { +func parseDirective(s string) (cmd string, args []string) { + if !strings.HasPrefix(s, "//lint:") { + return "", nil + } + s = strings.TrimPrefix(s, "//lint:") + fields := strings.Split(s, " ") + return fields[0], fields[1:] +} + +func (l *Linter) Lint(lprog *loader.Program, conf *loader.Config) []Problem { ssaprog := ssautil.CreateProgram(lprog, ssa.GlobalDebug) ssaprog.Build() pkgMap := map[*ssa.Package]*Pkg{} var pkgs []*Pkg for _, pkginfo := range lprog.InitialPackages() { ssapkg := ssaprog.Package(pkginfo.Pkg) + var bp *build.Package + if len(pkginfo.Files) != 0 { + path := lprog.Fset.Position(pkginfo.Files[0].Pos()).Filename + dir := filepath.Dir(path) + var err error + ctx := conf.Build + if ctx == nil { + ctx = &build.Default + } + bp, err = ctx.ImportDir(dir, 0) + if err != nil { + // shouldn't happen + } + } pkg := &Pkg{ - Package: ssapkg, - Info: pkginfo, + Package: ssapkg, + Info: pkginfo, + BuildPkg: bp, } pkgMap[ssapkg] = pkg pkgs = append(pkgs, pkg) @@ -158,6 +273,7 @@ func (l *Linter) Lint(lprog *loader.Program) []Problem { tokenFileMap: map[*token.File]*ast.File{}, astFileMap: map[*ast.File]*Pkg{}, } + initial := map[*types.Package]struct{}{} for _, pkg := range pkgs { initial[pkg.Info.Pkg] = struct{}{} @@ -176,9 +292,69 @@ func (l *Linter) Lint(lprog *loader.Program) []Problem { ssapkg := ssaprog.Package(pkg.Info.Pkg) for _, f := range pkg.Info.Files { + prog.astFileMap[f] = pkgMap[ssapkg] + } + } + + for _, pkginfo := range lprog.AllPackages { + for _, f := range pkginfo.Files { tf := lprog.Fset.File(f.Pos()) prog.tokenFileMap[tf] = f - prog.astFileMap[f] = pkgMap[ssapkg] + } + } + + var out []Problem + l.automaticIgnores = nil + for _, pkginfo := range lprog.InitialPackages() { + for _, f := range pkginfo.Files { + cm := ast.NewCommentMap(lprog.Fset, f, f.Comments) + for node, cgs := range cm { + for _, cg := range cgs { + for _, c := range cg.List { + if !strings.HasPrefix(c.Text, "//lint:") { + continue + } + cmd, args := parseDirective(c.Text) + switch cmd { + case "ignore", "file-ignore": + if len(args) < 2 { + // FIXME(dh): this causes duplicated warnings when using megacheck + p := Problem{ + pos: c.Pos(), + Position: prog.DisplayPosition(c.Pos()), + Text: "malformed linter directive; missing the required reason field?", + Check: "", + Checker: l.Checker.Name(), + Package: nil, + } + out = append(out, p) + continue + } + default: + // unknown directive, ignore + continue + } + checks := strings.Split(args[0], ",") + pos := prog.DisplayPosition(node.Pos()) + var ig Ignore + switch cmd { + case "ignore": + ig = &LineIgnore{ + File: pos.Filename, + Line: pos.Line, + Checks: checks, + pos: c.Pos(), + } + case "file-ignore": + ig = &FileIgnore{ + File: pos.Filename, + Checks: checks, + } + } + l.automaticIgnores = append(l.automaticIgnores, ig) + } + } + } } } @@ -237,6 +413,7 @@ func (l *Linter) Lint(lprog *loader.Program) []Problem { for _, k := range keys { j := &Job{ Program: prog, + checker: l.Checker.Name(), check: k, } jobs = append(jobs, j) @@ -255,15 +432,47 @@ func (l *Linter) Lint(lprog *loader.Program) []Problem { } wg.Wait() - var out []Problem for _, j := range jobs { for _, p := range j.problems { - if !l.ignore(j, p) { + p.Ignored = l.ignore(p) + if l.ReturnIgnored || !p.Ignored { out = append(out, p) } } } + for _, ig := range l.automaticIgnores { + ig, ok := ig.(*LineIgnore) + if !ok { + continue + } + if ig.matched { + continue + } + for _, c := range ig.Checks { + idx := strings.IndexFunc(c, func(r rune) bool { + return unicode.IsNumber(r) + }) + if idx == -1 { + // malformed check name, backing out + continue + } + if c[:idx] != l.Checker.Prefix() { + // not for this checker + continue + } + p := Problem{ + pos: ig.pos, + Position: prog.DisplayPosition(ig.pos), + Text: "this linter directive didn't match anything; should it be removed?", + Check: "", + Checker: l.Checker.Name(), + Package: nil, + } + out = append(out, p) + } + } + sort.Sort(byPosition{lprog.Fset, out}) return out } @@ -271,7 +480,8 @@ func (l *Linter) Lint(lprog *loader.Program) []Problem { // Pkg represents a package being linted. type Pkg struct { *ssa.Package - Info *loader.PackageInfo + Info *loader.PackageInfo + BuildPkg *build.Package } type packager interface { @@ -309,10 +519,55 @@ type Positioner interface { Pos() token.Pos } +func (prog *Program) DisplayPosition(p token.Pos) token.Position { + // The //line compiler directive can be used to change the file + // name and line numbers associated with code. This can, for + // example, be used by code generation tools. The most prominent + // example is 'go tool cgo', which uses //line directives to refer + // back to the original source code. + // + // In the context of our linters, we need to treat these + // directives differently depending on context. For cgo files, we + // want to honour the directives, so that line numbers are + // adjusted correctly. For all other files, we want to ignore the + // directives, so that problems are reported at their actual + // position and not, for example, a yacc grammar file. This also + // affects the ignore mechanism, since it operates on the position + // information stored within problems. With this implementation, a + // user will ignore foo.go, not foo.y + + pkg := prog.astFileMap[prog.tokenFileMap[prog.Prog.Fset.File(p)]] + bp := pkg.BuildPkg + adjPos := prog.Prog.Fset.Position(p) + if bp == nil { + // couldn't find the package for some reason (deleted? faulty + // file system?) + return adjPos + } + base := filepath.Base(adjPos.Filename) + for _, f := range bp.CgoFiles { + if f == base { + // this is a cgo file, use the adjusted position + return adjPos + } + } + // not a cgo file, ignore //line directives + return prog.Prog.Fset.PositionFor(p, false) +} + func (j *Job) Errorf(n Positioner, format string, args ...interface{}) *Problem { + tf := j.Program.SSA.Fset.File(n.Pos()) + f := j.Program.tokenFileMap[tf] + pkg := j.Program.astFileMap[f].Pkg + + pos := j.Program.DisplayPosition(n.Pos()) problem := Problem{ - Position: n.Pos(), - Text: fmt.Sprintf(format, args...) + fmt.Sprintf(" (%s)", j.check), + pos: n.Pos(), + Position: pos, + Text: fmt.Sprintf(format, args...), + Check: j.check, + Checker: j.checker, + Package: pkg, } j.problems = append(j.problems, problem) return &j.problems[len(j.problems)-1] @@ -422,6 +677,31 @@ func IsGenerated(f *ast.File) bool { return false } +func Preamble(f *ast.File) string { + cutoff := f.Package + if f.Doc != nil { + cutoff = f.Doc.Pos() + } + var out []string + for _, cmt := range f.Comments { + if cmt.Pos() >= cutoff { + break + } + out = append(out, cmt.Text()) + } + return strings.Join(out, "\n") +} + +func IsPointerLike(T types.Type) bool { + switch T := T.Underlying().(type) { + case *types.Interface, *types.Chan, *types.Map, *types.Pointer: + return true + case *types.Basic: + return T.Kind() == types.UnsafePointer + } + return false +} + func (j *Job) IsGoVersion(minor int) bool { return j.Program.GoVersion >= minor } diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lintutil/util.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lintutil/util.go index 53b9f83a..0bb14266 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lintutil/util.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/lintutil/util.go @@ -8,23 +8,70 @@ package lintutil // import "honnef.co/go/tools/lint/lintutil" import ( + "encoding/json" "errors" "flag" "fmt" "go/build" "go/parser" "go/token" + "go/types" + "io" "os" "path/filepath" "strconv" "strings" "honnef.co/go/tools/lint" + "honnef.co/go/tools/version" "github.com/kisielk/gotool" "golang.org/x/tools/go/loader" ) +type OutputFormatter interface { + Format(p lint.Problem) +} + +type TextOutput struct { + w io.Writer +} + +func (o TextOutput) Format(p lint.Problem) { + fmt.Fprintf(o.w, "%v: %s\n", relativePositionString(p.Position), p.String()) +} + +type JSONOutput struct { + w io.Writer +} + +func (o JSONOutput) Format(p lint.Problem) { + type location struct { + File string `json:"file"` + Line int `json:"line"` + Column int `json:"column"` + } + jp := struct { + Checker string `json:"checker"` + Code string `json:"code"` + Severity string `json:"severity,omitempty"` + Location location `json:"location"` + Message string `json:"message"` + Ignored bool `json:"ignored"` + }{ + p.Checker, + p.Check, + "", // TODO(dh): support severity + location{ + p.Position.Filename, + p.Position.Line, + p.Position.Column, + }, + p.Text, + p.Ignored, + } + _ = json.NewEncoder(o.w).Encode(jp) +} func usage(name string, flags *flag.FlagSet) func() { return func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", name) @@ -38,13 +85,14 @@ func usage(name string, flags *flag.FlagSet) func() { } type runner struct { - checker lint.Checker - tags []string - ignores []lint.Ignore - version int + checker lint.Checker + tags []string + ignores []lint.Ignore + version int + returnIgnored bool } -func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err error) { +func resolveRelative(importPaths []string, tags []string) (goFiles bool, err error) { if len(importPaths) == 0 { return false, nil } @@ -57,7 +105,7 @@ func (runner runner) resolveRelative(importPaths []string) (goFiles bool, err er return false, err } ctx := build.Default - ctx.BuildTags = runner.tags + ctx.BuildTags = tags for i, path := range importPaths { bpkg, err := ctx.Import(path, wd, build.FindOnly) if err != nil { @@ -80,7 +128,7 @@ func parseIgnore(s string) ([]lint.Ignore, error) { } path := p[0] checks := strings.Split(p[1], ",") - out = append(out, lint.Ignore{Pattern: path, Checks: checks}) + out = append(out, &lint.GlobIgnore{Pattern: path, Checks: checks}) } return out, nil } @@ -117,6 +165,9 @@ func FlagSet(name string) *flag.FlagSet { flags.String("tags", "", "List of `build tags`") flags.String("ignore", "", "Space separated list of checks to ignore, in the following format: 'import/path/file.go:Check1,Check2,...' Both the import path and file name sections support globbing, e.g. 'os/exec/*_test.go'") 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 'text' and 'json')") tags := build.Default.ReleaseTags v := tags[len(tags)-1][2:] @@ -129,67 +180,105 @@ func FlagSet(name string) *flag.FlagSet { return flags } -func ProcessFlagSet(c lint.Checker, fs *flag.FlagSet) { +type CheckerConfig struct { + Checker lint.Checker + ExitNonZero bool +} + +func ProcessFlagSet(confs []CheckerConfig, fs *flag.FlagSet) { tags := fs.Lookup("tags").Value.(flag.Getter).Get().(string) ignore := fs.Lookup("ignore").Value.(flag.Getter).Get().(string) tests := fs.Lookup("tests").Value.(flag.Getter).Get().(bool) - version := fs.Lookup("go").Value.(flag.Getter).Get().(int) + goVersion := fs.Lookup("go").Value.(flag.Getter).Get().(int) + format := 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) - ps, lprog, err := Lint(c, fs.Args(), &Options{ - Tags: strings.Fields(tags), - LintTests: tests, - Ignores: ignore, - GoVersion: version, + if printVersion { + version.Print() + os.Exit(0) + } + + var cs []lint.Checker + for _, conf := range confs { + cs = append(cs, conf.Checker) + } + pss, err := Lint(cs, fs.Args(), &Options{ + Tags: strings.Fields(tags), + LintTests: tests, + Ignores: ignore, + GoVersion: goVersion, + ReturnIgnored: showIgnored, }) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } - unclean := false - for _, p := range ps { - unclean = true - pos := lprog.Fset.Position(p.Position) - fmt.Printf("%v: %s\n", relativePositionString(pos), p.Text) + + var ps []lint.Problem + for _, p := range pss { + ps = append(ps, p...) } - if unclean { - os.Exit(1) + + var f OutputFormatter + switch format { + case "text": + f = TextOutput{os.Stdout} + case "json": + f = JSONOutput{os.Stdout} + default: + fmt.Fprintf(os.Stderr, "unsupported output format %q\n", format) + os.Exit(2) + } + + for _, p := range ps { + f.Format(p) + } + for i, p := range pss { + if len(p) != 0 && confs[i].ExitNonZero { + os.Exit(1) + } } } type Options struct { - Tags []string - LintTests bool - Ignores string - GoVersion int + Tags []string + LintTests bool + Ignores string + GoVersion int + ReturnIgnored bool } -func Lint(c lint.Checker, pkgs []string, opt *Options) ([]lint.Problem, *loader.Program, error) { - // TODO(dh): Instead of returning the loader.Program, we should - // store token.Position instead of token.Pos in lint.Problem. +func Lint(cs []lint.Checker, pkgs []string, opt *Options) ([][]lint.Problem, error) { if opt == nil { opt = &Options{} } ignores, err := parseIgnore(opt.Ignores) if err != nil { - return nil, nil, err - } - runner := &runner{ - checker: c, - tags: opt.Tags, - ignores: ignores, - version: opt.GoVersion, + return nil, err } paths := gotool.ImportPaths(pkgs) - goFiles, err := runner.resolveRelative(paths) + goFiles, err := resolveRelative(paths, opt.Tags) if err != nil { - return nil, nil, err + return nil, err } ctx := build.Default - ctx.BuildTags = runner.tags + ctx.BuildTags = opt.Tags + hadError := false conf := &loader.Config{ Build: &ctx, ParserMode: parser.ParseComments, ImportPkgs: map[string]bool{}, + TypeChecker: types.Config{ + Error: func(err error) { + // Only print the first error found + if hadError { + return + } + hadError = true + fmt.Fprintln(os.Stderr, err) + }, + }, } if goFiles { conf.CreateFromFilenames("adhoc", paths...) @@ -200,9 +289,21 @@ func Lint(c lint.Checker, pkgs []string, opt *Options) ([]lint.Problem, *loader. } lprog, err := conf.Load() if err != nil { - return nil, nil, err + return nil, err } - return runner.lint(lprog), lprog, nil + + var problems [][]lint.Problem + for _, c := range cs { + runner := &runner{ + checker: c, + tags: opt.Tags, + ignores: ignores, + version: opt.GoVersion, + returnIgnored: opt.ReturnIgnored, + } + problems = append(problems, runner.lint(lprog, conf)) + } + return problems, nil } func shortPath(path string) string { @@ -230,18 +331,19 @@ func relativePositionString(pos token.Position) string { return s } -func ProcessArgs(name string, c lint.Checker, args []string) { +func ProcessArgs(name string, cs []CheckerConfig, args []string) { flags := FlagSet(name) flags.Parse(args) - ProcessFlagSet(c, flags) + ProcessFlagSet(cs, flags) } -func (runner *runner) lint(lprog *loader.Program) []lint.Problem { +func (runner *runner) lint(lprog *loader.Program, conf *loader.Config) []lint.Problem { l := &lint.Linter{ - Checker: runner.checker, - Ignores: runner.ignores, - GoVersion: runner.version, + Checker: runner.checker, + Ignores: runner.ignores, + GoVersion: runner.version, + ReturnIgnored: runner.returnIgnored, } - return l.Lint(lprog) + return l.Lint(lprog, conf) } diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/testutil/util.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/testutil/util.go index 0cea384b..3e223f3c 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/testutil/util.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/lint/testutil/util.go @@ -91,7 +91,7 @@ func TestAll(t *testing.T, c lint.Checker, dir string) { for version, fis := range files { l := &lint.Linter{Checker: c, GoVersion: version} - res := l.Lint(lprog) + res := l.Lint(lprog, conf) for _, fi := range fis { name := fi.Name() src := sources[name] @@ -101,8 +101,7 @@ func TestAll(t *testing.T, c lint.Checker, dir string) { for _, in := range ins { ok := false for i, p := range res { - pos := lprog.Fset.Position(p.Position) - if pos.Line != in.Line || filepath.Base(pos.Filename) != name { + if p.Position.Line != in.Line || filepath.Base(p.Position.Filename) != name { continue } if in.Match.MatchString(p.Text) { @@ -121,11 +120,10 @@ func TestAll(t *testing.T, c lint.Checker, dir string) { } } for _, p := range res { - pos := lprog.Fset.Position(p.Position) - name := filepath.Base(pos.Filename) + name := filepath.Base(p.Position.Filename) for _, fi := range fis { if name == fi.Name() { - t.Errorf("Unexpected problem at %s: %v", pos, p.Text) + t.Errorf("Unexpected problem at %s: %v", p.Position, p.Text) break } } @@ -149,7 +147,7 @@ func parseInstructions(t *testing.T, filename string, src []byte) []instruction } var ins []instruction for _, cg := range f.Comments { - ln := fset.Position(cg.Pos()).Line + ln := fset.PositionFor(cg.Pos(), false).Line raw := cg.Text() for _, line := range strings.Split(raw, "\n") { if line == "" || strings.HasPrefix(line, "#") { diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/simple/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/simple/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/simple/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/simple/lint.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/simple/lint.go index bff62341..47ee6909 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/simple/lint.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/simple/lint.go @@ -29,6 +29,9 @@ func NewChecker() *Checker { } } +func (*Checker) Name() string { return "gosimple" } +func (*Checker) Prefix() string { return "S" } + func (c *Checker) Init(prog *lint.Program) { c.nodeFns = lint.NodeFns(prog.Packages) } @@ -61,7 +64,7 @@ func (c *Checker) Funcs() map[string]lint.Func { "S1023": c.LintRedundantBreak, "S1024": c.LintTimeUntil, "S1025": c.LintRedundantSprintf, - "S1026": c.LintStringCopy, + "S1026": nil, "S1027": nil, "S1028": c.LintErrorsNewSprintf, "S1029": c.LintRangeStringRunes, @@ -1022,7 +1025,9 @@ func (c *Checker) LintUnnecessaryBlank(j *lint.Job) { fn := func(node ast.Node) bool { fn1(node) fn2(node) - fn3(node) + if j.IsGoVersion(4) { + fn3(node) + } return true } for _, f := range c.filterGenerated(j.Program.Files) { @@ -1702,81 +1707,6 @@ func (c *Checker) LintRedundantSprintf(j *lint.Job) { } } -func (c *Checker) LintStringCopy(j *lint.Job) { - emptyStringLit := func(e ast.Expr) bool { - bl, ok := e.(*ast.BasicLit) - return ok && bl.Value == `""` - } - fn := func(node ast.Node) bool { - switch x := node.(type) { - case *ast.BinaryExpr: // "" + s, s + "" - if x.Op != token.ADD { - break - } - l1 := j.Program.Prog.Fset.Position(x.X.Pos()).Line - l2 := j.Program.Prog.Fset.Position(x.Y.Pos()).Line - if l1 != l2 { - break - } - var want ast.Expr - switch { - case emptyStringLit(x.X): - want = x.Y - case emptyStringLit(x.Y): - want = x.X - default: - return true - } - j.Errorf(x, "should use %s instead of %s", - j.Render(want), j.Render(x)) - case *ast.CallExpr: - if j.IsCallToAST(x, "fmt.Sprint") && len(x.Args) == 1 { - // fmt.Sprint(x) - - argT := j.Program.Info.TypeOf(x.Args[0]) - bt, ok := argT.Underlying().(*types.Basic) - if !ok || bt.Kind() != types.String { - return true - } - if c.Implements(j, argT, "fmt.Stringer") || c.Implements(j, argT, "error") { - return true - } - - j.Errorf(x, "should use %s instead of %s", j.Render(x.Args[0]), j.Render(x)) - return true - } - - // string([]byte(s)) - bt, ok := j.Program.Info.TypeOf(x.Fun).(*types.Basic) - if !ok || bt.Kind() != types.String { - break - } - nested, ok := x.Args[0].(*ast.CallExpr) - if !ok { - break - } - st, ok := j.Program.Info.TypeOf(nested.Fun).(*types.Slice) - if !ok { - break - } - et, ok := st.Elem().(*types.Basic) - if !ok || et.Kind() != types.Byte { - break - } - xt, ok := j.Program.Info.TypeOf(nested.Args[0]).(*types.Basic) - if !ok || xt.Kind() != types.String { - break - } - j.Errorf(x, "should use %s instead of %s", - j.Render(nested.Args[0]), j.Render(x)) - } - return true - } - for _, f := range c.filterGenerated(j.Program.Files) { - ast.Inspect(f, fn) - } -} - func (c *Checker) LintErrorsNewSprintf(j *lint.Job) { fn := func(node ast.Node) bool { if !j.IsCallToAST(node, "errors.New") { diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/ssa/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/ssa/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/ssa/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/buildtag.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/buildtag.go new file mode 100644 index 00000000..27c31c09 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/buildtag.go @@ -0,0 +1,21 @@ +package staticcheck + +import ( + "go/ast" + "strings" + + "honnef.co/go/tools/lint" +) + +func buildTags(f *ast.File) [][]string { + var out [][]string + for _, line := range strings.Split(lint.Preamble(f), "\n") { + if !strings.HasPrefix(line, "+build ") { + continue + } + line = strings.TrimSpace(strings.TrimPrefix(line, "+build ")) + fields := strings.Fields(line) + out = append(out, fields) + } + return out +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/lint.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/lint.go index 4ab90386..1694e40d 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/lint.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/staticcheck/lint.go @@ -4,20 +4,20 @@ package staticcheck // import "honnef.co/go/tools/staticcheck" import ( "fmt" "go/ast" - "go/build" "go/constant" "go/token" "go/types" htmltemplate "html/template" "net/http" "regexp" + "sort" "strconv" "strings" "sync" texttemplate "text/template" + "honnef.co/go/tools/deprecated" "honnef.co/go/tools/functions" - "honnef.co/go/tools/gcsizes" "honnef.co/go/tools/internal/sharedcheck" "honnef.co/go/tools/lint" "honnef.co/go/tools/ssa" @@ -111,14 +111,12 @@ var ( }, } - checkSyncPoolSizeRules = map[string]CallCheck{ + checkSyncPoolValueRules = map[string]CallCheck{ "(*sync.Pool).Put": func(call *Call) { - // TODO(dh): allow users to pass in a custom build environment - sizes := gcsizes.ForArch(build.Default.GOARCH) arg := call.Args[0] typ := arg.Value.Value.Type() - if !types.IsInterface(typ) && sizes.Sizeof(typ) > sizes.WordSize { - arg.Invalid("argument should be one word large or less to avoid allocations") + if !lint.IsPointerLike(typ) { + arg.Invalid("argument should be pointer-like to avoid allocations") } }, } @@ -209,6 +207,9 @@ func NewChecker() *Checker { return &Checker{} } +func (*Checker) Name() string { return "staticcheck" } +func (*Checker) Prefix() string { return "SA" } + func (c *Checker) Funcs() map[string]lint.Func { return map[string]lint.Func{ "SA1000": c.callChecker(checkRegexpRules), @@ -265,6 +266,7 @@ func (c *Checker) Funcs() map[string]lint.Func { "SA4016": c.CheckSillyBitwiseOps, "SA4017": c.CheckPureFunctions, "SA4018": c.CheckSelfAssignment, + "SA4019": c.CheckDuplicateBuildConstraints, "SA5000": c.CheckNilMaps, "SA5001": c.CheckEarlyDefer, @@ -277,7 +279,7 @@ func (c *Checker) Funcs() map[string]lint.Func { "SA6000": c.callChecker(checkRegexpMatchLoopRules), "SA6001": c.CheckMapBytesKey, - "SA6002": c.callChecker(checkSyncPoolSizeRules), + "SA6002": c.callChecker(checkSyncPoolValueRules), "SA6003": c.CheckRangeStringRunes, "SA6004": nil, @@ -301,36 +303,62 @@ func (c *Checker) filterGenerated(files []*ast.File) []*ast.File { return out } -func (c *Checker) Init(prog *lint.Program) { - c.funcDescs = functions.NewDescriptions(prog.SSA) - c.deprecatedObjs = map[types.Object]string{} - c.nodeFns = map[ast.Node]*ssa.Function{} - - for _, fn := range prog.AllFunctions { - if fn.Blocks != nil { - applyStdlibKnowledge(fn) - ssa.OptimizeBlocks(fn) - } +func (c *Checker) deprecateObject(m map[types.Object]string, prog *lint.Program, obj types.Object) { + if obj.Pkg() == nil { + return } - c.nodeFns = lint.NodeFns(prog.Packages) + f := prog.File(obj) + if f == nil { + return + } + msg := c.deprecationMessage(f, prog.Prog.Fset, obj) + if msg != "" { + m[obj] = msg + } +} - deprecated := []map[types.Object]string{} +func (c *Checker) Init(prog *lint.Program) { wg := &sync.WaitGroup{} - for _, pkginfo := range prog.Prog.AllPackages { - pkginfo := pkginfo - scope := pkginfo.Pkg.Scope() - names := scope.Names() - wg.Add(1) + wg.Add(3) + go func() { + c.funcDescs = functions.NewDescriptions(prog.SSA) + for _, fn := range prog.AllFunctions { + if fn.Blocks != nil { + applyStdlibKnowledge(fn) + ssa.OptimizeBlocks(fn) + } + } + wg.Done() + }() - m := map[types.Object]string{} - deprecated = append(deprecated, m) - go func(m map[types.Object]string) { - for _, name := range names { - obj := scope.Lookup(name) - msg := c.deprecationMessage(pkginfo.Files, prog.SSA.Fset, obj) - if msg != "" { - m[obj] = msg + go func() { + c.nodeFns = lint.NodeFns(prog.Packages) + wg.Done() + }() + + go func() { + c.deprecatedObjs = map[types.Object]string{} + for _, ssapkg := range prog.SSA.AllPackages() { + ssapkg := ssapkg + for _, member := range ssapkg.Members { + obj := member.Object() + if obj == nil { + continue + } + c.deprecateObject(c.deprecatedObjs, prog, obj) + if typ, ok := obj.Type().(*types.Named); ok { + for i := 0; i < typ.NumMethods(); i++ { + meth := typ.Method(i) + c.deprecateObject(c.deprecatedObjs, prog, meth) + } + + if iface, ok := typ.Underlying().(*types.Interface); ok { + for i := 0; i < iface.NumExplicitMethods(); i++ { + meth := iface.ExplicitMethod(i) + c.deprecateObject(c.deprecatedObjs, prog, meth) + } + } } if typ, ok := obj.Type().Underlying().(*types.Struct); ok { n := typ.NumFields() @@ -338,51 +366,20 @@ func (c *Checker) Init(prog *lint.Program) { // FIXME(dh): This code will not find deprecated // fields in anonymous structs. field := typ.Field(i) - msg := c.deprecationMessage(pkginfo.Files, prog.SSA.Fset, field) - if msg != "" { - m[field] = msg - } + c.deprecateObject(c.deprecatedObjs, prog, field) } } } - wg.Done() - }(m) - } + } + wg.Done() + }() + wg.Wait() - for _, m := range deprecated { - for k, v := range m { - c.deprecatedObjs[k] = v - } - } } -// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos) -func tokenFileContainsPos(f *token.File, pos token.Pos) bool { - p := int(pos) - base := f.Base() - return base <= p && p < base+f.Size() -} - -func pathEnclosingInterval(files []*ast.File, fset *token.FileSet, start, end token.Pos) (path []ast.Node, exact bool) { - for _, f := range files { - if f.Pos() == token.NoPos { - // This can happen if the parser saw - // too many errors and bailed out. - // (Use parser.AllErrors to prevent that.) - continue - } - if !tokenFileContainsPos(fset.File(f.Pos()), start) { - continue - } - if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil { - return path, exact - } - } - return nil, false -} - -func (c *Checker) deprecationMessage(files []*ast.File, fset *token.FileSet, obj types.Object) (message string) { - path, _ := pathEnclosingInterval(files, fset, obj.Pos(), obj.Pos()) +func (c *Checker) deprecationMessage(file *ast.File, fset *token.FileSet, obj types.Object) (message string) { + pos := obj.Pos() + path, _ := astutil.PathEnclosingInterval(file, pos, pos) if len(path) <= 2 { return "" } @@ -2065,7 +2062,7 @@ func (c *Checker) CheckCyclicFinalizer(j *lint.Job) { } for _, b := range mc.Bindings { if b == v { - pos := j.Program.SSA.Fset.Position(mc.Fn.Pos()) + pos := j.Program.DisplayPosition(mc.Fn.Pos()) j.Errorf(edge.Site, "the finalizer closes over the object, preventing the finalizer from ever running (at %s)", pos) } } @@ -2166,6 +2163,11 @@ func (c *Checker) CheckInfiniteRecursion(j *lint.Job) { if edge.Callee != node { continue } + if _, ok := edge.Site.(*ssa.Go); ok { + // Recursively spawning goroutines doesn't consume + // stack space infinitely, so don't flag it. + continue + } block := edge.Site.Block() canReturn := false @@ -2437,7 +2439,7 @@ fnLoop: if callee == nil { continue } - if c.funcDescs.Get(callee).Pure { + if c.funcDescs.Get(callee).Pure && !c.funcDescs.Get(callee).Stub { j.Errorf(ins, "%s is a pure function but its return value is ignored", callee.Name()) continue } @@ -2446,22 +2448,6 @@ fnLoop: } } -func enclosingFunction(j *lint.Job, node ast.Node) *ast.FuncDecl { - f := j.File(node) - path, _ := astutil.PathEnclosingInterval(f, node.Pos(), node.Pos()) - for _, e := range path { - fn, ok := e.(*ast.FuncDecl) - if !ok { - continue - } - if fn.Name == nil { - continue - } - return fn - } - return nil -} - func (c *Checker) isDeprecated(j *lint.Job, ident *ast.Ident) (bool, string) { obj := j.Program.Info.ObjectOf(ident) if obj.Pkg() == nil { @@ -2471,19 +2457,34 @@ func (c *Checker) isDeprecated(j *lint.Job, ident *ast.Ident) (bool, string) { return alt != "", alt } +func selectorName(j *lint.Job, expr *ast.SelectorExpr) string { + sel := j.Program.Info.Selections[expr] + if sel == nil { + if x, ok := expr.X.(*ast.Ident); ok { + return fmt.Sprintf("%s.%s", x.Name, expr.Sel.Name) + } + panic(fmt.Sprintf("unsupported selector: %v", expr)) + } + return fmt.Sprintf("(%s).%s", sel.Recv(), sel.Obj().Name()) +} + +func (c *Checker) enclosingFunc(sel *ast.SelectorExpr) *ssa.Function { + fn := c.nodeFns[sel] + if fn == nil { + return nil + } + for fn.Parent() != nil { + fn = fn.Parent() + } + return fn +} + func (c *Checker) CheckDeprecated(j *lint.Job) { fn := func(node ast.Node) bool { sel, ok := node.(*ast.SelectorExpr) if !ok { return true } - if fn := enclosingFunction(j, sel); fn != nil { - if ok, _ := c.isDeprecated(j, fn.Name); ok { - // functions that are deprecated may use deprecated - // symbols - return true - } - } obj := j.Program.Info.ObjectOf(sel.Sel) if obj.Pkg() == nil { @@ -2495,6 +2496,24 @@ func (c *Checker) CheckDeprecated(j *lint.Job) { return true } if ok, alt := c.isDeprecated(j, sel.Sel); ok { + // Look for the first available alternative, not the first + // version something was deprecated in. If a function was + // deprecated in Go 1.6, an alternative has been available + // already in 1.0, and we're targetting 1.2, it still + // makes sense to use the alternative from 1.0, to be + // future-proof. + minVersion := deprecated.Stdlib[selectorName(j, sel)].AlternativeAvailableSince + if !j.IsGoVersion(minVersion) { + return true + } + + if fn := c.enclosingFunc(sel); fn != nil { + if _, ok := c.deprecatedObjs[fn.Object()]; ok { + // functions that are deprecated may use deprecated + // symbols + return true + } + } j.Errorf(sel, "%s is deprecated: %s", j.Render(sel), alt) return true } @@ -2784,3 +2803,39 @@ func (c *Checker) CheckSelfAssignment(j *lint.Job) { ast.Inspect(f, fn) } } + +func buildTagsIdentical(s1, s2 []string) bool { + if len(s1) != len(s2) { + return false + } + s1s := make([]string, len(s1)) + copy(s1s, s1) + sort.Strings(s1s) + s2s := make([]string, len(s2)) + copy(s2s, s2) + sort.Strings(s2s) + for i, s := range s1s { + if s != s2s[i] { + return false + } + } + return true +} + +func (c *Checker) CheckDuplicateBuildConstraints(job *lint.Job) { + for _, f := range c.filterGenerated(job.Program.Files) { + constraints := buildTags(f) + for i, constraint1 := range constraints { + for j, constraint2 := range constraints { + if i >= j { + continue + } + if buildTagsIdentical(constraint1, constraint2) { + job.Errorf(f, "identical build constraints %q and %q", + strings.Join(constraint1, " "), + strings.Join(constraint2, " ")) + } + } + } + } +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/structlayout/layout.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/structlayout/layout.go new file mode 100644 index 00000000..04652f8b --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/structlayout/layout.go @@ -0,0 +1,22 @@ +package structlayout + +import "fmt" + +type Field struct { + Name string `json:"name"` + Type string `json:"type"` + Start int64 `json:"start"` + End int64 `json:"end"` + Size int64 `json:"size"` + Align int64 `json:"align"` + IsPadding bool `json:"is_padding"` +} + +func (f Field) String() string { + if f.IsPadding { + return fmt.Sprintf("%s: %d-%d (size %d, align %d)", + "padding", f.Start, f.End, f.Size, f.Align) + } + return fmt.Sprintf("%s %s: %d-%d (size %d, align %d)", + f.Name, f.Type, f.Start, f.End, f.Size, f.Align) +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/unused/LICENSE b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/unused/LICENSE deleted file mode 100644 index dfd03145..00000000 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/unused/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2016 Dominik Honnef - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/unused/unused.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/unused/unused.go index 55d7549e..c0a71e4e 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/unused/unused.go +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/unused/unused.go @@ -26,6 +26,9 @@ type LintChecker struct { c *Checker } +func (*LintChecker) Name() string { return "unused" } +func (*LintChecker) Prefix() string { return "U" } + func (l *LintChecker) Init(*lint.Program) {} func (l *LintChecker) Funcs() map[string]lint.Func { return map[string]lint.Func{ @@ -275,6 +278,51 @@ func (c *Checker) Check(lprog *loader.Program) []Unused { return unused } +// isNoCopyType reports whether a type represents the NoCopy sentinel +// type. The NoCopy type is a named struct with no fields and exactly +// one method `func Lock()` that is empty. +// +// FIXME(dh): currently we're not checking that the function body is +// empty. +func isNoCopyType(typ types.Type) bool { + st, ok := typ.Underlying().(*types.Struct) + if !ok { + return false + } + if st.NumFields() != 0 { + return false + } + + named, ok := typ.(*types.Named) + if !ok { + return false + } + if named.NumMethods() != 1 { + return false + } + meth := named.Method(0) + if meth.Name() != "Lock" { + return false + } + sig := meth.Type().(*types.Signature) + if sig.Params().Len() != 0 || sig.Results().Len() != 0 { + return false + } + return true +} + +func (c *Checker) useNoCopyFields(typ types.Type) { + if st, ok := typ.Underlying().(*types.Struct); ok { + n := st.NumFields() + for i := 0; i < n; i++ { + field := st.Field(i) + if isNoCopyType(field.Type()) { + c.graph.markUsedBy(field, typ) + } + } + } +} + func (c *Checker) useExportedFields(typ types.Type) { if st, ok := typ.Underlying().(*types.Struct); ok { n := st.NumFields() @@ -485,6 +533,7 @@ func (c *Checker) processTypes(pkg *loader.PackageInfo) { interfaces = append(interfaces, obj) } case *types.Struct: + c.useNoCopyFields(obj) if pkg.Pkg.Name() != "main" && !c.WholeProgram { c.useExportedFields(obj) } diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/version/version.go b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/version/version.go new file mode 100644 index 00000000..5e41bc4f --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/honnef.co/go/tools/version/version.go @@ -0,0 +1,17 @@ +package version + +import ( + "fmt" + "os" + "path/filepath" +) + +const Version = "2017.2" + +func Print() { + if Version == "devel" { + fmt.Printf("%s (no version)\n", filepath.Base(os.Args[0])) + } else { + fmt.Printf("%s %s\n", filepath.Base(os.Args[0]), Version) + } +} diff --git a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/manifest b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/manifest index dad0ba93..cf97bf21 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/_linters/src/manifest +++ b/vendor/src/github.com/alecthomas/gometalinter/_linters/src/manifest @@ -309,120 +309,20 @@ "notests": true }, { - "importpath": "honnef.co/go/tools/callgraph", - "repository": "https://github.com/dominikh/go-tools", + "importpath": "golang.org/x/tools/refactor/importgraph", + "repository": "https://go.googlesource.com/tools", "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", + "revision": "9c477bae194915bfd4bc8c314e90e28b9ec1c831", "branch": "master", - "path": "callgraph", + "path": "/refactor/importgraph", "notests": true }, { - "importpath": "honnef.co/go/tools/cmd/gosimple", + "importpath": "honnef.co/go/tools", "repository": "https://github.com/dominikh/go-tools", "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "/cmd/gosimple", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/cmd/megacheck", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "/cmd/megacheck", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/cmd/staticcheck", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "/cmd/staticcheck", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/cmd/unused", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "/cmd/unused", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/functions", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "functions", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/gcsizes", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "gcsizes", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/internal/sharedcheck", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "/internal/sharedcheck", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/lint", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "lint", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/simple", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "simple", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/ssa", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "ssa", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/staticcheck", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "staticcheck", - "notests": true - }, - { - "importpath": "honnef.co/go/tools/unused", - "repository": "https://github.com/dominikh/go-tools", - "vcs": "git", - "revision": "49f44f893d933fd08cd7d67d65ccefa5d7c23329", - "branch": "master", - "path": "unused", + "revision": "50914165a1ae448f1608c6c325d052313396182e", + "branch": "HEAD", "notests": true }, { @@ -450,4 +350,4 @@ "notests": true } ] -} +} \ No newline at end of file diff --git a/vendor/src/github.com/alecthomas/gometalinter/linters.go b/vendor/src/github.com/alecthomas/gometalinter/linters.go index c1f45a74..c779b8c1 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/linters.go +++ b/vendor/src/github.com/alecthomas/gometalinter/linters.go @@ -235,7 +235,7 @@ var defaultLinters = map[string]LinterConfig{ Command: `gas -fmt=csv`, Pattern: `^(?P.*?\.go),(?P\d+),(?P[^,]+,[^,]+,[^,]+)`, InstallFrom: "github.com/GoASTScanner/gas", - PartitionStrategy: partitionPathsAsDirectories, + PartitionStrategy: partitionPathsAsFiles, defaultEnabled: true, IsFast: true, }, diff --git a/vendor/src/github.com/alecthomas/gometalinter/main.go b/vendor/src/github.com/alecthomas/gometalinter/main.go index 4770d95d..3de9534f 100644 --- a/vendor/src/github.com/alecthomas/gometalinter/main.go +++ b/vendor/src/github.com/alecthomas/gometalinter/main.go @@ -26,7 +26,7 @@ var ( ) func setupFlags(app *kingpin.Application) { - app.Flag("config", "Load JSON configuration from file.").Action(loadConfig).String() + app.Flag("config", "Load JSON configuration from file.").Envar("GOMETALINTER_CONFIG").Action(loadConfig).String() app.Flag("disable", "Disable previously enabled linters.").PlaceHolder("LINTER").Short('D').Action(disableAction).Strings() app.Flag("enable", "Enable previously disabled linters.").PlaceHolder("LINTER").Short('E').Action(enableAction).Strings() app.Flag("linter", "Define a linter.").PlaceHolder("NAME:COMMAND:PATTERN").Action(cliLinterOverrides).StringMap() @@ -156,8 +156,8 @@ func formatLinters() string { if install == "()" { install = "" } - fmt.Fprintf(w, " %s %s\n %s\n %s\n", - linter.Name, install, linter.Command, linter.Pattern) + fmt.Fprintf(w, " %s: %s\n\tcommand: %s\n\tregex: %s\n\tfast: %t\n\tdefault enabled: %t\n\n", + linter.Name, install, linter.Command, linter.Pattern, linter.IsFast, linter.defaultEnabled) } return w.String() } diff --git a/vendor/src/github.com/alecthomas/gometalinter/regressiontests/gas_test.go b/vendor/src/github.com/alecthomas/gometalinter/regressiontests/gas_test.go new file mode 100644 index 00000000..51c07270 --- /dev/null +++ b/vendor/src/github.com/alecthomas/gometalinter/regressiontests/gas_test.go @@ -0,0 +1,37 @@ +package regressiontests + +import ( + "fmt" + "testing" + + "github.com/gotestyourself/gotestyourself/fs" + "github.com/stretchr/testify/assert" +) + +func TestGas(t *testing.T) { + t.Parallel() + dir := fs.NewDir(t, "test-gas", + fs.WithFile("file.go", gasFileErrorUnhandled("root")), + fs.WithDir("sub", + fs.WithFile("file.go", gasFileErrorUnhandled("sub")))) + defer dir.Remove() + expected := Issues{ + {Linter: "gas", Severity: "warning", Path: "file.go", Line: 3, Col: 0, Message: "Errors unhandled.,LOW,HIGH"}, + {Linter: "gas", Severity: "warning", Path: "sub/file.go", Line: 3, Col: 0, Message: "Errors unhandled.,LOW,HIGH"}, + } + actual := RunLinter(t, "gas", dir.Path()) + assert.Equal(t, expected, actual) +} + +func gasFileErrorUnhandled(pkg string) string { + return fmt.Sprintf(`package %s + func badFunction() string { + u, _ := ErrorHandle() + return u + } + + func ErrorHandle() (u string, err error) { + return u + } + `, pkg) +}