1 Star 0 Fork 0

Laomo. / golangci-lint

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
govet.go 6.58 KB
一键复制 编辑 原始数据 按行查看 历史
Denis Isaev 提交于 2018-08-18 22:15 . prettify issue texts
package golinters
import (
"context"
"fmt"
"go/ast"
"go/token"
"os"
"os/exec"
"strings"
"time"
"github.com/golangci/golangci-lint/pkg/fsutils"
"github.com/golangci/golangci-lint/pkg/goutils"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/logutils"
"github.com/golangci/golangci-lint/pkg/result"
"github.com/golangci/golangci-lint/pkg/timeutils"
govetAPI "github.com/golangci/govet"
)
type Govet struct{}
func (Govet) Name() string {
return "govet"
}
func (Govet) Desc() string {
return "Vet examines Go source code and reports suspicious constructs, " +
"such as Printf calls whose arguments do not align with the format string"
}
func (g Govet) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) {
var govetIssues []govetAPI.Issue
var err error
if lintCtx.Settings().Govet.UseInstalledPackages {
govetIssues, err = g.runOnInstalledPackages(ctx, lintCtx)
if err != nil {
return nil, fmt.Errorf("can't run govet on installed packages: %s", err)
}
} else {
govetIssues, err = g.runOnSourcePackages(ctx, lintCtx)
if err != nil {
return nil, fmt.Errorf("can't run govet on source packages: %s", err)
}
}
if len(govetIssues) == 0 {
return nil, nil
}
res := make([]result.Issue, 0, len(govetIssues))
for _, i := range govetIssues {
res = append(res, result.Issue{
Pos: i.Pos,
Text: markIdentifiers(i.Message),
FromLinter: g.Name(),
})
}
return res, nil
}
func (g Govet) runOnInstalledPackages(ctx context.Context, lintCtx *linter.Context) ([]govetAPI.Issue, error) {
if err := g.installPackages(ctx, lintCtx); err != nil {
return nil, fmt.Errorf("can't install packages (it's required for govet): %s", err)
}
// TODO: check .S asm files: govet can do it if pass dirs
var govetIssues []govetAPI.Issue
for _, pkg := range lintCtx.PkgProgram.Packages() {
var astFiles []*ast.File
var fset *token.FileSet
for _, fname := range pkg.Files(lintCtx.Cfg.Run.AnalyzeTests) {
af := lintCtx.ASTCache.Get(fname)
if af == nil || af.Err != nil {
return nil, fmt.Errorf("can't get parsed file %q from ast cache: %#v", fname, af)
}
astFiles = append(astFiles, af.F)
fset = af.Fset
}
if len(astFiles) == 0 {
continue
}
issues, err := govetAPI.Analyze(astFiles, fset, nil,
lintCtx.Settings().Govet.CheckShadowing, getPath)
if err != nil {
return nil, err
}
govetIssues = append(govetIssues, issues...)
}
return govetIssues, nil
}
func (g Govet) installPackages(ctx context.Context, lintCtx *linter.Context) error {
inGoRoot, err := goutils.InGoRoot()
if err != nil {
return fmt.Errorf("can't check whether we are in $GOROOT: %s", err)
}
if inGoRoot {
// Go source packages already should be installed into $GOROOT/pkg with go distribution
lintCtx.Log.Infof("In $GOROOT, don't install packages")
return nil
}
if err := g.installNonTestPackages(ctx, lintCtx); err != nil {
return err
}
if err := g.installTestDependencies(ctx, lintCtx); err != nil {
return err
}
return nil
}
func (g Govet) installTestDependencies(ctx context.Context, lintCtx *linter.Context) error {
log := lintCtx.Log
packages := lintCtx.PkgProgram.Packages()
var testDirs []string
for _, pkg := range packages {
dir := pkg.Dir()
if dir == "" {
log.Warnf("Package %#v has empty dir", pkg)
continue
}
if !strings.HasPrefix(dir, ".") {
// go install can't work without that
dir = "./" + dir
}
if len(pkg.TestFiles()) != 0 {
testDirs = append(testDirs, dir)
}
}
if len(testDirs) == 0 {
log.Infof("No test files in packages %#v", packages)
return nil
}
args := append([]string{"test", "-i"}, testDirs...)
return runGoCommand(ctx, log, args...)
}
func (g Govet) installNonTestPackages(ctx context.Context, lintCtx *linter.Context) error {
log := lintCtx.Log
packages := lintCtx.PkgProgram.Packages()
var importPaths []string
for _, pkg := range packages {
if pkg.IsTestOnly() {
// test-only package will be processed by installTestDependencies
continue
}
dir := pkg.Dir()
if dir == "" {
log.Warnf("Package %#v has empty dir", pkg)
continue
}
if !strings.HasPrefix(dir, ".") {
// go install can't work without that
dir = "./" + dir
}
importPaths = append(importPaths, dir)
}
if len(importPaths) == 0 {
log.Infof("No packages to install, all packages: %#v", packages)
return nil
}
// we need type information of dependencies of analyzed packages
// so we pass -i option to install it
if err := runGoInstall(ctx, log, importPaths, true); err != nil {
// try without -i option: go < 1.10 doesn't support this option
// and install dependencies by default.
return runGoInstall(ctx, log, importPaths, false)
}
return nil
}
func runGoInstall(ctx context.Context, log logutils.Log, importPaths []string, withIOption bool) error {
args := []string{"install"}
if withIOption {
args = append(args, "-i")
}
args = append(args, importPaths...)
return runGoCommand(ctx, log, args...)
}
func runGoCommand(ctx context.Context, log logutils.Log, args ...string) error {
argsStr := strings.Join(args, " ")
defer timeutils.Track(time.Now(), log, "go %s", argsStr)
cmd := exec.CommandContext(ctx, "go", args...)
cmd.Env = append([]string{}, os.Environ()...)
cmd.Env = append(cmd.Env, "GOMAXPROCS=1") // don't consume more than 1 cpu
// use .Output but not .Run to capture StdErr in err
_, err := cmd.Output()
if err != nil {
var stderr string
if ee, ok := err.(*exec.ExitError); ok && ee.Stderr != nil {
stderr = ": " + string(ee.Stderr)
}
return fmt.Errorf("can't run [go %s]: %s%s", argsStr, err, stderr)
}
return nil
}
func filterFiles(files []*ast.File, fset *token.FileSet) []*ast.File {
newFiles := make([]*ast.File, 0, len(files))
for _, f := range files {
if !goutils.IsCgoFilename(fset.Position(f.Pos()).Filename) {
newFiles = append(newFiles, f)
}
}
return newFiles
}
func (g Govet) runOnSourcePackages(_ context.Context, lintCtx *linter.Context) ([]govetAPI.Issue, error) {
// TODO: check .S asm files: govet can do it if pass dirs
var govetIssues []govetAPI.Issue
for _, pkg := range lintCtx.Program.InitialPackages() {
if len(pkg.Files) == 0 {
continue
}
filteredFiles := filterFiles(pkg.Files, lintCtx.Program.Fset)
issues, err := govetAPI.Analyze(filteredFiles, lintCtx.Program.Fset, pkg,
lintCtx.Settings().Govet.CheckShadowing, getPath)
if err != nil {
return nil, err
}
govetIssues = append(govetIssues, issues...)
}
return govetIssues, nil
}
func getPath(f *ast.File, fset *token.FileSet) (string, error) {
return fsutils.ShortestRelPath(fset.Position(f.Pos()).Filename, "")
}
1
https://gitee.com/LaomoBK/golangci-lint.git
git@gitee.com:LaomoBK/golangci-lint.git
LaomoBK
golangci-lint
golangci-lint
v1.10.1

搜索帮助