From c6dc47bcbd5592223af47c5e1306711dc32de886 Mon Sep 17 00:00:00 2001
From: golangci <dev@golangci.com>
Date: Mon, 7 May 2018 09:48:43 +0300
Subject: [PATCH] support interfacer

---
 Gopkg.lock                                    |  27 +-
 Gopkg.toml                                    |  10 +
 internal/commands/run.go                      |  30 ++
 pkg/enabled_linters.go                        |  34 +-
 pkg/golinters/context.go                      |   2 +
 pkg/golinters/interfacer.go                   |  39 ++
 pkg/golinters/megacheck.go                    |   2 +-
 pkg/golinters/testdata/interfacer.go          |   7 +
 .../go-tools/cmd/megacheck/megacheck.go       |   5 +-
 .../github.com/golangci/go-tools/lint/lint.go |  11 +-
 .../golangci/go-tools/lint/lintutil/util.go   |  15 +-
 vendor/github.com/kisielk/gotool/.travis.yml  |  23 +
 vendor/github.com/kisielk/gotool/LEGAL        |  32 ++
 vendor/github.com/kisielk/gotool/LICENSE      |  20 +
 vendor/github.com/kisielk/gotool/README.md    |   6 +
 vendor/github.com/kisielk/gotool/go.mod       |   1 +
 vendor/github.com/kisielk/gotool/go13.go      |  15 +
 vendor/github.com/kisielk/gotool/go14-15.go   |  15 +
 vendor/github.com/kisielk/gotool/go16-18.go   |  15 +
 .../kisielk/gotool/internal/load/path.go      |  27 +
 .../kisielk/gotool/internal/load/pkg.go       |  25 +
 .../kisielk/gotool/internal/load/search.go    | 354 ++++++++++++++
 vendor/github.com/kisielk/gotool/match.go     |  56 +++
 vendor/github.com/kisielk/gotool/match18.go   | 317 ++++++++++++
 vendor/github.com/kisielk/gotool/tool.go      |  48 ++
 vendor/mvdan.cc/interfacer/LICENSE            |  27 +
 vendor/mvdan.cc/interfacer/check/cache.go     |  50 ++
 vendor/mvdan.cc/interfacer/check/check.go     | 462 ++++++++++++++++++
 vendor/mvdan.cc/interfacer/check/types.go     | 170 +++++++
 vendor/mvdan.cc/lint/.travis.yml              |   7 +
 vendor/mvdan.cc/lint/LICENSE                  |  27 +
 vendor/mvdan.cc/lint/README.md                |  27 +
 vendor/mvdan.cc/lint/lint.go                  |  28 ++
 33 files changed, 1899 insertions(+), 35 deletions(-)
 create mode 100644 pkg/golinters/interfacer.go
 create mode 100644 pkg/golinters/testdata/interfacer.go
 create mode 100644 vendor/github.com/kisielk/gotool/.travis.yml
 create mode 100644 vendor/github.com/kisielk/gotool/LEGAL
 create mode 100644 vendor/github.com/kisielk/gotool/LICENSE
 create mode 100644 vendor/github.com/kisielk/gotool/README.md
 create mode 100644 vendor/github.com/kisielk/gotool/go.mod
 create mode 100644 vendor/github.com/kisielk/gotool/go13.go
 create mode 100644 vendor/github.com/kisielk/gotool/go14-15.go
 create mode 100644 vendor/github.com/kisielk/gotool/go16-18.go
 create mode 100644 vendor/github.com/kisielk/gotool/internal/load/path.go
 create mode 100644 vendor/github.com/kisielk/gotool/internal/load/pkg.go
 create mode 100644 vendor/github.com/kisielk/gotool/internal/load/search.go
 create mode 100644 vendor/github.com/kisielk/gotool/match.go
 create mode 100644 vendor/github.com/kisielk/gotool/match18.go
 create mode 100644 vendor/github.com/kisielk/gotool/tool.go
 create mode 100644 vendor/mvdan.cc/interfacer/LICENSE
 create mode 100644 vendor/mvdan.cc/interfacer/check/cache.go
 create mode 100644 vendor/mvdan.cc/interfacer/check/check.go
 create mode 100644 vendor/mvdan.cc/interfacer/check/types.go
 create mode 100644 vendor/mvdan.cc/lint/.travis.yml
 create mode 100644 vendor/mvdan.cc/lint/LICENSE
 create mode 100644 vendor/mvdan.cc/lint/README.md
 create mode 100644 vendor/mvdan.cc/lint/lint.go

diff --git a/Gopkg.lock b/Gopkg.lock
index 6228d1cc..56932356 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -72,7 +72,7 @@
     "unused",
     "version"
   ]
-  revision = "38c5f4a0efc6bd0efc88bdd3890e5e64e698bdc2"
+  revision = "f557f368b7f3d00a54ed44eb57b9eca59e85cee1"
 
 [[projects]]
   branch = "master"
@@ -136,6 +136,15 @@
   revision = "7a3d63cfc6fbd9e46f2e551f9b8d1e9c69bffab1"
   source = "github.com/golangci/errcheck"
 
+[[projects]]
+  name = "github.com/kisielk/gotool"
+  packages = [
+    ".",
+    "internal/load"
+  ]
+  revision = "80517062f582ea3340cd4baf70e86d539ae7d84d"
+  version = "v1.0.0"
+
 [[projects]]
   name = "github.com/mattn/go-colorable"
   packages = ["."]
@@ -243,6 +252,20 @@
   ]
   revision = "87723262609ca8fd55d449c027454c29cadefd68"
 
+[[projects]]
+  branch = "master"
+  name = "mvdan.cc/interfacer"
+  packages = ["check"]
+  revision = "72c3fb5d5e5e0ca07e9a7c90bcd150b049920b3b"
+  source = "github.com/golangci/interfacer"
+
+[[projects]]
+  branch = "master"
+  name = "mvdan.cc/lint"
+  packages = ["."]
+  revision = "8ff1696d5934157cea033c4b97cf5ea23fdb7a32"
+  source = "github.com/golangci/lint"
+
 [[projects]]
   branch = "master"
   name = "sourcegraph.com/sourcegraph/go-diff"
@@ -258,6 +281,6 @@
 [solve-meta]
   analyzer-name = "dep"
   analyzer-version = 1
-  inputs-digest = "aa0c6cd4a6cd5957ffdeeb0f06753a92f33f5393045845e45bc63a10ead24a85"
+  inputs-digest = "6e4437a7adb255525e8d1cfda07716617c1f28acaa721ac4f910f52f49ecea2f"
   solver-name = "gps-cdcl"
   solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
index 53fc9e9a..91874be6 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -55,6 +55,16 @@
   branch = "master"
   source = "github.com/golangci/dupl"
 
+[[constraint]]
+  name = "mvdan.cc/interfacer"
+  branch = "master"
+  source = "github.com/golangci/interfacer"
+
+[[override]]
+  name = "mvdan.cc/lint"
+  branch = "master"
+  source = "github.com/golangci/lint"
+
 [prune]
   go-tests = true
   unused-packages = true
diff --git a/internal/commands/run.go b/internal/commands/run.go
index 508f2a51..77408071 100644
--- a/internal/commands/run.go
+++ b/internal/commands/run.go
@@ -10,6 +10,8 @@ import (
 	"time"
 
 	"github.com/fatih/color"
+	"github.com/golangci/go-tools/ssa"
+	"github.com/golangci/go-tools/ssa/ssautil"
 	"github.com/golangci/golangci-lint/pkg"
 	"github.com/golangci/golangci-lint/pkg/config"
 	"github.com/golangci/golangci-lint/pkg/fsutils"
@@ -84,6 +86,17 @@ func isFullImportNeeded(linters []pkg.Linter) bool {
 	return false
 }
 
+func isSSAReprNeeded(linters []pkg.Linter) bool {
+	for _, linter := range linters {
+		lc := pkg.GetLinterConfig(linter.Name())
+		if lc.NeedsSSARepr {
+			return true
+		}
+	}
+
+	return false
+}
+
 func loadWholeAppIfNeeded(ctx context.Context, linters []pkg.Linter, cfg *config.Run, paths *fsutils.ProjectPaths) (*loader.Program, *loader.Config, error) {
 	if !isFullImportNeeded(linters) {
 		return nil, nil, nil
@@ -117,6 +130,17 @@ func loadWholeAppIfNeeded(ctx context.Context, linters []pkg.Linter, cfg *config
 	return prog, loadcfg, nil
 }
 
+func buildSSAProgram(ctx context.Context, lprog *loader.Program) *ssa.Program {
+	startedAt := time.Now()
+	defer func() {
+		analytics.Log(ctx).Infof("SSA repr building took %s", time.Since(startedAt))
+	}()
+
+	ssaProg := ssautil.CreateProgram(lprog, ssa.GlobalDebug)
+	ssaProg.Build()
+	return ssaProg
+}
+
 func buildLintCtx(ctx context.Context, linters []pkg.Linter, cfg *config.Config) (*golinters.Context, error) {
 	args := cfg.Run.Args
 	if len(args) == 0 {
@@ -133,10 +157,16 @@ func buildLintCtx(ctx context.Context, linters []pkg.Linter, cfg *config.Config)
 		return nil, err
 	}
 
+	var ssaProg *ssa.Program
+	if prog != nil && isSSAReprNeeded(linters) {
+		ssaProg = buildSSAProgram(ctx, prog)
+	}
+
 	return &golinters.Context{
 		Paths:        paths,
 		Cfg:          cfg,
 		Program:      prog,
+		SSAProgram:   ssaProg,
 		LoaderConfig: loaderConfig,
 	}, nil
 }
diff --git a/pkg/enabled_linters.go b/pkg/enabled_linters.go
index db96f7ef..6563830c 100644
--- a/pkg/enabled_linters.go
+++ b/pkg/enabled_linters.go
@@ -15,6 +15,7 @@ type LinterConfig struct {
 	Linter           Linter
 	EnabledByDefault bool
 	DoesFullImport   bool
+	NeedsSSARepr     bool
 }
 
 var nameToLC map[string]LinterConfig
@@ -36,40 +37,43 @@ func GetLinterConfig(name string) *LinterConfig {
 	return &lc
 }
 
-func enabledByDefault(linter Linter, desc string, doesFullImport bool) LinterConfig {
+func enabledByDefault(linter Linter, desc string, doesFullImport, needsSSARepr bool) LinterConfig {
 	return LinterConfig{
 		EnabledByDefault: true,
 		Linter:           linter,
 		Desc:             desc,
 		DoesFullImport:   doesFullImport,
+		NeedsSSARepr:     needsSSARepr,
 	}
 }
 
-func disabledByDefault(linter Linter, desc string, doesFullImport bool) LinterConfig {
+func disabledByDefault(linter Linter, desc string, doesFullImport, needsSSARepr bool) LinterConfig {
 	return LinterConfig{
 		EnabledByDefault: false,
 		Linter:           linter,
 		Desc:             desc,
 		DoesFullImport:   doesFullImport,
+		NeedsSSARepr:     needsSSARepr,
 	}
 }
 
 func GetAllSupportedLinterConfigs() []LinterConfig {
 	return []LinterConfig{
-		enabledByDefault(golinters.Govet{}, "Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string", false),
-		enabledByDefault(golinters.Errcheck{}, "Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases", true),
-		enabledByDefault(golinters.Golint{}, "Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes", false),
-		enabledByDefault(golinters.Deadcode{}, "Finds unused code", true),
-		enabledByDefault(golinters.Gocyclo{}, "Computes and checks the cyclomatic complexity of functions", false),
-		enabledByDefault(golinters.Structcheck{}, "Finds unused struct fields", true),
-		enabledByDefault(golinters.Varcheck{}, "Finds unused global variables and constants", true),
-		enabledByDefault(golinters.Megacheck{}, "Megacheck: 3 sub-linters in one: staticcheck, gosimple and unused", true),
-		enabledByDefault(golinters.Dupl{}, "Tool for code clone detection", false),
-		enabledByDefault(golinters.Ineffassign{}, "Detects when assignments to existing variables are not used", false),
+		enabledByDefault(golinters.Govet{}, "Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string", false, false),
+		enabledByDefault(golinters.Errcheck{}, "Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases", true, false),
+		enabledByDefault(golinters.Golint{}, "Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes", false, false),
+		enabledByDefault(golinters.Deadcode{}, "Finds unused code", true, false),
+		enabledByDefault(golinters.Gocyclo{}, "Computes and checks the cyclomatic complexity of functions", false, false),
+		enabledByDefault(golinters.Structcheck{}, "Finds unused struct fields", true, false),
+		enabledByDefault(golinters.Varcheck{}, "Finds unused global variables and constants", true, false),
+		enabledByDefault(golinters.Megacheck{}, "Megacheck: 3 sub-linters in one: staticcheck, gosimple and unused", true, true),
+		enabledByDefault(golinters.Dupl{}, "Tool for code clone detection", false, false),
+		enabledByDefault(golinters.Ineffassign{}, "Detects when assignments to existing variables are not used", false, false),
+		enabledByDefault(golinters.Interfacer{}, "Linter that suggests narrower interface types", true, true),
 
-		disabledByDefault(golinters.Gofmt{}, "Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification", false),
-		disabledByDefault(golinters.Gofmt{UseGoimports: true}, "Goimports does everything that gofmt does. Additionally it checks unused imports", false),
-		disabledByDefault(golinters.Maligned{}, "Tool to detect Go structs that would take less memory if their fields were sorted", true),
+		disabledByDefault(golinters.Gofmt{}, "Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification", false, false),
+		disabledByDefault(golinters.Gofmt{UseGoimports: true}, "Goimports does everything that gofmt does. Additionally it checks unused imports", false, false),
+		disabledByDefault(golinters.Maligned{}, "Tool to detect Go structs that would take less memory if their fields were sorted", true, false),
 	}
 }
 
diff --git a/pkg/golinters/context.go b/pkg/golinters/context.go
index dbc18797..2d692721 100644
--- a/pkg/golinters/context.go
+++ b/pkg/golinters/context.go
@@ -1,6 +1,7 @@
 package golinters
 
 import (
+	"github.com/golangci/go-tools/ssa"
 	"github.com/golangci/golangci-lint/pkg/config"
 	"github.com/golangci/golangci-lint/pkg/fsutils"
 	"golang.org/x/tools/go/loader"
@@ -10,6 +11,7 @@ type Context struct {
 	Paths        *fsutils.ProjectPaths
 	Cfg          *config.Config
 	Program      *loader.Program
+	SSAProgram   *ssa.Program
 	LoaderConfig *loader.Config
 }
 
diff --git a/pkg/golinters/interfacer.go b/pkg/golinters/interfacer.go
new file mode 100644
index 00000000..887d0941
--- /dev/null
+++ b/pkg/golinters/interfacer.go
@@ -0,0 +1,39 @@
+package golinters
+
+import (
+	"context"
+
+	"mvdan.cc/interfacer/check"
+
+	"github.com/golangci/golangci-lint/pkg/result"
+)
+
+type Interfacer struct{}
+
+func (Interfacer) Name() string {
+	return "interfacer"
+}
+
+func (lint Interfacer) Run(ctx context.Context, lintCtx *Context) (*result.Result, error) {
+	c := new(check.Checker)
+	c.Program(lintCtx.Program)
+	c.ProgramSSA(lintCtx.SSAProgram)
+
+	issues, err := c.Check()
+	if err != nil {
+		return nil, err
+	}
+
+	res := &result.Result{}
+	for _, i := range issues {
+		pos := lintCtx.SSAProgram.Fset.Position(i.Pos())
+		res.Issues = append(res.Issues, result.Issue{
+			File:       pos.Filename,
+			LineNumber: pos.Line,
+			Text:       i.Message(),
+			FromLinter: lint.Name(),
+		})
+	}
+
+	return res, nil
+}
diff --git a/pkg/golinters/megacheck.go b/pkg/golinters/megacheck.go
index 7ab24dd0..c88d7aee 100644
--- a/pkg/golinters/megacheck.go
+++ b/pkg/golinters/megacheck.go
@@ -15,7 +15,7 @@ func (Megacheck) Name() string {
 
 func (m Megacheck) Run(ctx context.Context, lintCtx *Context) (*result.Result, error) {
 	c := lintCtx.RunCfg().Megacheck
-	issues := megacheckAPI.Run(lintCtx.Program, lintCtx.LoaderConfig, c.EnableStaticcheck, c.EnableGosimple, c.EnableUnused)
+	issues := megacheckAPI.Run(lintCtx.Program, lintCtx.LoaderConfig, lintCtx.SSAProgram, c.EnableStaticcheck, c.EnableGosimple, c.EnableUnused)
 
 	res := &result.Result{}
 	for _, i := range issues {
diff --git a/pkg/golinters/testdata/interfacer.go b/pkg/golinters/testdata/interfacer.go
new file mode 100644
index 00000000..36d05742
--- /dev/null
+++ b/pkg/golinters/testdata/interfacer.go
@@ -0,0 +1,7 @@
+package testdata
+
+import "io"
+
+func InterfacerCheck(f io.ReadCloser) { // ERROR "XXX"
+	f.Close()
+}
diff --git a/vendor/github.com/golangci/go-tools/cmd/megacheck/megacheck.go b/vendor/github.com/golangci/go-tools/cmd/megacheck/megacheck.go
index a7834418..45b540d9 100644
--- a/vendor/github.com/golangci/go-tools/cmd/megacheck/megacheck.go
+++ b/vendor/github.com/golangci/go-tools/cmd/megacheck/megacheck.go
@@ -5,12 +5,13 @@ import (
 	"github.com/golangci/go-tools/lint"
 	"github.com/golangci/go-tools/lint/lintutil"
 	"github.com/golangci/go-tools/simple"
+	"github.com/golangci/go-tools/ssa"
 	"github.com/golangci/go-tools/staticcheck"
 	"github.com/golangci/go-tools/unused"
 	"golang.org/x/tools/go/loader"
 )
 
-func Run(program *loader.Program, conf *loader.Config, enableStaticcheck, enableGosimple, enableUnused bool) []lint.Problem {
+func Run(program *loader.Program, conf *loader.Config, ssaProg *ssa.Program, enableStaticcheck, enableGosimple, enableUnused bool) []lint.Problem {
 	var flags struct {
 		staticcheck struct {
 			enabled     bool
@@ -120,5 +121,5 @@ func Run(program *loader.Program, conf *loader.Config, enableStaticcheck, enable
 
 	}
 
-	return lintutil.ProcessFlagSet(checkers, fs, program, conf)
+	return lintutil.ProcessFlagSet(checkers, fs, program, conf, ssaProg)
 }
diff --git a/vendor/github.com/golangci/go-tools/lint/lint.go b/vendor/github.com/golangci/go-tools/lint/lint.go
index aad75b84..2fb7983f 100644
--- a/vendor/github.com/golangci/go-tools/lint/lint.go
+++ b/vendor/github.com/golangci/go-tools/lint/lint.go
@@ -23,10 +23,10 @@ import (
 	"sync"
 	"unicode"
 
-	"github.com/golangci/go-tools/ssa"
-	"github.com/golangci/go-tools/ssa/ssautil"
 	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/loader"
+	"github.com/golangci/go-tools/ssa"
+	"github.com/golangci/go-tools/ssa/ssautil"
 )
 
 type Job struct {
@@ -235,9 +235,7 @@ func parseDirective(s string) (cmd string, args []string) {
 	return fields[0], fields[1:]
 }
 
-func (l *Linter) Lint(lprog *loader.Program, conf *loader.Config) []Problem {
-	ssaprog := ssautil.CreateProgram(lprog, ssa.GlobalDebug)
-	ssaprog.Build()
+func (l *Linter) Lint(lprog *loader.Program, conf *loader.Config, ssaprog *ssa.Program) []Problem {
 	pkgMap := map[*ssa.Package]*Pkg{}
 	var pkgs []*Pkg
 	for _, pkginfo := range lprog.InitialPackages() {
@@ -836,9 +834,6 @@ func (v *fnVisitor) Visit(node ast.Node) ast.Visitor {
 	switch node := node.(type) {
 	case *ast.FuncDecl:
 		var ssafn *ssa.Function
-		if v.pkg == nil || v.pkg.Prog == nil {
-			return nil // partially loaded
-		}
 		ssafn = v.pkg.Prog.FuncValue(v.pkg.Info.ObjectOf(node.Name).(*types.Func))
 		v.m[node] = ssafn
 		if ssafn == nil {
diff --git a/vendor/github.com/golangci/go-tools/lint/lintutil/util.go b/vendor/github.com/golangci/go-tools/lint/lintutil/util.go
index ec32be0e..bd8dc62a 100644
--- a/vendor/github.com/golangci/go-tools/lint/lintutil/util.go
+++ b/vendor/github.com/golangci/go-tools/lint/lintutil/util.go
@@ -23,6 +23,7 @@ import (
 	"github.com/golangci/go-tools/lint"
 	"github.com/golangci/go-tools/version"
 
+	"github.com/golangci/go-tools/ssa"
 	"golang.org/x/tools/go/loader"
 )
 
@@ -182,7 +183,7 @@ type CheckerConfig struct {
 	ExitNonZero bool
 }
 
-func ProcessFlagSet(confs []CheckerConfig, fs *flag.FlagSet, lprog *loader.Program, conf *loader.Config) []lint.Problem {
+func ProcessFlagSet(confs []CheckerConfig, fs *flag.FlagSet, lprog *loader.Program, conf *loader.Config, ssaProg *ssa.Program) []lint.Problem {
 	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)
@@ -199,7 +200,7 @@ func ProcessFlagSet(confs []CheckerConfig, fs *flag.FlagSet, lprog *loader.Progr
 	for _, conf := range confs {
 		cs = append(cs, conf.Checker)
 	}
-	pss, err := Lint(cs, lprog, conf, &Options{
+	pss, err := Lint(cs, lprog, conf, ssaProg, &Options{
 		Tags:          strings.Fields(tags),
 		LintTests:     tests,
 		Ignores:       ignore,
@@ -226,7 +227,7 @@ type Options struct {
 	ReturnIgnored bool
 }
 
-func Lint(cs []lint.Checker, lprog *loader.Program, conf *loader.Config, opt *Options) ([][]lint.Problem, error) {
+func Lint(cs []lint.Checker, lprog *loader.Program, conf *loader.Config, ssaProg *ssa.Program, opt *Options) ([][]lint.Problem, error) {
 	if opt == nil {
 		opt = &Options{}
 	}
@@ -244,7 +245,7 @@ func Lint(cs []lint.Checker, lprog *loader.Program, conf *loader.Config, opt *Op
 			version:       opt.GoVersion,
 			returnIgnored: opt.ReturnIgnored,
 		}
-		problems = append(problems, runner.lint(lprog, conf))
+		problems = append(problems, runner.lint(lprog, conf, ssaProg))
 	}
 	return problems, nil
 }
@@ -278,15 +279,15 @@ func ProcessArgs(name string, cs []CheckerConfig, args []string) {
 	flags := FlagSet(name)
 	flags.Parse(args)
 
-	ProcessFlagSet(cs, flags, nil, nil)
+	ProcessFlagSet(cs, flags, nil, nil, nil)
 }
 
-func (runner *runner) lint(lprog *loader.Program, conf *loader.Config) []lint.Problem {
+func (runner *runner) lint(lprog *loader.Program, conf *loader.Config, ssaProg *ssa.Program) []lint.Problem {
 	l := &lint.Linter{
 		Checker:       runner.checker,
 		Ignores:       runner.ignores,
 		GoVersion:     runner.version,
 		ReturnIgnored: runner.returnIgnored,
 	}
-	return l.Lint(lprog, conf)
+	return l.Lint(lprog, conf, ssaProg)
 }
diff --git a/vendor/github.com/kisielk/gotool/.travis.yml b/vendor/github.com/kisielk/gotool/.travis.yml
new file mode 100644
index 00000000..d1784e1e
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/.travis.yml
@@ -0,0 +1,23 @@
+sudo: false
+language: go
+go:
+  - 1.2
+  - 1.3
+  - 1.4
+  - 1.5
+  - 1.6
+  - 1.7
+  - 1.8
+  - 1.9
+  - master
+matrix:
+  allow_failures:
+    - go: master
+  fast_finish: true
+install:
+  - # Skip.
+script:
+  - go get -t -v ./...
+  - diff -u <(echo -n) <(gofmt -d .)
+  - go tool vet .
+  - go test -v -race ./...
diff --git a/vendor/github.com/kisielk/gotool/LEGAL b/vendor/github.com/kisielk/gotool/LEGAL
new file mode 100644
index 00000000..72b859cd
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/LEGAL
@@ -0,0 +1,32 @@
+All the files in this distribution are covered under either the MIT
+license (see the file LICENSE) except some files mentioned below.
+
+match.go, match_test.go:
+
+    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/github.com/kisielk/gotool/LICENSE b/vendor/github.com/kisielk/gotool/LICENSE
new file mode 100644
index 00000000..1cbf651e
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Kamil Kisiel <kamil@kamilkisiel.net>
+
+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/github.com/kisielk/gotool/README.md b/vendor/github.com/kisielk/gotool/README.md
new file mode 100644
index 00000000..6e4e92b2
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/README.md
@@ -0,0 +1,6 @@
+gotool
+======
+[![GoDoc](https://godoc.org/github.com/kisielk/gotool?status.svg)](https://godoc.org/github.com/kisielk/gotool)
+[![Build Status](https://travis-ci.org/kisielk/gotool.svg?branch=master)](https://travis-ci.org/kisielk/gotool)
+
+Package gotool contains utility functions used to implement the standard "cmd/go" tool, provided as a convenience to developers who want to write tools with similar semantics.
diff --git a/vendor/github.com/kisielk/gotool/go.mod b/vendor/github.com/kisielk/gotool/go.mod
new file mode 100644
index 00000000..503b37c6
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/go.mod
@@ -0,0 +1 @@
+module "github.com/kisielk/gotool"
diff --git a/vendor/github.com/kisielk/gotool/go13.go b/vendor/github.com/kisielk/gotool/go13.go
new file mode 100644
index 00000000..2dd9b3fd
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/go13.go
@@ -0,0 +1,15 @@
+// +build !go1.4
+
+package gotool
+
+import (
+	"go/build"
+	"path/filepath"
+	"runtime"
+)
+
+var gorootSrc = filepath.Join(runtime.GOROOT(), "src", "pkg")
+
+func shouldIgnoreImport(p *build.Package) bool {
+	return true
+}
diff --git a/vendor/github.com/kisielk/gotool/go14-15.go b/vendor/github.com/kisielk/gotool/go14-15.go
new file mode 100644
index 00000000..aa99a322
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/go14-15.go
@@ -0,0 +1,15 @@
+// +build go1.4,!go1.6
+
+package gotool
+
+import (
+	"go/build"
+	"path/filepath"
+	"runtime"
+)
+
+var gorootSrc = filepath.Join(runtime.GOROOT(), "src")
+
+func shouldIgnoreImport(p *build.Package) bool {
+	return true
+}
diff --git a/vendor/github.com/kisielk/gotool/go16-18.go b/vendor/github.com/kisielk/gotool/go16-18.go
new file mode 100644
index 00000000..f25cec14
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/go16-18.go
@@ -0,0 +1,15 @@
+// +build go1.6,!go1.9
+
+package gotool
+
+import (
+	"go/build"
+	"path/filepath"
+	"runtime"
+)
+
+var gorootSrc = filepath.Join(runtime.GOROOT(), "src")
+
+func shouldIgnoreImport(p *build.Package) bool {
+	return p == nil || len(p.InvalidGoFiles) == 0
+}
diff --git a/vendor/github.com/kisielk/gotool/internal/load/path.go b/vendor/github.com/kisielk/gotool/internal/load/path.go
new file mode 100644
index 00000000..74e15b9d
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/internal/load/path.go
@@ -0,0 +1,27 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.9
+
+package load
+
+import (
+	"strings"
+)
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+	switch {
+	default:
+		return false
+	case len(s) == len(prefix):
+		return s == prefix
+	case len(s) > len(prefix):
+		if prefix != "" && prefix[len(prefix)-1] == '/' {
+			return strings.HasPrefix(s, prefix)
+		}
+		return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+	}
+}
diff --git a/vendor/github.com/kisielk/gotool/internal/load/pkg.go b/vendor/github.com/kisielk/gotool/internal/load/pkg.go
new file mode 100644
index 00000000..b937ede7
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/internal/load/pkg.go
@@ -0,0 +1,25 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.9
+
+// Package load loads packages.
+package load
+
+import (
+	"strings"
+)
+
+// isStandardImportPath reports whether $GOROOT/src/path should be considered
+// part of the standard distribution. For historical reasons we allow people to add
+// their own code to $GOROOT instead of using $GOPATH, but we assume that
+// code will start with a domain name (dot in the first element).
+func isStandardImportPath(path string) bool {
+	i := strings.Index(path, "/")
+	if i < 0 {
+		i = len(path)
+	}
+	elem := path[:i]
+	return !strings.Contains(elem, ".")
+}
diff --git a/vendor/github.com/kisielk/gotool/internal/load/search.go b/vendor/github.com/kisielk/gotool/internal/load/search.go
new file mode 100644
index 00000000..17ed62dd
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/internal/load/search.go
@@ -0,0 +1,354 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.9
+
+package load
+
+import (
+	"fmt"
+	"go/build"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"regexp"
+	"strings"
+)
+
+// Context specifies values for operation of ImportPaths that would
+// otherwise come from cmd/go/internal/cfg package.
+//
+// This is a construct added for gotool purposes and doesn't have
+// an equivalent upstream in cmd/go.
+type Context struct {
+	// BuildContext is the build context to use.
+	BuildContext build.Context
+
+	// GOROOTsrc is the location of the src directory in GOROOT.
+	// At this time, it's used only in MatchPackages to skip
+	// GOOROOT/src entry from BuildContext.SrcDirs output.
+	GOROOTsrc string
+}
+
+// allPackages returns all the packages that can be found
+// under the $GOPATH directories and $GOROOT matching pattern.
+// The pattern is either "all" (all packages), "std" (standard packages),
+// "cmd" (standard commands), or a path including "...".
+func (c *Context) allPackages(pattern string) []string {
+	pkgs := c.MatchPackages(pattern)
+	if len(pkgs) == 0 {
+		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+	}
+	return pkgs
+}
+
+// allPackagesInFS is like allPackages but is passed a pattern
+// beginning ./ or ../, meaning it should scan the tree rooted
+// at the given directory. There are ... in the pattern too.
+func (c *Context) allPackagesInFS(pattern string) []string {
+	pkgs := c.MatchPackagesInFS(pattern)
+	if len(pkgs) == 0 {
+		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+	}
+	return pkgs
+}
+
+// MatchPackages returns a list of package paths matching pattern
+// (see go help packages for pattern syntax).
+func (c *Context) MatchPackages(pattern string) []string {
+	match := func(string) bool { return true }
+	treeCanMatch := func(string) bool { return true }
+	if !IsMetaPackage(pattern) {
+		match = matchPattern(pattern)
+		treeCanMatch = treeCanMatchPattern(pattern)
+	}
+
+	have := map[string]bool{
+		"builtin": true, // ignore pseudo-package that exists only for documentation
+	}
+	if !c.BuildContext.CgoEnabled {
+		have["runtime/cgo"] = true // ignore during walk
+	}
+	var pkgs []string
+
+	for _, src := range c.BuildContext.SrcDirs() {
+		if (pattern == "std" || pattern == "cmd") && src != c.GOROOTsrc {
+			continue
+		}
+		src = filepath.Clean(src) + string(filepath.Separator)
+		root := src
+		if pattern == "cmd" {
+			root += "cmd" + string(filepath.Separator)
+		}
+		filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+			if err != nil || path == src {
+				return nil
+			}
+
+			want := true
+			// Avoid .foo, _foo, and testdata directory trees.
+			_, elem := filepath.Split(path)
+			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+				want = false
+			}
+
+			name := filepath.ToSlash(path[len(src):])
+			if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
+				// The name "std" is only the standard library.
+				// If the name is cmd, it's the root of the command tree.
+				want = false
+			}
+			if !treeCanMatch(name) {
+				want = false
+			}
+
+			if !fi.IsDir() {
+				if fi.Mode()&os.ModeSymlink != 0 && want {
+					if target, err := os.Stat(path); err == nil && target.IsDir() {
+						fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
+					}
+				}
+				return nil
+			}
+			if !want {
+				return filepath.SkipDir
+			}
+
+			if have[name] {
+				return nil
+			}
+			have[name] = true
+			if !match(name) {
+				return nil
+			}
+			pkg, err := c.BuildContext.ImportDir(path, 0)
+			if err != nil {
+				if _, noGo := err.(*build.NoGoError); noGo {
+					return nil
+				}
+			}
+
+			// If we are expanding "cmd", skip main
+			// packages under cmd/vendor. At least as of
+			// March, 2017, there is one there for the
+			// vendored pprof tool.
+			if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" {
+				return nil
+			}
+
+			pkgs = append(pkgs, name)
+			return nil
+		})
+	}
+	return pkgs
+}
+
+// MatchPackagesInFS returns a list of package paths matching pattern,
+// which must begin with ./ or ../
+// (see go help packages for pattern syntax).
+func (c *Context) MatchPackagesInFS(pattern string) []string {
+	// Find directory to begin the scan.
+	// Could be smarter but this one optimization
+	// is enough for now, since ... is usually at the
+	// end of a path.
+	i := strings.Index(pattern, "...")
+	dir, _ := path.Split(pattern[:i])
+
+	// pattern begins with ./ or ../.
+	// path.Clean will discard the ./ but not the ../.
+	// We need to preserve the ./ for pattern matching
+	// and in the returned import paths.
+	prefix := ""
+	if strings.HasPrefix(pattern, "./") {
+		prefix = "./"
+	}
+	match := matchPattern(pattern)
+
+	var pkgs []string
+	filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+		if err != nil || !fi.IsDir() {
+			return nil
+		}
+		if path == dir {
+			// filepath.Walk starts at dir and recurses. For the recursive case,
+			// the path is the result of filepath.Join, which calls filepath.Clean.
+			// The initial case is not Cleaned, though, so we do this explicitly.
+			//
+			// This converts a path like "./io/" to "io". Without this step, running
+			// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
+			// package, because prepending the prefix "./" to the unclean path would
+			// result in "././io", and match("././io") returns false.
+			path = filepath.Clean(path)
+		}
+
+		// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
+		_, elem := filepath.Split(path)
+		dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
+		if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
+			return filepath.SkipDir
+		}
+
+		name := prefix + filepath.ToSlash(path)
+		if !match(name) {
+			return nil
+		}
+
+		// We keep the directory if we can import it, or if we can't import it
+		// due to invalid Go source files. This means that directories containing
+		// parse errors will be built (and fail) instead of being silently skipped
+		// as not matching the pattern. Go 1.5 and earlier skipped, but that
+		// behavior means people miss serious mistakes.
+		// See golang.org/issue/11407.
+		if p, err := c.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
+			if _, noGo := err.(*build.NoGoError); !noGo {
+				log.Print(err)
+			}
+			return nil
+		}
+		pkgs = append(pkgs, name)
+		return nil
+	})
+	return pkgs
+}
+
+// treeCanMatchPattern(pattern)(name) reports whether
+// name or children of name can possibly match pattern.
+// Pattern is the same limited glob accepted by matchPattern.
+func treeCanMatchPattern(pattern string) func(name string) bool {
+	wildCard := false
+	if i := strings.Index(pattern, "..."); i >= 0 {
+		wildCard = true
+		pattern = pattern[:i]
+	}
+	return func(name string) bool {
+		return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
+			wildCard && strings.HasPrefix(name, pattern)
+	}
+}
+
+// matchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+// Unfortunately, there are two special cases. Quoting "go help packages":
+//
+// First, /... at the end of the pattern can match an empty string,
+// so that net/... matches both net and packages in its subdirectories, like net/http.
+// Second, any slash-separted pattern element containing a wildcard never
+// participates in a match of the "vendor" element in the path of a vendored
+// package, so that ./... does not match packages in subdirectories of
+// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+// Note, however, that a directory named vendor that itself contains code
+// is not a vendored package: cmd/vendor would be a command named vendor,
+// and the pattern cmd/... matches it.
+func matchPattern(pattern string) func(name string) bool {
+	// Convert pattern to regular expression.
+	// The strategy for the trailing /... is to nest it in an explicit ? expression.
+	// The strategy for the vendor exclusion is to change the unmatchable
+	// vendor strings to a disallowed code point (vendorChar) and to use
+	// "(anything but that codepoint)*" as the implementation of the ... wildcard.
+	// This is a bit complicated but the obvious alternative,
+	// namely a hand-written search like in most shell glob matchers,
+	// is too easy to make accidentally exponential.
+	// Using package regexp guarantees linear-time matching.
+
+	const vendorChar = "\x00"
+
+	if strings.Contains(pattern, vendorChar) {
+		return func(name string) bool { return false }
+	}
+
+	re := regexp.QuoteMeta(pattern)
+	re = replaceVendor(re, vendorChar)
+	switch {
+	case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
+		re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
+	case re == vendorChar+`/\.\.\.`:
+		re = `(/vendor|/` + vendorChar + `/\.\.\.)`
+	case strings.HasSuffix(re, `/\.\.\.`):
+		re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
+	}
+	re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
+
+	reg := regexp.MustCompile(`^` + re + `$`)
+
+	return func(name string) bool {
+		if strings.Contains(name, vendorChar) {
+			return false
+		}
+		return reg.MatchString(replaceVendor(name, vendorChar))
+	}
+}
+
+// replaceVendor returns the result of replacing
+// non-trailing vendor path elements in x with repl.
+func replaceVendor(x, repl string) string {
+	if !strings.Contains(x, "vendor") {
+		return x
+	}
+	elem := strings.Split(x, "/")
+	for i := 0; i < len(elem)-1; i++ {
+		if elem[i] == "vendor" {
+			elem[i] = repl
+		}
+	}
+	return strings.Join(elem, "/")
+}
+
+// ImportPaths returns the import paths to use for the given command line.
+func (c *Context) ImportPaths(args []string) []string {
+	args = c.ImportPathsNoDotExpansion(args)
+	var out []string
+	for _, a := range args {
+		if strings.Contains(a, "...") {
+			if build.IsLocalImport(a) {
+				out = append(out, c.allPackagesInFS(a)...)
+			} else {
+				out = append(out, c.allPackages(a)...)
+			}
+			continue
+		}
+		out = append(out, a)
+	}
+	return out
+}
+
+// ImportPathsNoDotExpansion returns the import paths to use for the given
+// command line, but it does no ... expansion.
+func (c *Context) ImportPathsNoDotExpansion(args []string) []string {
+	if len(args) == 0 {
+		return []string{"."}
+	}
+	var out []string
+	for _, a := range args {
+		// Arguments are supposed to be import paths, but
+		// as a courtesy to Windows developers, rewrite \ to /
+		// in command-line arguments. Handles .\... and so on.
+		if filepath.Separator == '\\' {
+			a = strings.Replace(a, `\`, `/`, -1)
+		}
+
+		// Put argument in canonical form, but preserve leading ./.
+		if strings.HasPrefix(a, "./") {
+			a = "./" + path.Clean(a)
+			if a == "./." {
+				a = "."
+			}
+		} else {
+			a = path.Clean(a)
+		}
+		if IsMetaPackage(a) {
+			out = append(out, c.allPackages(a)...)
+			continue
+		}
+		out = append(out, a)
+	}
+	return out
+}
+
+// IsMetaPackage checks if name is a reserved package name that expands to multiple packages.
+func IsMetaPackage(name string) bool {
+	return name == "std" || name == "cmd" || name == "all"
+}
diff --git a/vendor/github.com/kisielk/gotool/match.go b/vendor/github.com/kisielk/gotool/match.go
new file mode 100644
index 00000000..4dbdbff4
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/match.go
@@ -0,0 +1,56 @@
+// 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.
+
+// +build go1.9
+
+package gotool
+
+import (
+	"path/filepath"
+
+	"github.com/kisielk/gotool/internal/load"
+)
+
+// importPaths returns the import paths to use for the given command line.
+func (c *Context) importPaths(args []string) []string {
+	lctx := load.Context{
+		BuildContext: c.BuildContext,
+		GOROOTsrc:    c.joinPath(c.BuildContext.GOROOT, "src"),
+	}
+	return lctx.ImportPaths(args)
+}
+
+// joinPath calls c.BuildContext.JoinPath (if not nil) or else filepath.Join.
+//
+// It's a copy of the unexported build.Context.joinPath helper.
+func (c *Context) joinPath(elem ...string) string {
+	if f := c.BuildContext.JoinPath; f != nil {
+		return f(elem...)
+	}
+	return filepath.Join(elem...)
+}
diff --git a/vendor/github.com/kisielk/gotool/match18.go b/vendor/github.com/kisielk/gotool/match18.go
new file mode 100644
index 00000000..6d6b1368
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/match18.go
@@ -0,0 +1,317 @@
+// 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.
+
+// +build !go1.9
+
+package gotool
+
+import (
+	"fmt"
+	"go/build"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"regexp"
+	"strings"
+)
+
+// This file contains code from the Go distribution.
+
+// matchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+func matchPattern(pattern string) func(name string) bool {
+	re := regexp.QuoteMeta(pattern)
+	re = strings.Replace(re, `\.\.\.`, `.*`, -1)
+	// Special case: foo/... matches foo too.
+	if strings.HasSuffix(re, `/.*`) {
+		re = re[:len(re)-len(`/.*`)] + `(/.*)?`
+	}
+	reg := regexp.MustCompile(`^` + re + `$`)
+	return reg.MatchString
+}
+
+// matchPackages returns a list of package paths matching pattern
+// (see go help packages for pattern syntax).
+func (c *Context) matchPackages(pattern string) []string {
+	match := func(string) bool { return true }
+	treeCanMatch := func(string) bool { return true }
+	if !isMetaPackage(pattern) {
+		match = matchPattern(pattern)
+		treeCanMatch = treeCanMatchPattern(pattern)
+	}
+
+	have := map[string]bool{
+		"builtin": true, // ignore pseudo-package that exists only for documentation
+	}
+	if !c.BuildContext.CgoEnabled {
+		have["runtime/cgo"] = true // ignore during walk
+	}
+	var pkgs []string
+
+	for _, src := range c.BuildContext.SrcDirs() {
+		if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
+			continue
+		}
+		src = filepath.Clean(src) + string(filepath.Separator)
+		root := src
+		if pattern == "cmd" {
+			root += "cmd" + string(filepath.Separator)
+		}
+		filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+			if err != nil || !fi.IsDir() || path == src {
+				return nil
+			}
+
+			// Avoid .foo, _foo, and testdata directory trees.
+			_, elem := filepath.Split(path)
+			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+				return filepath.SkipDir
+			}
+
+			name := filepath.ToSlash(path[len(src):])
+			if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
+				// The name "std" is only the standard library.
+				// If the name is cmd, it's the root of the command tree.
+				return filepath.SkipDir
+			}
+			if !treeCanMatch(name) {
+				return filepath.SkipDir
+			}
+			if have[name] {
+				return nil
+			}
+			have[name] = true
+			if !match(name) {
+				return nil
+			}
+			_, err = c.BuildContext.ImportDir(path, 0)
+			if err != nil {
+				if _, noGo := err.(*build.NoGoError); noGo {
+					return nil
+				}
+			}
+			pkgs = append(pkgs, name)
+			return nil
+		})
+	}
+	return pkgs
+}
+
+// importPathsNoDotExpansion returns the import paths to use for the given
+// command line, but it does no ... expansion.
+func (c *Context) importPathsNoDotExpansion(args []string) []string {
+	if len(args) == 0 {
+		return []string{"."}
+	}
+	var out []string
+	for _, a := range args {
+		// Arguments are supposed to be import paths, but
+		// as a courtesy to Windows developers, rewrite \ to /
+		// in command-line arguments. Handles .\... and so on.
+		if filepath.Separator == '\\' {
+			a = strings.Replace(a, `\`, `/`, -1)
+		}
+
+		// Put argument in canonical form, but preserve leading ./.
+		if strings.HasPrefix(a, "./") {
+			a = "./" + path.Clean(a)
+			if a == "./." {
+				a = "."
+			}
+		} else {
+			a = path.Clean(a)
+		}
+		if isMetaPackage(a) {
+			out = append(out, c.allPackages(a)...)
+			continue
+		}
+		out = append(out, a)
+	}
+	return out
+}
+
+// importPaths returns the import paths to use for the given command line.
+func (c *Context) importPaths(args []string) []string {
+	args = c.importPathsNoDotExpansion(args)
+	var out []string
+	for _, a := range args {
+		if strings.Contains(a, "...") {
+			if build.IsLocalImport(a) {
+				out = append(out, c.allPackagesInFS(a)...)
+			} else {
+				out = append(out, c.allPackages(a)...)
+			}
+			continue
+		}
+		out = append(out, a)
+	}
+	return out
+}
+
+// allPackages returns all the packages that can be found
+// under the $GOPATH directories and $GOROOT matching pattern.
+// The pattern is either "all" (all packages), "std" (standard packages),
+// "cmd" (standard commands), or a path including "...".
+func (c *Context) allPackages(pattern string) []string {
+	pkgs := c.matchPackages(pattern)
+	if len(pkgs) == 0 {
+		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+	}
+	return pkgs
+}
+
+// allPackagesInFS is like allPackages but is passed a pattern
+// beginning ./ or ../, meaning it should scan the tree rooted
+// at the given directory. There are ... in the pattern too.
+func (c *Context) allPackagesInFS(pattern string) []string {
+	pkgs := c.matchPackagesInFS(pattern)
+	if len(pkgs) == 0 {
+		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+	}
+	return pkgs
+}
+
+// matchPackagesInFS returns a list of package paths matching pattern,
+// which must begin with ./ or ../
+// (see go help packages for pattern syntax).
+func (c *Context) matchPackagesInFS(pattern string) []string {
+	// Find directory to begin the scan.
+	// Could be smarter but this one optimization
+	// is enough for now, since ... is usually at the
+	// end of a path.
+	i := strings.Index(pattern, "...")
+	dir, _ := path.Split(pattern[:i])
+
+	// pattern begins with ./ or ../.
+	// path.Clean will discard the ./ but not the ../.
+	// We need to preserve the ./ for pattern matching
+	// and in the returned import paths.
+	prefix := ""
+	if strings.HasPrefix(pattern, "./") {
+		prefix = "./"
+	}
+	match := matchPattern(pattern)
+
+	var pkgs []string
+	filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+		if err != nil || !fi.IsDir() {
+			return nil
+		}
+		if path == dir {
+			// filepath.Walk starts at dir and recurses. For the recursive case,
+			// the path is the result of filepath.Join, which calls filepath.Clean.
+			// The initial case is not Cleaned, though, so we do this explicitly.
+			//
+			// This converts a path like "./io/" to "io". Without this step, running
+			// "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
+			// package, because prepending the prefix "./" to the unclean path would
+			// result in "././io", and match("././io") returns false.
+			path = filepath.Clean(path)
+		}
+
+		// Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
+		_, elem := filepath.Split(path)
+		dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
+		if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
+			return filepath.SkipDir
+		}
+
+		name := prefix + filepath.ToSlash(path)
+		if !match(name) {
+			return nil
+		}
+
+		// We keep the directory if we can import it, or if we can't import it
+		// due to invalid Go source files. This means that directories containing
+		// parse errors will be built (and fail) instead of being silently skipped
+		// as not matching the pattern. Go 1.5 and earlier skipped, but that
+		// behavior means people miss serious mistakes.
+		// See golang.org/issue/11407.
+		if p, err := c.BuildContext.ImportDir(path, 0); err != nil && shouldIgnoreImport(p) {
+			if _, noGo := err.(*build.NoGoError); !noGo {
+				log.Print(err)
+			}
+			return nil
+		}
+		pkgs = append(pkgs, name)
+		return nil
+	})
+	return pkgs
+}
+
+// isMetaPackage checks if name is a reserved package name that expands to multiple packages.
+func isMetaPackage(name string) bool {
+	return name == "std" || name == "cmd" || name == "all"
+}
+
+// isStandardImportPath reports whether $GOROOT/src/path should be considered
+// part of the standard distribution. For historical reasons we allow people to add
+// their own code to $GOROOT instead of using $GOPATH, but we assume that
+// code will start with a domain name (dot in the first element).
+func isStandardImportPath(path string) bool {
+	i := strings.Index(path, "/")
+	if i < 0 {
+		i = len(path)
+	}
+	elem := path[:i]
+	return !strings.Contains(elem, ".")
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+	switch {
+	default:
+		return false
+	case len(s) == len(prefix):
+		return s == prefix
+	case len(s) > len(prefix):
+		if prefix != "" && prefix[len(prefix)-1] == '/' {
+			return strings.HasPrefix(s, prefix)
+		}
+		return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+	}
+}
+
+// treeCanMatchPattern(pattern)(name) reports whether
+// name or children of name can possibly match pattern.
+// Pattern is the same limited glob accepted by matchPattern.
+func treeCanMatchPattern(pattern string) func(name string) bool {
+	wildCard := false
+	if i := strings.Index(pattern, "..."); i >= 0 {
+		wildCard = true
+		pattern = pattern[:i]
+	}
+	return func(name string) bool {
+		return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
+			wildCard && strings.HasPrefix(name, pattern)
+	}
+}
diff --git a/vendor/github.com/kisielk/gotool/tool.go b/vendor/github.com/kisielk/gotool/tool.go
new file mode 100644
index 00000000..c7409e11
--- /dev/null
+++ b/vendor/github.com/kisielk/gotool/tool.go
@@ -0,0 +1,48 @@
+// Package gotool contains utility functions used to implement the standard
+// "cmd/go" tool, provided as a convenience to developers who want to write
+// tools with similar semantics.
+package gotool
+
+import "go/build"
+
+// Export functions here to make it easier to keep the implementations up to date with upstream.
+
+// DefaultContext is the default context that uses build.Default.
+var DefaultContext = Context{
+	BuildContext: build.Default,
+}
+
+// A Context specifies the supporting context.
+type Context struct {
+	// BuildContext is the build.Context that is used when computing import paths.
+	BuildContext build.Context
+}
+
+// ImportPaths returns the import paths to use for the given command line.
+//
+// The path "all" is expanded to all packages in $GOPATH and $GOROOT.
+// The path "std" is expanded to all packages in the Go standard library.
+// The path "cmd" is expanded to all Go standard commands.
+// The string "..." is treated as a wildcard within a path.
+// When matching recursively, directories are ignored if they are prefixed with
+// a dot or an underscore (such as ".foo" or "_foo"), or are named "testdata".
+// Relative import paths are not converted to full import paths.
+// If args is empty, a single element "." is returned.
+func (c *Context) ImportPaths(args []string) []string {
+	return c.importPaths(args)
+}
+
+// ImportPaths returns the import paths to use for the given command line
+// using default context.
+//
+// The path "all" is expanded to all packages in $GOPATH and $GOROOT.
+// The path "std" is expanded to all packages in the Go standard library.
+// The path "cmd" is expanded to all Go standard commands.
+// The string "..." is treated as a wildcard within a path.
+// When matching recursively, directories are ignored if they are prefixed with
+// a dot or an underscore (such as ".foo" or "_foo"), or are named "testdata".
+// Relative import paths are not converted to full import paths.
+// If args is empty, a single element "." is returned.
+func ImportPaths(args []string) []string {
+	return DefaultContext.importPaths(args)
+}
diff --git a/vendor/mvdan.cc/interfacer/LICENSE b/vendor/mvdan.cc/interfacer/LICENSE
new file mode 100644
index 00000000..7d71d51a
--- /dev/null
+++ b/vendor/mvdan.cc/interfacer/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2015, Daniel Martí. 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 the copyright holder 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/mvdan.cc/interfacer/check/cache.go b/vendor/mvdan.cc/interfacer/check/cache.go
new file mode 100644
index 00000000..757eca55
--- /dev/null
+++ b/vendor/mvdan.cc/interfacer/check/cache.go
@@ -0,0 +1,50 @@
+// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
+// See LICENSE for licensing information
+
+package check
+
+import (
+	"go/ast"
+	"go/types"
+)
+
+type pkgTypes struct {
+	ifaces    map[string]string
+	funcSigns map[string]bool
+}
+
+func (p *pkgTypes) getTypes(pkg *types.Package) {
+	p.ifaces = make(map[string]string)
+	p.funcSigns = make(map[string]bool)
+	done := make(map[*types.Package]bool)
+	addTypes := func(pkg *types.Package, top bool) {
+		if done[pkg] {
+			return
+		}
+		done[pkg] = true
+		ifs, funs := fromScope(pkg.Scope())
+		fullName := func(name string) string {
+			if !top {
+				return pkg.Path() + "." + name
+			}
+			return name
+		}
+		for iftype, name := range ifs {
+			// only suggest exported interfaces
+			if ast.IsExported(name) {
+				p.ifaces[iftype] = fullName(name)
+			}
+		}
+		for ftype := range funs {
+			// ignore non-exported func signatures too
+			p.funcSigns[ftype] = true
+		}
+	}
+	for _, imp := range pkg.Imports() {
+		addTypes(imp, false)
+		for _, imp2 := range imp.Imports() {
+			addTypes(imp2, false)
+		}
+	}
+	addTypes(pkg, true)
+}
diff --git a/vendor/mvdan.cc/interfacer/check/check.go b/vendor/mvdan.cc/interfacer/check/check.go
new file mode 100644
index 00000000..5d930e35
--- /dev/null
+++ b/vendor/mvdan.cc/interfacer/check/check.go
@@ -0,0 +1,462 @@
+// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
+// See LICENSE for licensing information
+
+package check // import "mvdan.cc/interfacer/check"
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+	"go/types"
+	"os"
+	"strings"
+
+	"github.com/golangci/go-tools/ssa"
+	"github.com/golangci/go-tools/ssa/ssautil"
+	"golang.org/x/tools/go/loader"
+
+	"github.com/kisielk/gotool"
+	"mvdan.cc/lint"
+)
+
+func toDiscard(usage *varUsage) bool {
+	if usage.discard {
+		return true
+	}
+	for to := range usage.assigned {
+		if toDiscard(to) {
+			return true
+		}
+	}
+	return false
+}
+
+func allCalls(usage *varUsage, all, ftypes map[string]string) {
+	for fname := range usage.calls {
+		all[fname] = ftypes[fname]
+	}
+	for to := range usage.assigned {
+		allCalls(to, all, ftypes)
+	}
+}
+
+func (c *Checker) interfaceMatching(param *types.Var, usage *varUsage) (string, string) {
+	if toDiscard(usage) {
+		return "", ""
+	}
+	ftypes := typeFuncMap(param.Type())
+	called := make(map[string]string, len(usage.calls))
+	allCalls(usage, called, ftypes)
+	s := funcMapString(called)
+	return c.ifaces[s], s
+}
+
+type varUsage struct {
+	calls   map[string]struct{}
+	discard bool
+
+	assigned map[*varUsage]struct{}
+}
+
+type funcDecl struct {
+	astDecl *ast.FuncDecl
+	ssaFn   *ssa.Function
+}
+
+// CheckArgs checks the packages specified by their import paths in
+// args.
+func CheckArgs(args []string) ([]string, error) {
+	paths := gotool.ImportPaths(args)
+	conf := loader.Config{}
+	conf.AllowErrors = true
+	rest, err := conf.FromArgs(paths, false)
+	if err != nil {
+		return nil, err
+	}
+	if len(rest) > 0 {
+		return nil, fmt.Errorf("unwanted extra args: %v", rest)
+	}
+	lprog, err := conf.Load()
+	if err != nil {
+		return nil, err
+	}
+	prog := ssautil.CreateProgram(lprog, 0)
+	prog.Build()
+	c := new(Checker)
+	c.Program(lprog)
+	c.ProgramSSA(prog)
+	issues, err := c.Check()
+	if err != nil {
+		return nil, err
+	}
+	wd, err := os.Getwd()
+	if err != nil {
+		return nil, err
+	}
+	lines := make([]string, len(issues))
+	for i, issue := range issues {
+		fpos := prog.Fset.Position(issue.Pos()).String()
+		if strings.HasPrefix(fpos, wd) {
+			fpos = fpos[len(wd)+1:]
+		}
+		lines[i] = fmt.Sprintf("%s: %s", fpos, issue.Message())
+	}
+	return lines, nil
+}
+
+type Checker struct {
+	lprog *loader.Program
+	prog  *ssa.Program
+
+	pkgTypes
+	*loader.PackageInfo
+
+	funcs []*funcDecl
+
+	ssaByPos map[token.Pos]*ssa.Function
+
+	discardFuncs map[*types.Signature]struct{}
+
+	vars map[*types.Var]*varUsage
+}
+
+var (
+	_ lint.Checker = (*Checker)(nil)
+	_ lint.WithSSA = (*Checker)(nil)
+)
+
+func (c *Checker) Program(lprog *loader.Program) {
+	c.lprog = lprog
+}
+
+func (c *Checker) ProgramSSA(prog *ssa.Program) {
+	c.prog = prog
+}
+
+func (c *Checker) Check() ([]lint.Issue, error) {
+	var total []lint.Issue
+	c.ssaByPos = make(map[token.Pos]*ssa.Function)
+	wantPkg := make(map[*types.Package]bool)
+	for _, pinfo := range c.lprog.InitialPackages() {
+		wantPkg[pinfo.Pkg] = true
+	}
+	for fn := range ssautil.AllFunctions(c.prog) {
+		if fn.Pkg == nil { // builtin?
+			continue
+		}
+		if len(fn.Blocks) == 0 { // stub
+			continue
+		}
+		if !wantPkg[fn.Pkg.Pkg] { // not part of given pkgs
+			continue
+		}
+		c.ssaByPos[fn.Pos()] = fn
+	}
+	for _, pinfo := range c.lprog.InitialPackages() {
+		pkg := pinfo.Pkg
+		c.getTypes(pkg)
+		c.PackageInfo = c.lprog.AllPackages[pkg]
+		total = append(total, c.checkPkg()...)
+	}
+	return total, nil
+}
+
+func (c *Checker) checkPkg() []lint.Issue {
+	c.discardFuncs = make(map[*types.Signature]struct{})
+	c.vars = make(map[*types.Var]*varUsage)
+	c.funcs = c.funcs[:0]
+	findFuncs := func(node ast.Node) bool {
+		decl, ok := node.(*ast.FuncDecl)
+		if !ok {
+			return true
+		}
+		ssaFn := c.ssaByPos[decl.Name.Pos()]
+		if ssaFn == nil {
+			return true
+		}
+		fd := &funcDecl{
+			astDecl: decl,
+			ssaFn:   ssaFn,
+		}
+		if c.funcSigns[signString(fd.ssaFn.Signature)] {
+			// implements interface
+			return true
+		}
+		c.funcs = append(c.funcs, fd)
+		ast.Walk(c, decl.Body)
+		return true
+	}
+	for _, f := range c.Files {
+		ast.Inspect(f, findFuncs)
+	}
+	return c.packageIssues()
+}
+
+func paramVarAndType(sign *types.Signature, i int) (*types.Var, types.Type) {
+	params := sign.Params()
+	extra := sign.Variadic() && i >= params.Len()-1
+	if !extra {
+		if i >= params.Len() {
+			// builtins with multiple signatures
+			return nil, nil
+		}
+		vr := params.At(i)
+		return vr, vr.Type()
+	}
+	last := params.At(params.Len() - 1)
+	switch x := last.Type().(type) {
+	case *types.Slice:
+		return nil, x.Elem()
+	default:
+		return nil, x
+	}
+}
+
+func (c *Checker) varUsage(e ast.Expr) *varUsage {
+	id, ok := e.(*ast.Ident)
+	if !ok {
+		return nil
+	}
+	param, ok := c.ObjectOf(id).(*types.Var)
+	if !ok {
+		// not a variable
+		return nil
+	}
+	if usage, e := c.vars[param]; e {
+		return usage
+	}
+	if !interesting(param.Type()) {
+		return nil
+	}
+	usage := &varUsage{
+		calls:    make(map[string]struct{}),
+		assigned: make(map[*varUsage]struct{}),
+	}
+	c.vars[param] = usage
+	return usage
+}
+
+func (c *Checker) addUsed(e ast.Expr, as types.Type) {
+	if as == nil {
+		return
+	}
+	if usage := c.varUsage(e); usage != nil {
+		// using variable
+		iface, ok := as.Underlying().(*types.Interface)
+		if !ok {
+			usage.discard = true
+			return
+		}
+		for i := 0; i < iface.NumMethods(); i++ {
+			m := iface.Method(i)
+			usage.calls[m.Name()] = struct{}{}
+		}
+	} else if t, ok := c.TypeOf(e).(*types.Signature); ok {
+		// using func
+		c.discardFuncs[t] = struct{}{}
+	}
+}
+
+func (c *Checker) addAssign(to, from ast.Expr) {
+	pto := c.varUsage(to)
+	pfrom := c.varUsage(from)
+	if pto == nil || pfrom == nil {
+		// either isn't interesting
+		return
+	}
+	pfrom.assigned[pto] = struct{}{}
+}
+
+func (c *Checker) discard(e ast.Expr) {
+	if usage := c.varUsage(e); usage != nil {
+		usage.discard = true
+	}
+}
+
+func (c *Checker) comparedWith(e, with ast.Expr) {
+	if _, ok := with.(*ast.BasicLit); ok {
+		c.discard(e)
+	}
+}
+
+func (c *Checker) Visit(node ast.Node) ast.Visitor {
+	switch x := node.(type) {
+	case *ast.SelectorExpr:
+		if _, ok := c.TypeOf(x.Sel).(*types.Signature); !ok {
+			c.discard(x.X)
+		}
+	case *ast.StarExpr:
+		c.discard(x.X)
+	case *ast.UnaryExpr:
+		c.discard(x.X)
+	case *ast.IndexExpr:
+		c.discard(x.X)
+	case *ast.IncDecStmt:
+		c.discard(x.X)
+	case *ast.BinaryExpr:
+		switch x.Op {
+		case token.EQL, token.NEQ:
+			c.comparedWith(x.X, x.Y)
+			c.comparedWith(x.Y, x.X)
+		default:
+			c.discard(x.X)
+			c.discard(x.Y)
+		}
+	case *ast.ValueSpec:
+		for _, val := range x.Values {
+			c.addUsed(val, c.TypeOf(x.Type))
+		}
+	case *ast.AssignStmt:
+		for i, val := range x.Rhs {
+			left := x.Lhs[i]
+			if x.Tok == token.ASSIGN {
+				c.addUsed(val, c.TypeOf(left))
+			}
+			c.addAssign(left, val)
+		}
+	case *ast.CompositeLit:
+		for i, e := range x.Elts {
+			switch y := e.(type) {
+			case *ast.KeyValueExpr:
+				c.addUsed(y.Key, c.TypeOf(y.Value))
+				c.addUsed(y.Value, c.TypeOf(y.Key))
+			case *ast.Ident:
+				c.addUsed(y, compositeIdentType(c.TypeOf(x), i))
+			}
+		}
+	case *ast.CallExpr:
+		switch y := c.TypeOf(x.Fun).Underlying().(type) {
+		case *types.Signature:
+			c.onMethodCall(x, y)
+		default:
+			// type conversion
+			if len(x.Args) == 1 {
+				c.addUsed(x.Args[0], y)
+			}
+		}
+	}
+	return c
+}
+
+func compositeIdentType(t types.Type, i int) types.Type {
+	switch x := t.(type) {
+	case *types.Named:
+		return compositeIdentType(x.Underlying(), i)
+	case *types.Struct:
+		return x.Field(i).Type()
+	case *types.Array:
+		return x.Elem()
+	case *types.Slice:
+		return x.Elem()
+	}
+	return nil
+}
+
+func (c *Checker) onMethodCall(ce *ast.CallExpr, sign *types.Signature) {
+	for i, e := range ce.Args {
+		paramObj, t := paramVarAndType(sign, i)
+		// Don't if this is a parameter being re-used as itself
+		// in a recursive call
+		if id, ok := e.(*ast.Ident); ok {
+			if paramObj == c.ObjectOf(id) {
+				continue
+			}
+		}
+		c.addUsed(e, t)
+	}
+	sel, ok := ce.Fun.(*ast.SelectorExpr)
+	if !ok {
+		return
+	}
+	// receiver func call on the left side
+	if usage := c.varUsage(sel.X); usage != nil {
+		usage.calls[sel.Sel.Name] = struct{}{}
+	}
+}
+
+func (fd *funcDecl) paramGroups() [][]*types.Var {
+	astList := fd.astDecl.Type.Params.List
+	groups := make([][]*types.Var, len(astList))
+	signIndex := 0
+	for i, field := range astList {
+		group := make([]*types.Var, len(field.Names))
+		for j := range field.Names {
+			group[j] = fd.ssaFn.Signature.Params().At(signIndex)
+			signIndex++
+		}
+		groups[i] = group
+	}
+	return groups
+}
+
+func (c *Checker) packageIssues() []lint.Issue {
+	var issues []lint.Issue
+	for _, fd := range c.funcs {
+		if _, e := c.discardFuncs[fd.ssaFn.Signature]; e {
+			continue
+		}
+		for _, group := range fd.paramGroups() {
+			issues = append(issues, c.groupIssues(fd, group)...)
+		}
+	}
+	return issues
+}
+
+type Issue struct {
+	pos token.Pos
+	msg string
+}
+
+func (i Issue) Pos() token.Pos  { return i.pos }
+func (i Issue) Message() string { return i.msg }
+
+func (c *Checker) groupIssues(fd *funcDecl, group []*types.Var) []lint.Issue {
+	var issues []lint.Issue
+	for _, param := range group {
+		usage := c.vars[param]
+		if usage == nil {
+			return nil
+		}
+		newType := c.paramNewType(fd.astDecl.Name.Name, param, usage)
+		if newType == "" {
+			return nil
+		}
+		issues = append(issues, Issue{
+			pos: param.Pos(),
+			msg: fmt.Sprintf("%s can be %s", param.Name(), newType),
+		})
+	}
+	return issues
+}
+
+func willAddAllocation(t types.Type) bool {
+	switch t.Underlying().(type) {
+	case *types.Pointer, *types.Interface:
+		return false
+	}
+	return true
+}
+
+func (c *Checker) paramNewType(funcName string, param *types.Var, usage *varUsage) string {
+	t := param.Type()
+	if !ast.IsExported(funcName) && willAddAllocation(t) {
+		return ""
+	}
+	if named := typeNamed(t); named != nil {
+		tname := named.Obj().Name()
+		vname := param.Name()
+		if mentionsName(funcName, tname) || mentionsName(funcName, vname) {
+			return ""
+		}
+	}
+	ifname, iftype := c.interfaceMatching(param, usage)
+	if ifname == "" {
+		return ""
+	}
+	if types.IsInterface(t.Underlying()) {
+		if have := funcMapString(typeFuncMap(t)); have == iftype {
+			return ""
+		}
+	}
+	return ifname
+}
diff --git a/vendor/mvdan.cc/interfacer/check/types.go b/vendor/mvdan.cc/interfacer/check/types.go
new file mode 100644
index 00000000..393bb0b9
--- /dev/null
+++ b/vendor/mvdan.cc/interfacer/check/types.go
@@ -0,0 +1,170 @@
+// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
+// See LICENSE for licensing information
+
+package check
+
+import (
+	"bytes"
+	"fmt"
+	"go/types"
+	"sort"
+	"strings"
+)
+
+type methoder interface {
+	NumMethods() int
+	Method(int) *types.Func
+}
+
+func methoderFuncMap(m methoder, skip bool) map[string]string {
+	ifuncs := make(map[string]string, m.NumMethods())
+	for i := 0; i < m.NumMethods(); i++ {
+		f := m.Method(i)
+		if !f.Exported() {
+			if skip {
+				continue
+			}
+			return nil
+		}
+		sign := f.Type().(*types.Signature)
+		ifuncs[f.Name()] = signString(sign)
+	}
+	return ifuncs
+}
+
+func typeFuncMap(t types.Type) map[string]string {
+	switch x := t.(type) {
+	case *types.Pointer:
+		return typeFuncMap(x.Elem())
+	case *types.Named:
+		u := x.Underlying()
+		if types.IsInterface(u) {
+			return typeFuncMap(u)
+		}
+		return methoderFuncMap(x, true)
+	case *types.Interface:
+		return methoderFuncMap(x, false)
+	default:
+		return nil
+	}
+}
+
+func funcMapString(iface map[string]string) string {
+	fnames := make([]string, 0, len(iface))
+	for fname := range iface {
+		fnames = append(fnames, fname)
+	}
+	sort.Strings(fnames)
+	var b bytes.Buffer
+	for i, fname := range fnames {
+		if i > 0 {
+			fmt.Fprint(&b, "; ")
+		}
+		fmt.Fprint(&b, fname, iface[fname])
+	}
+	return b.String()
+}
+
+func tupleJoin(buf *bytes.Buffer, t *types.Tuple) {
+	buf.WriteByte('(')
+	for i := 0; i < t.Len(); i++ {
+		if i > 0 {
+			buf.WriteString(", ")
+		}
+		buf.WriteString(t.At(i).Type().String())
+	}
+	buf.WriteByte(')')
+}
+
+// signString is similar to Signature.String(), but it ignores
+// param/result names.
+func signString(sign *types.Signature) string {
+	var buf bytes.Buffer
+	tupleJoin(&buf, sign.Params())
+	tupleJoin(&buf, sign.Results())
+	return buf.String()
+}
+
+func interesting(t types.Type) bool {
+	switch x := t.(type) {
+	case *types.Interface:
+		return x.NumMethods() > 1
+	case *types.Named:
+		if u := x.Underlying(); types.IsInterface(u) {
+			return interesting(u)
+		}
+		return x.NumMethods() >= 1
+	case *types.Pointer:
+		return interesting(x.Elem())
+	default:
+		return false
+	}
+}
+
+func anyInteresting(params *types.Tuple) bool {
+	for i := 0; i < params.Len(); i++ {
+		t := params.At(i).Type()
+		if interesting(t) {
+			return true
+		}
+	}
+	return false
+}
+
+func fromScope(scope *types.Scope) (ifaces map[string]string, funcs map[string]bool) {
+	ifaces = make(map[string]string)
+	funcs = make(map[string]bool)
+	for _, name := range scope.Names() {
+		tn, ok := scope.Lookup(name).(*types.TypeName)
+		if !ok {
+			continue
+		}
+		switch x := tn.Type().Underlying().(type) {
+		case *types.Interface:
+			iface := methoderFuncMap(x, false)
+			if len(iface) == 0 {
+				continue
+			}
+			for i := 0; i < x.NumMethods(); i++ {
+				f := x.Method(i)
+				sign := f.Type().(*types.Signature)
+				if !anyInteresting(sign.Params()) {
+					continue
+				}
+				funcs[signString(sign)] = true
+			}
+			s := funcMapString(iface)
+			if _, e := ifaces[s]; !e {
+				ifaces[s] = tn.Name()
+			}
+		case *types.Signature:
+			if !anyInteresting(x.Params()) {
+				continue
+			}
+			funcs[signString(x)] = true
+		}
+	}
+	return ifaces, funcs
+}
+
+func mentionsName(fname, name string) bool {
+	if len(name) < 2 {
+		return false
+	}
+	capit := strings.ToUpper(name[:1]) + name[1:]
+	lower := strings.ToLower(name)
+	return strings.Contains(fname, capit) || strings.HasPrefix(fname, lower)
+}
+
+func typeNamed(t types.Type) *types.Named {
+	for {
+		switch x := t.(type) {
+		case *types.Named:
+			return x
+		case *types.Pointer:
+			t = x.Elem()
+		default:
+			return nil
+		}
+	}
+}
diff --git a/vendor/mvdan.cc/lint/.travis.yml b/vendor/mvdan.cc/lint/.travis.yml
new file mode 100644
index 00000000..2ccdeab9
--- /dev/null
+++ b/vendor/mvdan.cc/lint/.travis.yml
@@ -0,0 +1,7 @@
+language: go
+
+go:
+  - 1.8.x
+  - 1.9.x
+
+go_import_path: mvdan.cc/lint
diff --git a/vendor/mvdan.cc/lint/LICENSE b/vendor/mvdan.cc/lint/LICENSE
new file mode 100644
index 00000000..a06c5ebf
--- /dev/null
+++ b/vendor/mvdan.cc/lint/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2017, Daniel Martí. 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 the copyright holder 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/mvdan.cc/lint/README.md b/vendor/mvdan.cc/lint/README.md
new file mode 100644
index 00000000..8a9c8b51
--- /dev/null
+++ b/vendor/mvdan.cc/lint/README.md
@@ -0,0 +1,27 @@
+# lint
+
+[![GoDoc](https://godoc.org/mvdan.cc/lint?status.svg)](https://godoc.org/mvdan.cc/lint)
+[![Build Status](https://travis-ci.org/mvdan/lint.svg?branch=master)](https://travis-ci.org/mvdan/lint)
+
+Work in progress. Its API might change before the 1.0 release.
+
+This package intends to define simple interfaces that Go code checkers
+can implement. This would simplify calling them from Go code, as well as
+running multiple linters while sharing initial loading work.
+
+### metalint
+
+	go get -u mvdan.cc/lint/cmd/metalint
+
+The start of a linter that runs many linters leveraging the common
+interface. Not stable yet.
+
+Linters included:
+
+* [unparam](https://mvdan.cc/unparam)
+* [interfacer](https://github.com/mvdan/interfacer)
+
+### Related projects
+
+* [golinters](https://github.com/thomasheller/golinters) - Report on
+  linter support
diff --git a/vendor/mvdan.cc/lint/lint.go b/vendor/mvdan.cc/lint/lint.go
new file mode 100644
index 00000000..153d04ca
--- /dev/null
+++ b/vendor/mvdan.cc/lint/lint.go
@@ -0,0 +1,28 @@
+// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
+// See LICENSE for licensing information
+
+// Package lint defines common interfaces for Go code checkers.
+package lint // import "mvdan.cc/lint"
+
+import (
+	"go/token"
+
+	"github.com/golangci/go-tools/ssa"
+	"golang.org/x/tools/go/loader"
+)
+
+// A Checker points out issues in a program.
+type Checker interface {
+	Program(*loader.Program)
+	Check() ([]Issue, error)
+}
+
+type WithSSA interface {
+	ProgramSSA(*ssa.Program)
+}
+
+// Issue represents an issue somewhere in a source code file.
+type Issue interface {
+	Pos() token.Pos
+	Message() string
+}