support interfacer
This commit is contained in:
parent
364dd68ed8
commit
c6dc47bcbd
27
Gopkg.lock
generated
27
Gopkg.lock
generated
@ -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
|
||||
|
10
Gopkg.toml
10
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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
39
pkg/golinters/interfacer.go
Normal file
39
pkg/golinters/interfacer.go
Normal file
@ -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
|
||||
}
|
@ -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 {
|
||||
|
7
pkg/golinters/testdata/interfacer.go
vendored
Normal file
7
pkg/golinters/testdata/interfacer.go
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
package testdata
|
||||
|
||||
import "io"
|
||||
|
||||
func InterfacerCheck(f io.ReadCloser) { // ERROR "XXX"
|
||||
f.Close()
|
||||
}
|
5
vendor/github.com/golangci/go-tools/cmd/megacheck/megacheck.go
generated
vendored
5
vendor/github.com/golangci/go-tools/cmd/megacheck/megacheck.go
generated
vendored
@ -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)
|
||||
}
|
||||
|
11
vendor/github.com/golangci/go-tools/lint/lint.go
generated
vendored
11
vendor/github.com/golangci/go-tools/lint/lint.go
generated
vendored
@ -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 {
|
||||
|
15
vendor/github.com/golangci/go-tools/lint/lintutil/util.go
generated
vendored
15
vendor/github.com/golangci/go-tools/lint/lintutil/util.go
generated
vendored
@ -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)
|
||||
}
|
||||
|
23
vendor/github.com/kisielk/gotool/.travis.yml
generated
vendored
Normal file
23
vendor/github.com/kisielk/gotool/.travis.yml
generated
vendored
Normal file
@ -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 ./...
|
32
vendor/github.com/kisielk/gotool/LEGAL
generated
vendored
Normal file
32
vendor/github.com/kisielk/gotool/LEGAL
generated
vendored
Normal file
@ -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.
|
20
vendor/github.com/kisielk/gotool/LICENSE
generated
vendored
Normal file
20
vendor/github.com/kisielk/gotool/LICENSE
generated
vendored
Normal file
@ -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.
|
6
vendor/github.com/kisielk/gotool/README.md
generated
vendored
Normal file
6
vendor/github.com/kisielk/gotool/README.md
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
gotool
|
||||
======
|
||||
[](https://godoc.org/github.com/kisielk/gotool)
|
||||
[](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.
|
1
vendor/github.com/kisielk/gotool/go.mod
generated
vendored
Normal file
1
vendor/github.com/kisielk/gotool/go.mod
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
module "github.com/kisielk/gotool"
|
15
vendor/github.com/kisielk/gotool/go13.go
generated
vendored
Normal file
15
vendor/github.com/kisielk/gotool/go13.go
generated
vendored
Normal file
@ -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
|
||||
}
|
15
vendor/github.com/kisielk/gotool/go14-15.go
generated
vendored
Normal file
15
vendor/github.com/kisielk/gotool/go14-15.go
generated
vendored
Normal file
@ -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
|
||||
}
|
15
vendor/github.com/kisielk/gotool/go16-18.go
generated
vendored
Normal file
15
vendor/github.com/kisielk/gotool/go16-18.go
generated
vendored
Normal file
@ -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
|
||||
}
|
27
vendor/github.com/kisielk/gotool/internal/load/path.go
generated
vendored
Normal file
27
vendor/github.com/kisielk/gotool/internal/load/path.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
25
vendor/github.com/kisielk/gotool/internal/load/pkg.go
generated
vendored
Normal file
25
vendor/github.com/kisielk/gotool/internal/load/pkg.go
generated
vendored
Normal file
@ -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, ".")
|
||||
}
|
354
vendor/github.com/kisielk/gotool/internal/load/search.go
generated
vendored
Normal file
354
vendor/github.com/kisielk/gotool/internal/load/search.go
generated
vendored
Normal file
@ -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"
|
||||
}
|
56
vendor/github.com/kisielk/gotool/match.go
generated
vendored
Normal file
56
vendor/github.com/kisielk/gotool/match.go
generated
vendored
Normal file
@ -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...)
|
||||
}
|
317
vendor/github.com/kisielk/gotool/match18.go
generated
vendored
Normal file
317
vendor/github.com/kisielk/gotool/match18.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
||||
}
|
48
vendor/github.com/kisielk/gotool/tool.go
generated
vendored
Normal file
48
vendor/github.com/kisielk/gotool/tool.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
27
vendor/mvdan.cc/interfacer/LICENSE
vendored
Normal file
27
vendor/mvdan.cc/interfacer/LICENSE
vendored
Normal file
@ -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.
|
50
vendor/mvdan.cc/interfacer/check/cache.go
vendored
Normal file
50
vendor/mvdan.cc/interfacer/check/cache.go
vendored
Normal file
@ -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)
|
||||
}
|
462
vendor/mvdan.cc/interfacer/check/check.go
vendored
Normal file
462
vendor/mvdan.cc/interfacer/check/check.go
vendored
Normal file
@ -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
|
||||
}
|
170
vendor/mvdan.cc/interfacer/check/types.go
vendored
Normal file
170
vendor/mvdan.cc/interfacer/check/types.go
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
7
vendor/mvdan.cc/lint/.travis.yml
vendored
Normal file
7
vendor/mvdan.cc/lint/.travis.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
|
||||
go_import_path: mvdan.cc/lint
|
27
vendor/mvdan.cc/lint/LICENSE
vendored
Normal file
27
vendor/mvdan.cc/lint/LICENSE
vendored
Normal file
@ -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.
|
27
vendor/mvdan.cc/lint/README.md
vendored
Normal file
27
vendor/mvdan.cc/lint/README.md
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# lint
|
||||
|
||||
[](https://godoc.org/mvdan.cc/lint)
|
||||
[](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
|
28
vendor/mvdan.cc/lint/lint.go
vendored
Normal file
28
vendor/mvdan.cc/lint/lint.go
vendored
Normal file
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user