From c9a92552385e742555fe341f813e6beba93defae Mon Sep 17 00:00:00 2001 From: Isaev Denis Date: Sat, 14 Sep 2019 18:48:18 +0300 Subject: [PATCH] Speed up packages loading (#693) Don't perform extra go env calls in go/packages. Load only needed go env vars in golangci-lint. Stay in sync by enabled analyzers in go vet: remove nilness and atomicalign analyzers, add errorsas analyzer. Don't build SSA for govet. Standalone govet runs 25% faster than before. All runs can be 5-10% faster than before. Relates: #208 --- go.mod | 3 + go.sum | 17 +-- pkg/commands/executor.go | 9 +- pkg/commands/help.go | 2 +- pkg/commands/run.go | 8 +- pkg/golinters/govet.go | 13 +- pkg/golinters/megacheck.go | 19 +-- pkg/goutil/env.go | 24 +++- pkg/lint/linter/config.go | 11 +- pkg/lint/lintersdb/enabled_set.go | 2 +- pkg/lint/lintersdb/manager.go | 9 +- pkg/lint/load.go | 15 ++- pkg/logutils/logutils.go | 5 +- pkg/logutils/stderr_log.go | 9 +- pkg/result/processors/cgo.go | 2 +- test/enabled_linters_test.go | 6 +- .../passes/atomicalign/atomicalign.go | 126 ------------------ .../go/analysis/passes/errorsas/errorsas.go | 75 +++++++++++ .../golang.org/x/tools/go/packages/golist.go | 40 ++++-- vendor/modules.txt | 4 +- 20 files changed, 197 insertions(+), 202 deletions(-) delete mode 100644 vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go diff --git a/go.mod b/go.mod index 477e2693..84daa54f 100644 --- a/go.mod +++ b/go.mod @@ -50,3 +50,6 @@ require ( mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34 ) + +// https://github.com/golang/tools/pull/160 +replace golang.org/x/tools => github.com/golangci/tools v0.0.0-20190914130248-e9260b99c8f1 diff --git a/go.sum b/go.sum index 4ad2756d..92b2e6b5 100644 --- a/go.sum +++ b/go.sum @@ -106,6 +106,8 @@ github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21 h1:leSNB7iYzLYSS github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0 h1:HVfrLniijszjS1aiNg8JbBMO2+E1WIQ+j/gL4SQqGPg= github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/tools v0.0.0-20190914130248-e9260b99c8f1 h1:8eGJVbBRoAvCh/YZq6n11s9WJkIgWKa/iTNq+R0UrNw= +github.com/golangci/tools v0.0.0-20190914130248-e9260b99c8f1/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -283,21 +285,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911022129-16c5e0f7d110/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678 h1:rM1Udd0CgtYI3KUIhu9ROz0QCqjW+n/ODp/hH7c60Xc= -golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= diff --git a/pkg/commands/executor.go b/pkg/commands/executor.go index 71845691..bfe6476c 100644 --- a/pkg/commands/executor.go +++ b/pkg/commands/executor.go @@ -31,6 +31,7 @@ type Executor struct { goenv *goutil.Env fileCache *fsutils.FileCache lineCache *fsutils.LineCache + debugf logutils.DebugFunc } func NewExecutor(version, commit, date string) *Executor { @@ -40,8 +41,10 @@ func NewExecutor(version, commit, date string) *Executor { commit: commit, date: date, DBManager: lintersdb.NewManager(nil), + debugf: logutils.Debug("exec"), } + e.debugf("Starting execution...") e.log = report.NewLogWrapper(logutils.NewStderrLog(""), &e.reportData) // to setup log level early we need to parse config from command line extra time to @@ -100,10 +103,12 @@ func NewExecutor(version, commit, date string) *Executor { e.fileCache = fsutils.NewFileCache() e.lineCache = fsutils.NewLineCache(e.fileCache) e.contextLoader = lint.NewContextLoader(e.cfg, e.log.Child("loader"), e.goenv, e.lineCache, e.fileCache) - + e.debugf("Initialized executor") return e } func (e *Executor) Execute() error { - return e.rootCmd.Execute() + err := e.rootCmd.Execute() + e.debugf("Finished execution") + return err } diff --git a/pkg/commands/help.go b/pkg/commands/help.go index 078e60e8..4e5ff6e0 100644 --- a/pkg/commands/help.go +++ b/pkg/commands/help.go @@ -46,7 +46,7 @@ func printLinterConfigs(lcs []*linter.Config) { altNamesStr = fmt.Sprintf(" (%s)", strings.Join(lc.AlternativeNames, ", ")) } fmt.Fprintf(logutils.StdOut, "%s%s: %s [fast: %t, auto-fix: %t]\n", color.YellowString(lc.Name()), - altNamesStr, lc.Linter.Desc(), !lc.NeedsSSARepr, lc.CanAutoFix) + altNamesStr, lc.Linter.Desc(), !lc.NeedsDepsTypeInfo, lc.CanAutoFix) } } diff --git a/pkg/commands/run.go b/pkg/commands/run.go index 565169eb..8f5186d0 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -406,7 +406,7 @@ func (e *Executor) executeRun(_ *cobra.Command, args []string) { defer cancel() if needTrackResources { - go watchResources(ctx, trackResourcesEndCh, e.log) + go watchResources(ctx, trackResourcesEndCh, e.log, e.debugf) } if err := e.runAndPrint(ctx, args); err != nil { @@ -447,11 +447,12 @@ func (e *Executor) setupExitCode(ctx context.Context) { } } -func watchResources(ctx context.Context, done chan struct{}, logger logutils.Log) { +func watchResources(ctx context.Context, done chan struct{}, logger logutils.Log, debugf logutils.DebugFunc) { startedAt := time.Now() + debugf("Started tracking time") var rssValues []uint64 - ticker := time.NewTicker(100 * time.Millisecond) + ticker := time.NewTicker(10 * time.Millisecond) defer ticker.Stop() logEveryRecord := os.Getenv("GL_MEM_LOG_EVERY") == "1" @@ -474,6 +475,7 @@ func watchResources(ctx context.Context, done chan struct{}, logger logutils.Log select { case <-ctx.Done(): stop = true + debugf("Stopped resources tracking") case <-ticker.C: // track every second } diff --git a/pkg/golinters/govet.go b/pkg/golinters/govet.go index 683d1a96..1aae17dc 100644 --- a/pkg/golinters/govet.go +++ b/pkg/golinters/govet.go @@ -11,12 +11,12 @@ import ( "golang.org/x/tools/go/analysis/passes/asmdecl" "golang.org/x/tools/go/analysis/passes/assign" "golang.org/x/tools/go/analysis/passes/atomic" - "golang.org/x/tools/go/analysis/passes/atomicalign" "golang.org/x/tools/go/analysis/passes/bools" "golang.org/x/tools/go/analysis/passes/buildtag" "golang.org/x/tools/go/analysis/passes/cgocall" "golang.org/x/tools/go/analysis/passes/composite" "golang.org/x/tools/go/analysis/passes/copylock" + "golang.org/x/tools/go/analysis/passes/errorsas" "golang.org/x/tools/go/analysis/passes/httpresponse" "golang.org/x/tools/go/analysis/passes/loopclosure" "golang.org/x/tools/go/analysis/passes/lostcancel" @@ -31,8 +31,6 @@ import ( "golang.org/x/tools/go/analysis/passes/unreachable" "golang.org/x/tools/go/analysis/passes/unsafeptr" "golang.org/x/tools/go/analysis/passes/unusedresult" - - "github.com/golangci/golangci-lint/pkg/golinters/goanalysis/passes/nilness" ) func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter { @@ -41,12 +39,12 @@ func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter { asmdecl.Analyzer, assign.Analyzer, atomic.Analyzer, - atomicalign.Analyzer, bools.Analyzer, buildtag.Analyzer, cgocall.Analyzer, composite.Analyzer, copylock.Analyzer, + errorsas.Analyzer, httpresponse.Analyzer, loopclosure.Analyzer, lostcancel.Analyzer, @@ -60,13 +58,6 @@ func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter { unreachable.Analyzer, unsafeptr.Analyzer, unusedresult.Analyzer, - - // for debugging: - // findcall.Analyzer, - // pkgfact.Analyzer, - - // uses SSA: - nilness.Analyzer, } var settings map[string]map[string]interface{} diff --git a/pkg/golinters/megacheck.go b/pkg/golinters/megacheck.go index d4bf8604..937e10cf 100644 --- a/pkg/golinters/megacheck.go +++ b/pkg/golinters/megacheck.go @@ -144,15 +144,16 @@ func (MegacheckMetalinter) BuildLinterConfig(enabledChildren []string) (*linter. // TODO: merge linter.Config and linter.Linter or refactor it in another way return &linter.Config{ - Linter: m, - EnabledByDefault: false, - NeedsTypeInfo: true, - NeedsSSARepr: true, - InPresets: []string{linter.PresetStyle, linter.PresetBugs, linter.PresetUnused}, - Speed: 1, - AlternativeNames: nil, - OriginalURL: "", - ParentLinterName: "", + Linter: m, + EnabledByDefault: false, + NeedsTypeInfo: true, + NeedsDepsTypeInfo: true, + NeedsSSARepr: true, + InPresets: []string{linter.PresetStyle, linter.PresetBugs, linter.PresetUnused}, + Speed: 1, + AlternativeNames: nil, + OriginalURL: "", + ParentLinterName: "", }, nil } diff --git a/pkg/goutil/env.go b/pkg/goutil/env.go index e0936224..1c05b980 100644 --- a/pkg/goutil/env.go +++ b/pkg/goutil/env.go @@ -5,12 +5,21 @@ import ( "encoding/json" "os" "os/exec" + "strings" + "time" "github.com/pkg/errors" "github.com/golangci/golangci-lint/pkg/logutils" ) +type EnvKey string + +const ( + EnvGoCache EnvKey = "GOCACHE" + EnvGoRoot EnvKey = "GOROOT" +) + type Env struct { vars map[string]string log logutils.Log @@ -26,24 +35,27 @@ func NewEnv(log logutils.Log) *Env { } func (e *Env) Discover(ctx context.Context) error { - out, err := exec.CommandContext(ctx, "go", "env", "-json").Output() + startedAt := time.Now() + args := []string{"env", "-json"} + args = append(args, string(EnvGoCache), string(EnvGoRoot)) + out, err := exec.CommandContext(ctx, "go", args...).Output() if err != nil { return errors.Wrap(err, "failed to run 'go env'") } if err = json.Unmarshal(out, &e.vars); err != nil { - return errors.Wrap(err, "failed to parse go env json") + return errors.Wrapf(err, "failed to parse 'go %s' json", strings.Join(args, " ")) } - e.debugf("Read go env: %#v", e.vars) + e.debugf("Read go env for %s: %#v", time.Since(startedAt), e.vars) return nil } -func (e Env) Get(k string) string { - envValue := os.Getenv(k) +func (e Env) Get(k EnvKey) string { + envValue := os.Getenv(string(k)) if envValue != "" { return envValue } - return e.vars[k] + return e.vars[string(k)] } diff --git a/pkg/lint/linter/config.go b/pkg/lint/linter/config.go index 32848eca..75a281ad 100644 --- a/pkg/lint/linter/config.go +++ b/pkg/lint/linter/config.go @@ -13,8 +13,9 @@ type Config struct { Linter Linter EnabledByDefault bool - NeedsTypeInfo bool - NeedsSSARepr bool + NeedsTypeInfo bool + NeedsDepsTypeInfo bool + NeedsSSARepr bool InPresets []string Speed int // more value means faster execution of linter @@ -30,6 +31,12 @@ func (lc *Config) WithTypeInfo() *Config { return lc } +func (lc *Config) WithDepsTypeInfo() *Config { + lc.NeedsTypeInfo = true + lc.NeedsDepsTypeInfo = true + return lc +} + func (lc *Config) WithSSA() *Config { lc.NeedsTypeInfo = true lc.NeedsSSARepr = true diff --git a/pkg/lint/lintersdb/enabled_set.go b/pkg/lint/lintersdb/enabled_set.go index 3799912f..e4f3d154 100644 --- a/pkg/lint/lintersdb/enabled_set.go +++ b/pkg/lint/lintersdb/enabled_set.go @@ -51,7 +51,7 @@ func (es EnabledSet) build(lcfg *config.Linters, enabledByDefaultLinters []*lint // It should be before --enable and --disable to be able to enable or disable specific linter. if lcfg.Fast { for name := range resultLintersSet { - if es.m.GetLinterConfig(name).NeedsSSARepr { + if es.m.GetLinterConfig(name).NeedsDepsTypeInfo { delete(resultLintersSet, name) } } diff --git a/pkg/lint/lintersdb/manager.go b/pkg/lint/lintersdb/manager.go index c1d19bb3..a1e7bcfa 100644 --- a/pkg/lint/lintersdb/manager.go +++ b/pkg/lint/lintersdb/manager.go @@ -85,12 +85,13 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { } lcs := []*linter.Config{ linter.NewConfig(golinters.NewGovet(govetCfg)). - WithSSA(). // TODO: extract from the linter config and don't build SSA, just use LoadAllSyntax mode + WithDepsTypeInfo(). WithPresets(linter.PresetBugs). WithSpeed(4). WithAlternativeNames("vet", "vetshadow"). WithURL("https://golang.org/cmd/vet/"), linter.NewConfig(golinters.NewBodyclose()). + WithDepsTypeInfo(). WithSSA(). WithPresets(linter.PresetPerformance, linter.PresetBugs). WithSpeed(4). @@ -106,21 +107,25 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithURL("https://github.com/golang/lint"), linter.NewConfig(golinters.NewStaticcheck()). + WithDepsTypeInfo(). WithSSA(). WithPresets(linter.PresetBugs). WithSpeed(2). WithURL("https://staticcheck.io/"), linter.NewConfig(golinters.NewUnused()). + WithDepsTypeInfo(). WithSSA(). WithPresets(linter.PresetUnused). WithSpeed(5). WithURL("https://github.com/dominikh/go-tools/tree/master/cmd/unused"), linter.NewConfig(golinters.NewGosimple()). + WithDepsTypeInfo(). WithSSA(). WithPresets(linter.PresetStyle). WithSpeed(5). WithURL("https://github.com/dominikh/go-tools/tree/master/cmd/gosimple"), linter.NewConfig(golinters.NewStylecheck()). + WithDepsTypeInfo(). WithSSA(). WithPresets(linter.PresetStyle). WithSpeed(5). @@ -143,6 +148,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { WithSpeed(10). WithURL("https://github.com/opennota/check"), linter.NewConfig(golinters.Interfacer{}). + WithDepsTypeInfo(). WithSSA(). WithPresets(linter.PresetStyle). WithSpeed(6). @@ -211,6 +217,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config { linter.NewConfig(golinters.Unparam{}). WithPresets(linter.PresetUnused). WithSpeed(3). + WithDepsTypeInfo(). WithSSA(). WithURL("https://github.com/mvdan/unparam"), linter.NewConfig(golinters.Nakedret{}). diff --git a/pkg/lint/load.go b/pkg/lint/load.go index b4229ad9..a7344773 100644 --- a/pkg/lint/load.go +++ b/pkg/lint/load.go @@ -53,7 +53,7 @@ func NewContextLoader(cfg *config.Config, log logutils.Log, goenv *goutil.Env, func (cl ContextLoader) prepareBuildContext() { // Set GOROOT to have working cross-compilation: cross-compiled binaries // have invalid GOROOT. XXX: can't use runtime.GOROOT(). - goroot := cl.goenv.Get("GOROOT") + goroot := cl.goenv.Get(goutil.EnvGoRoot) if goroot == "" { return } @@ -149,7 +149,7 @@ func (cl ContextLoader) findLoadMode(linters []*linter.Config) packages.LoadMode if lc.NeedsTypeInfo { loadMode |= packages.NeedImports | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedTypesInfo | packages.NeedSyntax } - if lc.NeedsSSARepr { + if lc.NeedsDepsTypeInfo { loadMode |= packages.NeedDeps } } @@ -349,6 +349,15 @@ func (cl ContextLoader) filterDuplicatePackages(pkgs []*packages.Package) []*pac return retPkgs } +func needSSA(linters []*linter.Config) bool { + for _, lc := range linters { + if lc.NeedsSSARepr { + return true + } + } + return false +} + //nolint:gocyclo func (cl ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*linter.Context, error) { loadMode := cl.findLoadMode(linters) @@ -369,7 +378,7 @@ func (cl ContextLoader) Load(ctx context.Context, linters []*linter.Config) (*li } var ssaProg *ssa.Program - if loadMode&packages.NeedDeps != 0 { + if needSSA(linters) { ssaProg = cl.buildSSAProgram(deduplicatedPkgs) } diff --git a/pkg/logutils/logutils.go b/pkg/logutils/logutils.go index 7dd23e23..93c9873d 100644 --- a/pkg/logutils/logutils.go +++ b/pkg/logutils/logutils.go @@ -30,9 +30,10 @@ func Debug(tag string) DebugFunc { return nopDebugf } + logger := NewStderrLog(tag) + logger.SetLevel(LogLevelDebug) + return func(format string, args ...interface{}) { - logger := NewStderrLog(tag) - logger.SetLevel(LogLevelDebug) logger.Debugf(format, args...) } } diff --git a/pkg/logutils/stderr_log.go b/pkg/logutils/stderr_log.go index 8bf8292d..a8f0d40b 100644 --- a/pkg/logutils/stderr_log.go +++ b/pkg/logutils/stderr_log.go @@ -3,6 +3,7 @@ package logutils import ( "fmt" "os" + "time" "github.com/sirupsen/logrus" //nolint:depguard @@ -36,9 +37,15 @@ func NewStderrLog(name string) *StderrLog { } sl.logger.Out = StdErr - sl.logger.Formatter = &logrus.TextFormatter{ + formatter := &logrus.TextFormatter{ DisableTimestamp: true, // `INFO[0007] msg` -> `INFO msg` } + if os.Getenv("LOG_TIMESTAMP") == "1" { + formatter.DisableTimestamp = false + formatter.FullTimestamp = true + formatter.TimestampFormat = time.StampMilli + } + sl.logger.Formatter = formatter return sl } diff --git a/pkg/result/processors/cgo.go b/pkg/result/processors/cgo.go index 2ce45877..c8793871 100644 --- a/pkg/result/processors/cgo.go +++ b/pkg/result/processors/cgo.go @@ -18,7 +18,7 @@ var _ Processor = Cgo{} func NewCgo(goenv *goutil.Env) *Cgo { return &Cgo{ - goCacheDir: goenv.Get("GOCACHE"), + goCacheDir: goenv.Get(goutil.EnvGoCache), } } diff --git a/test/enabled_linters_test.go b/test/enabled_linters_test.go index 13068856..4eb5574e 100644 --- a/test/enabled_linters_test.go +++ b/test/enabled_linters_test.go @@ -25,7 +25,7 @@ func getEnabledByDefaultFastLintersExcept(except ...string) []string { ebdl := m.GetAllEnabledByDefaultLinters() ret := []string{} for _, lc := range ebdl { - if lc.NeedsSSARepr { + if lc.NeedsDepsTypeInfo { continue } @@ -41,7 +41,7 @@ func getAllFastLintersWith(with ...string) []string { linters := lintersdb.NewManager(nil).GetAllSupportedLinterConfigs() ret := append([]string{}, with...) for _, lc := range linters { - if lc.NeedsSSARepr { + if lc.NeedsDepsTypeInfo { continue } ret = append(ret, lc.Name()) @@ -64,7 +64,7 @@ func getEnabledByDefaultFastLintersWith(with ...string) []string { ebdl := lintersdb.NewManager(nil).GetAllEnabledByDefaultLinters() ret := append([]string{}, with...) for _, lc := range ebdl { - if lc.NeedsSSARepr { + if lc.NeedsDepsTypeInfo { continue } diff --git a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go b/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go deleted file mode 100644 index d3fc3e2d..00000000 --- a/vendor/golang.org/x/tools/go/analysis/passes/atomicalign/atomicalign.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package atomicalign defines an Analyzer that checks for non-64-bit-aligned -// arguments to sync/atomic functions. On non-32-bit platforms, those functions -// panic if their argument variables are not 64-bit aligned. It is therefore -// the caller's responsibility to arrange for 64-bit alignment of such variables. -// See https://golang.org/pkg/sync/atomic/#pkg-note-BUG -package atomicalign - -import ( - "go/ast" - "go/token" - "go/types" - - "golang.org/x/tools/go/analysis" - "golang.org/x/tools/go/analysis/passes/inspect" - "golang.org/x/tools/go/ast/inspector" -) - -var Analyzer = &analysis.Analyzer{ - Name: "atomicalign", - Doc: "check for non-64-bits-aligned arguments to sync/atomic functions", - Requires: []*analysis.Analyzer{inspect.Analyzer}, - Run: run, -} - -func run(pass *analysis.Pass) (interface{}, error) { - if 8*pass.TypesSizes.Sizeof(types.Typ[types.Uintptr]) == 64 { - return nil, nil // 64-bit platform - } - if imports(pass.Pkg, "sync/atomic") == nil { - return nil, nil // doesn't directly import sync/atomic - } - - inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) - nodeFilter := []ast.Node{ - (*ast.CallExpr)(nil), - } - - inspect.Preorder(nodeFilter, func(node ast.Node) { - call := node.(*ast.CallExpr) - sel, ok := call.Fun.(*ast.SelectorExpr) - if !ok { - return - } - pkgIdent, ok := sel.X.(*ast.Ident) - if !ok { - return - } - pkgName, ok := pass.TypesInfo.Uses[pkgIdent].(*types.PkgName) - if !ok || pkgName.Imported().Path() != "sync/atomic" { - return - } - - switch sel.Sel.Name { - case "AddInt64", "AddUint64", - "LoadInt64", "LoadUint64", - "StoreInt64", "StoreUint64", - "SwapInt64", "SwapUint64", - "CompareAndSwapInt64", "CompareAndSwapUint64": - - // For all the listed functions, the expression to check is always the first function argument. - check64BitAlignment(pass, sel.Sel.Name, call.Args[0]) - } - }) - - return nil, nil -} - -func check64BitAlignment(pass *analysis.Pass, funcName string, arg ast.Expr) { - // Checks the argument is made of the address operator (&) applied to - // to a struct field (as opposed to a variable as the first word of - // uint64 and int64 variables can be relied upon to be 64-bit aligned. - unary, ok := arg.(*ast.UnaryExpr) - if !ok || unary.Op != token.AND { - return - } - - // Retrieve the types.Struct in order to get the offset of the - // atomically accessed field. - sel, ok := unary.X.(*ast.SelectorExpr) - if !ok { - return - } - tvar, ok := pass.TypesInfo.Selections[sel].Obj().(*types.Var) - if !ok || !tvar.IsField() { - return - } - - stype, ok := pass.TypesInfo.Types[sel.X].Type.Underlying().(*types.Struct) - if !ok { - return - } - - var offset int64 - var fields []*types.Var - for i := 0; i < stype.NumFields(); i++ { - f := stype.Field(i) - fields = append(fields, f) - if f == tvar { - // We're done, this is the field we were looking for, - // no need to fill the fields slice further. - offset = pass.TypesSizes.Offsetsof(fields)[i] - break - } - } - if offset&7 == 0 { - return // 64-bit aligned - } - - pass.Reportf(arg.Pos(), "address of non 64-bit aligned field .%s passed to atomic.%s", tvar.Name(), funcName) -} - -// imports reports whether pkg has path among its direct imports. -// It returns the imported package if so, or nil if not. -// copied from passes/cgocall. -func imports(pkg *types.Package, path string) *types.Package { - for _, imp := range pkg.Imports() { - if imp.Path() == path { - return imp - } - } - return nil -} diff --git a/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go new file mode 100644 index 00000000..01abc700 --- /dev/null +++ b/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go @@ -0,0 +1,75 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The errorsas package defines an Analyzer that checks that the second argument to +// errors.As is a pointer to a type implementing error. +package errorsas + +import ( + "go/ast" + "go/types" + + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/go/analysis/passes/inspect" + "golang.org/x/tools/go/ast/inspector" + "golang.org/x/tools/go/types/typeutil" +) + +const doc = `report passing non-pointer or non-error values to errors.As + +The errorsas analysis reports calls to errors.As where the type +of the second argument is not a pointer to a type implementing error.` + +var Analyzer = &analysis.Analyzer{ + Name: "errorsas", + Doc: doc, + Requires: []*analysis.Analyzer{inspect.Analyzer}, + Run: run, +} + +func run(pass *analysis.Pass) (interface{}, error) { + switch pass.Pkg.Path() { + case "errors", "errors_test": + // These packages know how to use their own APIs. + // Sometimes they are testing what happens to incorrect programs. + return nil, nil + } + + inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) + + nodeFilter := []ast.Node{ + (*ast.CallExpr)(nil), + } + inspect.Preorder(nodeFilter, func(n ast.Node) { + call := n.(*ast.CallExpr) + fn := typeutil.StaticCallee(pass.TypesInfo, call) + if fn == nil { + return // not a static call + } + if len(call.Args) < 2 { + return // not enough arguments, e.g. called with return values of another function + } + if fn.FullName() == "errors.As" && !pointerToInterfaceOrError(pass, call.Args[1]) { + pass.Reportf(call.Pos(), "second argument to errors.As must be a pointer to an interface or a type implementing error") + } + }) + return nil, nil +} + +var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface) + +// pointerToInterfaceOrError reports whether the type of e is a pointer to an interface or a type implementing error, +// or is the empty interface. +func pointerToInterfaceOrError(pass *analysis.Pass, e ast.Expr) bool { + t := pass.TypesInfo.Types[e].Type + if it, ok := t.Underlying().(*types.Interface); ok && it.NumMethods() == 0 { + return true + } + pt, ok := t.Underlying().(*types.Pointer) + if !ok { + return false + } + _, ok = pt.Elem().Underlying().(*types.Interface) + return ok || types.Implements(pt.Elem(), errorType) +} diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go index 6b341b7e..ed851ef6 100644 --- a/vendor/golang.org/x/tools/go/packages/golist.go +++ b/vendor/golang.org/x/tools/go/packages/golist.go @@ -112,19 +112,33 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { // start fetching rootDirs var info goInfo - var rootDirsReady, envReady = make(chan struct{}), make(chan struct{}) - go func() { - info.rootDirs = determineRootDirs(cfg) - close(rootDirsReady) - }() - go func() { - info.env = determineEnv(cfg) - close(envReady) - }() - getGoInfo := func() *goInfo { - <-rootDirsReady - <-envReady - return &info + var getGoInfo func() *goInfo + if len(cfg.Overlay) != 0 { + // Both of determineEnv and determineRootDirs calls take 100-200ms on MacBook Pro. + // Optimize: right now they are needed in most cases only for overlay processing. + + var rootDirsReady, envReady = make(chan struct{}), make(chan struct{}) + go func() { + info.rootDirs = determineRootDirs(cfg) + close(rootDirsReady) + }() + go func() { + info.env = determineEnv(cfg) + close(envReady) + }() + getGoInfo = func() *goInfo { + <-rootDirsReady + <-envReady + return &info + } + } else { + var determineRootDirsOnce sync.Once + getGoInfo = func() *goInfo { + determineRootDirsOnce.Do(func() { + info.rootDirs = determineRootDirs(cfg) + }) + return &info + } } // always pass getGoInfo to golistDriver diff --git a/vendor/modules.txt b/vendor/modules.txt index 5d3b90ce..ad95376b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -202,12 +202,11 @@ golang.org/x/sys/windows golang.org/x/text/transform golang.org/x/text/unicode/norm golang.org/x/text/width -# golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678 +# golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678 => github.com/golangci/tools v0.0.0-20190914130248-e9260b99c8f1 golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/passes/asmdecl golang.org/x/tools/go/analysis/passes/assign golang.org/x/tools/go/analysis/passes/atomic -golang.org/x/tools/go/analysis/passes/atomicalign golang.org/x/tools/go/analysis/passes/bools golang.org/x/tools/go/analysis/passes/buildssa golang.org/x/tools/go/analysis/passes/buildtag @@ -215,6 +214,7 @@ golang.org/x/tools/go/analysis/passes/cgocall golang.org/x/tools/go/analysis/passes/composite golang.org/x/tools/go/analysis/passes/copylock golang.org/x/tools/go/analysis/passes/ctrlflow +golang.org/x/tools/go/analysis/passes/errorsas golang.org/x/tools/go/analysis/passes/httpresponse golang.org/x/tools/go/analysis/passes/inspect golang.org/x/tools/go/analysis/passes/internal/analysisutil