Denis Isaev ac77eaac68 Fix #282, fix #209: revert goimports commit
ed64e33c8c8bc9a919e2b85a1a08225b5ae59d70. Also add tests
for local mode of goimports and do refactoring of tests.
2018-11-10 11:46:37 +03:00

112 lines
2.6 KiB
Go

package golinters
import (
"context"
"fmt"
"go/ast"
"go/types"
"path/filepath"
"runtime"
"runtime/debug"
"strings"
"sync"
_ "github.com/go-critic/checkers" // this import register checkers
"github.com/go-lintpack/lintpack"
"golang.org/x/tools/go/loader"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/result"
)
type Gocritic struct{}
func (Gocritic) Name() string {
return "gocritic"
}
func (Gocritic) Desc() string {
return "The most opinionated Go source code linter"
}
func (lint Gocritic) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
sizes := types.SizesFor("gc", runtime.GOARCH)
lintpackCtx := lintpack.NewContext(lintCtx.Program.Fset, sizes)
s := lintCtx.Settings().Gocritic
var enabledCheckers []*lintpack.Checker
for _, info := range lintpack.GetCheckersInfo() {
if !s.IsCheckEnabled(info.Name) {
continue
}
params := s.SettingsPerCheck[strings.ToLower(info.Name)]
c := lintpack.NewChecker(lintpackCtx, info, params)
enabledCheckers = append(enabledCheckers, c)
}
issuesCh := make(chan result.Issue, 1024)
var panicErr error
go func() {
defer func() {
if err := recover(); err != nil {
panicErr = fmt.Errorf("panic occured: %s", err)
lintCtx.Log.Warnf("Panic: %s", debug.Stack())
}
}()
for _, pkgInfo := range lintCtx.Program.InitialPackages() {
lintpackCtx.SetPackageInfo(&pkgInfo.Info, pkgInfo.Pkg)
lint.runOnPackage(lintpackCtx, enabledCheckers, pkgInfo, issuesCh)
}
close(issuesCh)
}()
var res []result.Issue
for i := range issuesCh {
res = append(res, i)
}
if panicErr != nil {
return nil, panicErr
}
return res, nil
}
func (lint Gocritic) runOnPackage(lintpackCtx *lintpack.Context, checkers []*lintpack.Checker,
pkgInfo *loader.PackageInfo, ret chan<- result.Issue) {
for _, f := range pkgInfo.Files {
filename := filepath.Base(lintpackCtx.FileSet.Position(f.Pos()).Filename)
lintpackCtx.SetFileInfo(filename, f)
lint.runOnFile(lintpackCtx, f, checkers, ret)
}
}
func (lint Gocritic) runOnFile(ctx *lintpack.Context, f *ast.File, checkers []*lintpack.Checker,
ret chan<- result.Issue) {
var wg sync.WaitGroup
wg.Add(len(checkers))
for _, c := range checkers {
// All checkers are expected to use *lint.Context
// as read-only structure, so no copying is required.
go func(c *lintpack.Checker) {
defer wg.Done()
for _, warn := range c.Check(f) {
pos := ctx.FileSet.Position(warn.Node.Pos())
ret <- result.Issue{
Pos: pos,
Text: fmt.Sprintf("%s: %s", c.Info.Name, warn.Text),
FromLinter: lint.Name(),
}
}
}(c)
}
wg.Wait()
}