Make fine-grained hashing. (#814)
Speed up golint: don't typecheck packages twice. Relates: #805
This commit is contained in:
parent
f13436112d
commit
48599c64ba
2
go.mod
2
go.mod
@ -17,7 +17,7 @@ require (
|
|||||||
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee
|
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee
|
||||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a
|
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a
|
||||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc
|
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc
|
||||||
github.com/golangci/lint-1 v0.0.0-20190930103755-fad67e08aa89
|
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0
|
||||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca
|
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca
|
||||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770
|
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770
|
||||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21
|
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21
|
||||||
|
4
go.sum
4
go.sum
@ -94,8 +94,8 @@ github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS
|
|||||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
|
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
|
||||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI=
|
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI=
|
||||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
|
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
|
||||||
github.com/golangci/lint-1 v0.0.0-20190930103755-fad67e08aa89 h1:664ewjIQUXDvinFMbAsoH2V2Yvaro/X8BoYpIMTWGXI=
|
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA=
|
||||||
github.com/golangci/lint-1 v0.0.0-20190930103755-fad67e08aa89/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
||||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
|
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
|
||||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
||||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk=
|
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk=
|
||||||
|
@ -17,6 +17,14 @@ import (
|
|||||||
"github.com/golangci/golangci-lint/pkg/timeutils"
|
"github.com/golangci/golangci-lint/pkg/timeutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type HashMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
HashModeNeedOnlySelf HashMode = iota
|
||||||
|
HashModeNeedDirectDeps
|
||||||
|
HashModeNeedAllDeps
|
||||||
|
)
|
||||||
|
|
||||||
// Cache is a per-package data cache. A cached data is invalidated when
|
// Cache is a per-package data cache. A cached data is invalidated when
|
||||||
// package or it's dependencies change.
|
// package or it's dependencies change.
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
@ -46,7 +54,7 @@ func (c *Cache) Trim() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) Put(pkg *packages.Package, key string, data interface{}) error {
|
func (c *Cache) Put(pkg *packages.Package, mode HashMode, key string, data interface{}) error {
|
||||||
var err error
|
var err error
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
c.sw.TrackStage("gob", func() {
|
c.sw.TrackStage("gob", func() {
|
||||||
@ -59,7 +67,7 @@ func (c *Cache) Put(pkg *packages.Package, key string, data interface{}) error {
|
|||||||
var aID cache.ActionID
|
var aID cache.ActionID
|
||||||
|
|
||||||
c.sw.TrackStage("key build", func() {
|
c.sw.TrackStage("key build", func() {
|
||||||
aID, err = c.pkgActionID(pkg)
|
aID, err = c.pkgActionID(pkg, mode)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
subkey, subkeyErr := cache.Subkey(aID, key)
|
subkey, subkeyErr := cache.Subkey(aID, key)
|
||||||
if subkeyErr != nil {
|
if subkeyErr != nil {
|
||||||
@ -85,11 +93,11 @@ func (c *Cache) Put(pkg *packages.Package, key string, data interface{}) error {
|
|||||||
|
|
||||||
var ErrMissing = errors.New("missing data")
|
var ErrMissing = errors.New("missing data")
|
||||||
|
|
||||||
func (c *Cache) Get(pkg *packages.Package, key string, data interface{}) error {
|
func (c *Cache) Get(pkg *packages.Package, mode HashMode, key string, data interface{}) error {
|
||||||
var aID cache.ActionID
|
var aID cache.ActionID
|
||||||
var err error
|
var err error
|
||||||
c.sw.TrackStage("key build", func() {
|
c.sw.TrackStage("key build", func() {
|
||||||
aID, err = c.pkgActionID(pkg)
|
aID, err = c.pkgActionID(pkg, mode)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
subkey, subkeyErr := cache.Subkey(aID, key)
|
subkey, subkeyErr := cache.Subkey(aID, key)
|
||||||
if subkeyErr != nil {
|
if subkeyErr != nil {
|
||||||
@ -125,8 +133,8 @@ func (c *Cache) Get(pkg *packages.Package, key string, data interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) pkgActionID(pkg *packages.Package) (cache.ActionID, error) {
|
func (c *Cache) pkgActionID(pkg *packages.Package, mode HashMode) (cache.ActionID, error) {
|
||||||
hash, err := c.packageHash(pkg)
|
hash, err := c.packageHash(pkg, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cache.ActionID{}, errors.Wrap(err, "failed to get package hash")
|
return cache.ActionID{}, errors.Wrap(err, "failed to get package hash")
|
||||||
}
|
}
|
||||||
@ -144,12 +152,19 @@ func (c *Cache) pkgActionID(pkg *packages.Package) (cache.ActionID, error) {
|
|||||||
// packageHash computes a package's hash. The hash is based on all Go
|
// packageHash computes a package's hash. The hash is based on all Go
|
||||||
// files that make up the package, as well as the hashes of imported
|
// files that make up the package, as well as the hashes of imported
|
||||||
// packages.
|
// packages.
|
||||||
func (c *Cache) packageHash(pkg *packages.Package) (string, error) {
|
func (c *Cache) packageHash(pkg *packages.Package, mode HashMode) (string, error) {
|
||||||
cachedHash, ok := c.pkgHashes.Load(pkg)
|
type hashResults map[HashMode]string
|
||||||
|
hashResI, ok := c.pkgHashes.Load(pkg)
|
||||||
if ok {
|
if ok {
|
||||||
return cachedHash.(string), nil
|
hashRes := hashResI.(hashResults)
|
||||||
|
if _, ok := hashRes[mode]; !ok {
|
||||||
|
return "", fmt.Errorf("no mode %d in hash result", mode)
|
||||||
|
}
|
||||||
|
return hashRes[mode], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hashRes := hashResults{}
|
||||||
|
|
||||||
key, err := cache.NewHash("package hash")
|
key, err := cache.NewHash("package hash")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "failed to make a hash")
|
return "", errors.Wrap(err, "failed to make a hash")
|
||||||
@ -158,13 +173,15 @@ func (c *Cache) packageHash(pkg *packages.Package) (string, error) {
|
|||||||
fmt.Fprintf(key, "pkgpath %s\n", pkg.PkgPath)
|
fmt.Fprintf(key, "pkgpath %s\n", pkg.PkgPath)
|
||||||
for _, f := range pkg.CompiledGoFiles {
|
for _, f := range pkg.CompiledGoFiles {
|
||||||
c.ioSem <- struct{}{}
|
c.ioSem <- struct{}{}
|
||||||
h, err := cache.FileHash(f)
|
h, fErr := cache.FileHash(f)
|
||||||
<-c.ioSem
|
<-c.ioSem
|
||||||
if err != nil {
|
if fErr != nil {
|
||||||
return "", errors.Wrapf(err, "failed to calculate file %s hash", f)
|
return "", errors.Wrapf(fErr, "failed to calculate file %s hash", f)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(key, "file %s %x\n", f, h)
|
fmt.Fprintf(key, "file %s %x\n", f, h)
|
||||||
}
|
}
|
||||||
|
curSum := key.Sum()
|
||||||
|
hashRes[HashModeNeedOnlySelf] = hex.EncodeToString(curSum[:])
|
||||||
|
|
||||||
imps := make([]*packages.Package, 0, len(pkg.Imports))
|
imps := make([]*packages.Package, 0, len(pkg.Imports))
|
||||||
for _, imp := range pkg.Imports {
|
for _, imp := range pkg.Imports {
|
||||||
@ -173,20 +190,40 @@ func (c *Cache) packageHash(pkg *packages.Package) (string, error) {
|
|||||||
sort.Slice(imps, func(i, j int) bool {
|
sort.Slice(imps, func(i, j int) bool {
|
||||||
return imps[i].PkgPath < imps[j].PkgPath
|
return imps[i].PkgPath < imps[j].PkgPath
|
||||||
})
|
})
|
||||||
for _, dep := range imps {
|
|
||||||
if dep.PkgPath == "unsafe" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
depHash, err := c.packageHash(dep)
|
calcDepsHash := func(depMode HashMode) error {
|
||||||
if err != nil {
|
for _, dep := range imps {
|
||||||
return "", errors.Wrapf(err, "failed to calculate hash for dependency %s", dep.Name)
|
if dep.PkgPath == "unsafe" {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Fprintf(key, "import %s %s\n", dep.PkgPath, depHash)
|
depHash, depErr := c.packageHash(dep, depMode)
|
||||||
|
if depErr != nil {
|
||||||
|
return errors.Wrapf(depErr, "failed to calculate hash for dependency %s with mode %d", dep.Name, depMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(key, "import %s %s\n", dep.PkgPath, depHash)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
h := key.Sum()
|
|
||||||
ret := hex.EncodeToString(h[:])
|
if err := calcDepsHash(HashModeNeedOnlySelf); err != nil {
|
||||||
c.pkgHashes.Store(pkg, ret)
|
return "", err
|
||||||
return ret, nil
|
}
|
||||||
|
|
||||||
|
curSum = key.Sum()
|
||||||
|
hashRes[HashModeNeedDirectDeps] = hex.EncodeToString(curSum[:])
|
||||||
|
|
||||||
|
if err := calcDepsHash(HashModeNeedAllDeps); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
curSum = key.Sum()
|
||||||
|
hashRes[HashModeNeedAllDeps] = hex.EncodeToString(curSum[:])
|
||||||
|
|
||||||
|
if _, ok := hashRes[mode]; !ok {
|
||||||
|
return "", fmt.Errorf("invalid mode %d", mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.pkgHashes.Store(pkg, hashRes)
|
||||||
|
return hashRes[mode], nil
|
||||||
}
|
}
|
||||||
|
@ -30,3 +30,5 @@ var (
|
|||||||
Code: Failure,
|
Code: Failure,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 1
|
||||||
|
@ -11,6 +11,9 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/timeutils"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/internal/pkgcache"
|
||||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||||
|
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
@ -332,7 +335,7 @@ func saveIssuesToCache(allPkgs []*packages.Package, pkgsFromCache map[*packages.
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic.AddInt32(&savedIssuesCount, int32(len(encodedIssues)))
|
atomic.AddInt32(&savedIssuesCount, int32(len(encodedIssues)))
|
||||||
if err := lintCtx.PkgCache.Put(pkg, lintResKey, encodedIssues); err != nil {
|
if err := lintCtx.PkgCache.Put(pkg, pkgcache.HashModeNeedAllDeps, lintResKey, encodedIssues); err != nil {
|
||||||
lintCtx.Log.Infof("Failed to save package %s issues (%d) to cache: %s", pkg, len(pkgIssues), err)
|
lintCtx.Log.Infof("Failed to save package %s issues (%d) to cache: %s", pkg, len(pkgIssues), err)
|
||||||
} else {
|
} else {
|
||||||
issuesCacheDebugf("Saved package %s issues (%d) to cache", pkg, len(pkgIssues))
|
issuesCacheDebugf("Saved package %s issues (%d) to cache", pkg, len(pkgIssues))
|
||||||
@ -379,7 +382,7 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context,
|
|||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for pkg := range pkgCh {
|
for pkg := range pkgCh {
|
||||||
var pkgIssues []EncodingIssue
|
var pkgIssues []EncodingIssue
|
||||||
err := lintCtx.PkgCache.Get(pkg, lintResKey, &pkgIssues)
|
err := lintCtx.PkgCache.Get(pkg, pkgcache.HashModeNeedAllDeps, lintResKey, &pkgIssues)
|
||||||
cacheRes := pkgToCacheRes[pkg]
|
cacheRes := pkgToCacheRes[pkg]
|
||||||
cacheRes.loadErr = err
|
cacheRes.loadErr = err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -430,8 +433,11 @@ func loadIssuesFromCache(pkgs []*packages.Package, lintCtx *linter.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Issue, error) {
|
func runAnalyzers(cfg runAnalyzersConfig, lintCtx *linter.Context) ([]result.Issue, error) {
|
||||||
runner := newRunner(cfg.getName(), lintCtx.Log.Child("goanalysis"),
|
log := lintCtx.Log.Child("goanalysis")
|
||||||
lintCtx.PkgCache, lintCtx.LoadGuard, cfg.getLoadMode())
|
sw := timeutils.NewStopwatch("analyzers", log)
|
||||||
|
defer sw.PrintTopStages(10)
|
||||||
|
|
||||||
|
runner := newRunner(cfg.getName(), log, lintCtx.PkgCache, lintCtx.LoadGuard, cfg.getLoadMode(), sw)
|
||||||
|
|
||||||
pkgs := lintCtx.Packages
|
pkgs := lintCtx.Packages
|
||||||
if cfg.useOriginalPackages() {
|
if cfg.useOriginalPackages() {
|
||||||
|
@ -28,6 +28,8 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/timeutils"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/tools/go/analysis"
|
"golang.org/x/tools/go/analysis"
|
||||||
"golang.org/x/tools/go/gcexportdata"
|
"golang.org/x/tools/go/gcexportdata"
|
||||||
@ -80,9 +82,11 @@ type runner struct {
|
|||||||
loadMode LoadMode
|
loadMode LoadMode
|
||||||
passToPkg map[*analysis.Pass]*packages.Package
|
passToPkg map[*analysis.Pass]*packages.Package
|
||||||
passToPkgGuard sync.Mutex
|
passToPkgGuard sync.Mutex
|
||||||
|
sw *timeutils.Stopwatch
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRunner(prefix string, logger logutils.Log, pkgCache *pkgcache.Cache, loadGuard *load.Guard, loadMode LoadMode) *runner {
|
func newRunner(prefix string, logger logutils.Log, pkgCache *pkgcache.Cache, loadGuard *load.Guard,
|
||||||
|
loadMode LoadMode, sw *timeutils.Stopwatch) *runner {
|
||||||
return &runner{
|
return &runner{
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
log: logger,
|
log: logger,
|
||||||
@ -90,6 +94,7 @@ func newRunner(prefix string, logger logutils.Log, pkgCache *pkgcache.Cache, loa
|
|||||||
loadGuard: loadGuard,
|
loadGuard: loadGuard,
|
||||||
loadMode: loadMode,
|
loadMode: loadMode,
|
||||||
passToPkg: map[*analysis.Pass]*packages.Package{},
|
passToPkg: map[*analysis.Pass]*packages.Package{},
|
||||||
|
sw: sw,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,7 +486,9 @@ func (act *action) analyzeSafe() {
|
|||||||
act.a.Name, act.pkg.Name, act.isInitialPkg, act.needAnalyzeSource, p), debug.Stack())
|
act.a.Name, act.pkg.Name, act.isInitialPkg, act.needAnalyzeSource, p), debug.Stack())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
act.analyze()
|
act.r.sw.TrackStage(act.a.Name, func() {
|
||||||
|
act.analyze()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (act *action) analyze() {
|
func (act *action) analyze() {
|
||||||
@ -803,13 +810,13 @@ func (act *action) persistFactsToCache() error {
|
|||||||
factsCacheDebugf("Caching %d facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name)
|
factsCacheDebugf("Caching %d facts for package %q and analyzer %s", len(facts), act.pkg.Name, act.a.Name)
|
||||||
|
|
||||||
key := fmt.Sprintf("%s/facts", analyzer.Name)
|
key := fmt.Sprintf("%s/facts", analyzer.Name)
|
||||||
return act.r.pkgCache.Put(act.pkg, key, facts)
|
return act.r.pkgCache.Put(act.pkg, pkgcache.HashModeNeedAllDeps, key, facts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (act *action) loadPersistedFacts() bool {
|
func (act *action) loadPersistedFacts() bool {
|
||||||
var facts []Fact
|
var facts []Fact
|
||||||
key := fmt.Sprintf("%s/facts", act.a.Name)
|
key := fmt.Sprintf("%s/facts", act.a.Name)
|
||||||
if err := act.r.pkgCache.Get(act.pkg, key, &facts); err != nil {
|
if err := act.r.pkgCache.Get(act.pkg, pkgcache.HashModeNeedAllDeps, key, &facts); err != nil {
|
||||||
if err != pkgcache.ErrMissing {
|
if err != pkgcache.ErrMissing {
|
||||||
act.r.log.Warnf("Failed to get persisted facts: %s", err)
|
act.r.log.Warnf("Failed to get persisted facts: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"go/types"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
lintAPI "github.com/golangci/lint-1"
|
lintAPI "github.com/golangci/lint-1"
|
||||||
@ -14,9 +15,10 @@ import (
|
|||||||
"github.com/golangci/golangci-lint/pkg/result"
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
)
|
)
|
||||||
|
|
||||||
func golintProcessPkg(minConfidence float64, files []*ast.File, fset *token.FileSet) ([]result.Issue, error) {
|
func golintProcessPkg(minConfidence float64, files []*ast.File, fset *token.FileSet,
|
||||||
|
typesPkg *types.Package, typesInfo *types.Info) ([]result.Issue, error) {
|
||||||
l := new(lintAPI.Linter)
|
l := new(lintAPI.Linter)
|
||||||
ps, err := l.LintASTFiles(files, fset)
|
ps, err := l.LintPkg(files, fset, typesPkg, typesInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't lint %d files: %s", len(files), err)
|
return nil, fmt.Errorf("can't lint %d files: %s", len(files), err)
|
||||||
}
|
}
|
||||||
@ -57,7 +59,7 @@ func NewGolint() *goanalysis.Linter {
|
|||||||
nil,
|
nil,
|
||||||
).WithContextSetter(func(lintCtx *linter.Context) {
|
).WithContextSetter(func(lintCtx *linter.Context) {
|
||||||
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
|
analyzer.Run = func(pass *analysis.Pass) (interface{}, error) {
|
||||||
res, err := golintProcessPkg(lintCtx.Settings().Golint.MinConfidence, pass.Files, pass.Fset)
|
res, err := golintProcessPkg(lintCtx.Settings().Golint.MinConfidence, pass.Files, pass.Fset, pass.Pkg, pass.TypesInfo)
|
||||||
if err != nil || len(res) == 0 {
|
if err != nil || len(res) == 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -72,5 +74,5 @@ func NewGolint() *goanalysis.Linter {
|
|||||||
}
|
}
|
||||||
}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
}).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
||||||
return resIssues
|
return resIssues
|
||||||
}).WithLoadMode(goanalysis.LoadModeSyntax)
|
}).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
WithPresets(linter.PresetBugs).
|
WithPresets(linter.PresetBugs).
|
||||||
WithURL("https://github.com/kisielk/errcheck"),
|
WithURL("https://github.com/kisielk/errcheck"),
|
||||||
linter.NewConfig(golinters.NewGolint()).
|
linter.NewConfig(golinters.NewGolint()).
|
||||||
|
WithLoadForGoAnalysis().
|
||||||
WithPresets(linter.PresetStyle).
|
WithPresets(linter.PresetStyle).
|
||||||
WithURL("https://github.com/golang/lint"),
|
WithURL("https://github.com/golang/lint"),
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const noStagesText = "no stages"
|
||||||
|
|
||||||
type Stopwatch struct {
|
type Stopwatch struct {
|
||||||
name string
|
name string
|
||||||
startedAt time.Time
|
startedAt time.Time
|
||||||
@ -33,11 +35,7 @@ type stageDuration struct {
|
|||||||
d time.Duration
|
d time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stopwatch) sprintStages() string {
|
func (s *Stopwatch) stageDurationsSorted() []stageDuration {
|
||||||
if len(s.stages) == 0 {
|
|
||||||
return "no stages"
|
|
||||||
}
|
|
||||||
|
|
||||||
stageDurations := []stageDuration{}
|
stageDurations := []stageDuration{}
|
||||||
for n, d := range s.stages {
|
for n, d := range s.stages {
|
||||||
stageDurations = append(stageDurations, stageDuration{
|
stageDurations = append(stageDurations, stageDuration{
|
||||||
@ -48,6 +46,16 @@ func (s *Stopwatch) sprintStages() string {
|
|||||||
sort.Slice(stageDurations, func(i, j int) bool {
|
sort.Slice(stageDurations, func(i, j int) bool {
|
||||||
return stageDurations[i].d > stageDurations[j].d
|
return stageDurations[i].d > stageDurations[j].d
|
||||||
})
|
})
|
||||||
|
return stageDurations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stopwatch) sprintStages() string {
|
||||||
|
if len(s.stages) == 0 {
|
||||||
|
return noStagesText
|
||||||
|
}
|
||||||
|
|
||||||
|
stageDurations := s.stageDurationsSorted()
|
||||||
|
|
||||||
stagesStrings := []string{}
|
stagesStrings := []string{}
|
||||||
for _, s := range stageDurations {
|
for _, s := range stageDurations {
|
||||||
stagesStrings = append(stagesStrings, fmt.Sprintf("%s: %s", s.name, s.d))
|
stagesStrings = append(stagesStrings, fmt.Sprintf("%s: %s", s.name, s.d))
|
||||||
@ -56,6 +64,22 @@ func (s *Stopwatch) sprintStages() string {
|
|||||||
return fmt.Sprintf("stages: %s", strings.Join(stagesStrings, ", "))
|
return fmt.Sprintf("stages: %s", strings.Join(stagesStrings, ", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Stopwatch) sprintTopStages(n int) string {
|
||||||
|
if len(s.stages) == 0 {
|
||||||
|
return noStagesText
|
||||||
|
}
|
||||||
|
|
||||||
|
stageDurations := s.stageDurationsSorted()
|
||||||
|
|
||||||
|
stagesStrings := []string{}
|
||||||
|
for i := 0; i < len(stageDurations) && i < n; i++ {
|
||||||
|
s := stageDurations[i]
|
||||||
|
stagesStrings = append(stagesStrings, fmt.Sprintf("%s: %s", s.name, s.d))
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("top %d stages: %s", n, strings.Join(stagesStrings, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Stopwatch) Print() {
|
func (s *Stopwatch) Print() {
|
||||||
p := fmt.Sprintf("%s took %s", s.name, time.Since(s.startedAt))
|
p := fmt.Sprintf("%s took %s", s.name, time.Since(s.startedAt))
|
||||||
if len(s.stages) == 0 {
|
if len(s.stages) == 0 {
|
||||||
@ -74,6 +98,14 @@ func (s *Stopwatch) PrintStages() {
|
|||||||
s.log.Infof("%s took %s with %s", s.name, stagesDuration, s.sprintStages())
|
s.log.Infof("%s took %s with %s", s.name, stagesDuration, s.sprintStages())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Stopwatch) PrintTopStages(n int) {
|
||||||
|
var stagesDuration time.Duration
|
||||||
|
for _, s := range s.stages {
|
||||||
|
stagesDuration += s
|
||||||
|
}
|
||||||
|
s.log.Infof("%s took %s with %s", s.name, stagesDuration, s.sprintTopStages(n))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Stopwatch) TrackStage(name string, f func()) {
|
func (s *Stopwatch) TrackStage(name string, f func()) {
|
||||||
startedAt := time.Now()
|
startedAt := time.Now()
|
||||||
f()
|
f()
|
||||||
|
27
vendor/github.com/golangci/lint-1/lint.go
generated
vendored
27
vendor/github.com/golangci/lint-1/lint.go
generated
vendored
@ -118,10 +118,12 @@ func (l *Linter) LintFiles(files map[string][]byte) ([]Problem, error) {
|
|||||||
|
|
||||||
// LintFiles lints a set of files of a single package.
|
// LintFiles lints a set of files of a single package.
|
||||||
// The argument is a map of filename to source.
|
// The argument is a map of filename to source.
|
||||||
func (l *Linter) LintASTFiles(files []*ast.File, fset *token.FileSet) ([]Problem, error) {
|
func (l *Linter) LintPkg(files []*ast.File, fset *token.FileSet, typesPkg *types.Package, typesInfo *types.Info) ([]Problem, error) {
|
||||||
pkg := &pkg{
|
pkg := &pkg{
|
||||||
fset: fset,
|
fset: fset,
|
||||||
files: make(map[string]*file),
|
files: make(map[string]*file),
|
||||||
|
typesPkg: typesPkg,
|
||||||
|
typesInfo: typesInfo,
|
||||||
}
|
}
|
||||||
var pkgName string
|
var pkgName string
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
@ -193,25 +195,6 @@ type pkg struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *pkg) lint() []Problem {
|
func (p *pkg) lint() []Problem {
|
||||||
if err := p.typeCheck(); err != nil {
|
|
||||||
/* TODO(dsymonds): Consider reporting these errors when golint operates on entire packages.
|
|
||||||
if e, ok := err.(types.Error); ok {
|
|
||||||
pos := p.fset.Position(e.Pos)
|
|
||||||
conf := 1.0
|
|
||||||
if strings.Contains(e.Msg, "can't find import: ") {
|
|
||||||
// Golint is probably being run in a context that doesn't support
|
|
||||||
// typechecking (e.g. package files aren't found), so don't warn about it.
|
|
||||||
conf = 0
|
|
||||||
}
|
|
||||||
if conf > 0 {
|
|
||||||
p.errorfAt(pos, conf, category("typechecking"), e.Msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(dsymonds): Abort if !e.Soft?
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
p.scanSortable()
|
p.scanSortable()
|
||||||
p.main = p.isMain()
|
p.main = p.isMain()
|
||||||
|
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -72,7 +72,7 @@ github.com/golangci/gofmt/gofmt
|
|||||||
github.com/golangci/gofmt/goimports
|
github.com/golangci/gofmt/goimports
|
||||||
# github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc
|
# github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc
|
||||||
github.com/golangci/ineffassign
|
github.com/golangci/ineffassign
|
||||||
# github.com/golangci/lint-1 v0.0.0-20190930103755-fad67e08aa89
|
# github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0
|
||||||
github.com/golangci/lint-1
|
github.com/golangci/lint-1
|
||||||
# github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca
|
# github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca
|
||||||
github.com/golangci/maligned
|
github.com/golangci/maligned
|
||||||
|
Loading…
x
Reference in New Issue
Block a user