group of fixes after running on golang source code
This commit is contained in:
parent
6f384926cf
commit
d993d3a264
4
Gopkg.lock
generated
4
Gopkg.lock
generated
@ -101,7 +101,7 @@
|
||||
"lib/cfg",
|
||||
"lib/whitelist"
|
||||
]
|
||||
revision = "31bebf17d90d40b728c41fecdd5acf5fb8654fc7"
|
||||
revision = "1a9ab8120ec96a014df3afab2d6c47f7e12d8928"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@ -140,7 +140,7 @@
|
||||
"golangci",
|
||||
"internal/errcheck"
|
||||
]
|
||||
revision = "7a3d63cfc6fbd9e46f2e551f9b8d1e9c69bffab1"
|
||||
revision = "d2c0791055c651c4bb6798ee1aacbd27ad377aa8"
|
||||
source = "github.com/golangci/errcheck"
|
||||
|
||||
[[projects]]
|
||||
|
@ -3,6 +3,7 @@ package commands
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/golangci/golangci-lint/pkg"
|
||||
@ -20,7 +21,7 @@ func (e *Executor) initLinters() {
|
||||
|
||||
func printLinterConfigs(lcs []pkg.LinterConfig) {
|
||||
for _, lc := range lcs {
|
||||
fmt.Printf("%s: %s\n", color.YellowString(lc.Linter.Name()), lc.Desc)
|
||||
fmt.Printf("%s: %s\n", color.YellowString(lc.Linter.Name()), lc.Linter.Desc())
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,5 +40,15 @@ func (e Executor) executeLinters(cmd *cobra.Command, args []string) {
|
||||
color.Red("\nDisabled by default linters:\n")
|
||||
printLinterConfigs(disabledLCs)
|
||||
|
||||
color.Green("\nLinters presets:")
|
||||
for _, p := range pkg.AllPresets() {
|
||||
linters := pkg.GetAllLintersForPreset(p)
|
||||
linterNames := []string{}
|
||||
for _, linter := range linters {
|
||||
linterNames = append(linterNames, linter.Name())
|
||||
}
|
||||
fmt.Printf("%s: %s\n", color.YellowString(p), strings.Join(linterNames, ", "))
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/token"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
@ -38,16 +39,16 @@ func (e *Executor) initRun() {
|
||||
fmt.Sprintf("Format of output: %s", strings.Join(config.OutFormats, "|")))
|
||||
runCmd.Flags().BoolVar(&rc.PrintIssuedLine, "print-issued-lines", true, "Print lines of code with issue")
|
||||
runCmd.Flags().BoolVar(&rc.PrintLinterName, "print-linter-name", true, "Print linter name in issue line")
|
||||
runCmd.Flags().BoolVar(&rc.PrintWelcomeMessage, "print-welcome", true, "Print welcome message")
|
||||
|
||||
runCmd.Flags().IntVar(&rc.ExitCodeIfIssuesFound, "issues-exit-code",
|
||||
1, "Exit code when issues were found")
|
||||
runCmd.Flags().StringSliceVar(&rc.BuildTags, "build-tags", []string{}, "Build tags (not all linters support them)")
|
||||
|
||||
runCmd.Flags().BoolVar(&rc.Errcheck.CheckClose, "errcheck.check-close", false, "Errcheck: check missed error checks on .Close() calls")
|
||||
runCmd.Flags().BoolVar(&rc.Errcheck.CheckTypeAssertions, "errcheck.check-type-assertions", false, "Errcheck: check for ignored type assertion results")
|
||||
runCmd.Flags().BoolVar(&rc.Errcheck.CheckAssignToBlank, "errcheck.check-blank", false, "Errcheck: check for errors assigned to blank identifier: _ = errFunc()")
|
||||
|
||||
runCmd.Flags().BoolVar(&rc.Govet.CheckShadowing, "govet.check-shadowing", true, "Govet: check for shadowed variables")
|
||||
runCmd.Flags().BoolVar(&rc.Govet.CheckShadowing, "govet.check-shadowing", false, "Govet: check for shadowed variables")
|
||||
|
||||
runCmd.Flags().Float64Var(&rc.Golint.MinConfidence, "golint.min-confidence", 0.8, "Golint: minimum confidence of a problem to print it")
|
||||
|
||||
@ -90,6 +91,9 @@ func (e *Executor) initRun() {
|
||||
runCmd.Flags().StringVar(&rc.DiffFromRevision, "new-from-rev", "", "Show only new issues created after git revision `REV`")
|
||||
runCmd.Flags().StringVar(&rc.DiffPatchFilePath, "new-from-patch", "", "Show only new issues created in git patch with file path `PATH`")
|
||||
runCmd.Flags().BoolVar(&rc.AnalyzeTests, "tests", false, "Analyze tests (*_test.go)")
|
||||
|
||||
runCmd.Flags().StringSliceVarP(&rc.Presets, "presets", "p", []string{},
|
||||
fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see them. This option implies option --disable-all", strings.Join(pkg.AllPresets(), "|")))
|
||||
}
|
||||
|
||||
func isFullImportNeeded(linters []pkg.Linter) bool {
|
||||
@ -208,10 +212,15 @@ func (e *Executor) runAnalysis(ctx context.Context, args []string) (chan result.
|
||||
if len(excludePatterns) != 0 {
|
||||
excludeTotalPattern = fmt.Sprintf("(%s)", strings.Join(excludePatterns, "|"))
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
if lintCtx.Program != nil {
|
||||
fset = lintCtx.Program.Fset
|
||||
}
|
||||
runner := pkg.SimpleRunner{
|
||||
Processors: []processors.Processor{
|
||||
processors.NewExclude(excludeTotalPattern),
|
||||
processors.NewNolint(lintCtx.Program.Fset),
|
||||
processors.NewCgo(),
|
||||
processors.NewNolint(fset),
|
||||
processors.NewUniqByLine(),
|
||||
processors.NewDiff(e.cfg.Run.Diff, e.cfg.Run.DiffFromRevision, e.cfg.Run.DiffPatchFilePath),
|
||||
processors.NewMaxPerFileFromLinter(),
|
||||
@ -231,6 +240,10 @@ func (e *Executor) executeRun(cmd *cobra.Command, args []string) {
|
||||
logrus.Infof("Run took %s", time.Since(startedAt))
|
||||
}(time.Now())
|
||||
|
||||
if e.cfg.Run.PrintWelcomeMessage {
|
||||
fmt.Println("Run this tool in cloud on every github pull request in https://golangci.com for free (public repos)")
|
||||
}
|
||||
|
||||
f := func() error {
|
||||
issues, err := e.runAnalysis(ctx, args)
|
||||
if err != nil {
|
||||
|
@ -15,6 +15,7 @@ const (
|
||||
var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON}
|
||||
|
||||
var DefaultExcludePatterns = []string{
|
||||
"Error return value of `(os\\.Std(out|err)\\.Write|.*\\.Close)` is not checked",
|
||||
"should have comment",
|
||||
"comment on exported method",
|
||||
"G104", // disable what errcheck does: it reports on Close etc
|
||||
@ -33,14 +34,14 @@ type Run struct { // nolint:maligned
|
||||
|
||||
BuildTags []string
|
||||
|
||||
OutFormat string
|
||||
PrintIssuedLine bool
|
||||
PrintLinterName bool
|
||||
OutFormat string
|
||||
PrintIssuedLine bool
|
||||
PrintLinterName bool
|
||||
PrintWelcomeMessage bool
|
||||
|
||||
ExitCodeIfIssuesFound int
|
||||
|
||||
Errcheck struct {
|
||||
CheckClose bool
|
||||
CheckTypeAssertions bool
|
||||
CheckAssignToBlank bool
|
||||
}
|
||||
@ -83,6 +84,8 @@ type Run struct { // nolint:maligned
|
||||
EnableAllLinters bool
|
||||
DisableAllLinters bool
|
||||
|
||||
Presets []string
|
||||
|
||||
ExcludePatterns []string
|
||||
UseDefaultExcludes bool
|
||||
|
||||
|
@ -3,6 +3,7 @@ package pkg
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
@ -10,12 +11,61 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
PresetFormatting = "format"
|
||||
PresetComplexity = "complexity"
|
||||
PresetStyle = "style"
|
||||
PresetBugs = "bugs"
|
||||
PresetUnused = "unused"
|
||||
PresetPerformance = "performance"
|
||||
)
|
||||
|
||||
func AllPresets() []string {
|
||||
return []string{PresetBugs, PresetUnused, PresetFormatting, PresetStyle, PresetComplexity, PresetPerformance}
|
||||
}
|
||||
|
||||
func allPresetsSet() map[string]bool {
|
||||
ret := map[string]bool{}
|
||||
for _, p := range AllPresets() {
|
||||
ret[p] = true
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type LinterConfig struct {
|
||||
Desc string
|
||||
Linter Linter
|
||||
EnabledByDefault bool
|
||||
DoesFullImport bool
|
||||
NeedsSSARepr bool
|
||||
InPresets []string
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithFullImport() LinterConfig {
|
||||
lc.DoesFullImport = true
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithSSA() LinterConfig {
|
||||
lc.DoesFullImport = true
|
||||
lc.NeedsSSARepr = true
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithPresets(presets ...string) LinterConfig {
|
||||
lc.InPresets = presets
|
||||
return lc
|
||||
}
|
||||
|
||||
func (lc LinterConfig) WithDisabledByDefault() LinterConfig {
|
||||
lc.EnabledByDefault = false
|
||||
return lc
|
||||
}
|
||||
|
||||
func newLinterConfig(linter Linter) LinterConfig {
|
||||
return LinterConfig{
|
||||
Linter: linter,
|
||||
EnabledByDefault: true,
|
||||
}
|
||||
}
|
||||
|
||||
var nameToLC map[string]LinterConfig
|
||||
@ -37,46 +87,26 @@ func GetLinterConfig(name string) *LinterConfig {
|
||||
return &lc
|
||||
}
|
||||
|
||||
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, 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, 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.Megacheck{}, "Megacheck: 3 sub-linters in one: staticcheck, gosimple and unused", true, true),
|
||||
enabledByDefault(golinters.Gas{}, "Inspects source code for security problems", true, false),
|
||||
enabledByDefault(golinters.Structcheck{}, "Finds unused struct fields", true, false),
|
||||
enabledByDefault(golinters.Varcheck{}, "Finds unused global variables and constants", true, false),
|
||||
enabledByDefault(golinters.Interfacer{}, "Linter that suggests narrower interface types", true, true),
|
||||
enabledByDefault(golinters.Unconvert{}, "Remove unnecessary type conversions", true, false),
|
||||
enabledByDefault(golinters.Ineffassign{}, "Detects when assignments to existing variables are not used", false, false),
|
||||
enabledByDefault(golinters.Dupl{}, "Tool for code clone detection", false, false),
|
||||
enabledByDefault(golinters.Goconst{}, "Finds repeated strings that could be replaced by a constant", false, false),
|
||||
enabledByDefault(golinters.Deadcode{}, "Finds unused code", true, false),
|
||||
enabledByDefault(golinters.Gocyclo{}, "Computes and checks the cyclomatic complexity of functions", false, false),
|
||||
newLinterConfig(golinters.Govet{}).WithPresets(PresetBugs),
|
||||
newLinterConfig(golinters.Errcheck{}).WithFullImport().WithPresets(PresetBugs),
|
||||
newLinterConfig(golinters.Golint{}).WithDisabledByDefault().WithPresets(PresetStyle),
|
||||
newLinterConfig(golinters.Megacheck{}).WithSSA().WithPresets(PresetBugs, PresetUnused, PresetStyle),
|
||||
newLinterConfig(golinters.Gas{}).WithFullImport().WithPresets(PresetBugs),
|
||||
newLinterConfig(golinters.Structcheck{}).WithFullImport().WithPresets(PresetUnused),
|
||||
newLinterConfig(golinters.Varcheck{}).WithFullImport().WithPresets(PresetUnused),
|
||||
newLinterConfig(golinters.Interfacer{}).WithDisabledByDefault().WithSSA().WithPresets(PresetStyle),
|
||||
newLinterConfig(golinters.Unconvert{}).WithDisabledByDefault().WithFullImport().WithPresets(PresetStyle),
|
||||
newLinterConfig(golinters.Ineffassign{}).WithPresets(PresetUnused),
|
||||
newLinterConfig(golinters.Dupl{}).WithDisabledByDefault().WithPresets(PresetStyle),
|
||||
newLinterConfig(golinters.Goconst{}).WithDisabledByDefault().WithPresets(PresetStyle),
|
||||
newLinterConfig(golinters.Deadcode{}).WithFullImport().WithPresets(PresetUnused),
|
||||
newLinterConfig(golinters.Gocyclo{}).WithDisabledByDefault().WithPresets(PresetComplexity),
|
||||
|
||||
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),
|
||||
newLinterConfig(golinters.Gofmt{}).WithDisabledByDefault().WithPresets(PresetFormatting),
|
||||
newLinterConfig(golinters.Gofmt{UseGoimports: true}).WithDisabledByDefault().WithPresets(PresetFormatting),
|
||||
newLinterConfig(golinters.Maligned{}).WithFullImport().WithDisabledByDefault().WithPresets(PresetPerformance),
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +162,17 @@ func validateEnabledDisabledLintersConfig(cfg *config.Run) error {
|
||||
}
|
||||
}
|
||||
|
||||
allPresets := allPresetsSet()
|
||||
for _, p := range cfg.Presets {
|
||||
if !allPresets[p] {
|
||||
return fmt.Errorf("no such preset %q: only next presets exist: (%s)", p, strings.Join(AllPresets(), "|"))
|
||||
}
|
||||
}
|
||||
|
||||
if len(cfg.Presets) != 0 && cfg.EnableAllLinters {
|
||||
return fmt.Errorf("--presets is incompatible with --enable-all")
|
||||
}
|
||||
|
||||
if cfg.EnableAllLinters && cfg.DisableAllLinters {
|
||||
return fmt.Errorf("--enable-all and --disable-all options must not be combined")
|
||||
}
|
||||
@ -164,12 +205,29 @@ func validateEnabledDisabledLintersConfig(cfg *config.Run) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllLintersForPreset(p string) []Linter {
|
||||
ret := []Linter{}
|
||||
for _, lc := range GetAllSupportedLinterConfigs() {
|
||||
for _, ip := range lc.InPresets {
|
||||
if p == ip {
|
||||
ret = append(ret, lc.Linter)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetEnabledLinters(ctx context.Context, cfg *config.Run) ([]Linter, error) {
|
||||
if err := validateEnabledDisabledLintersConfig(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resultLintersSet := map[string]Linter{}
|
||||
switch {
|
||||
case len(cfg.Presets) != 0:
|
||||
break // imply --disable-all
|
||||
case cfg.EnableAllLinters:
|
||||
resultLintersSet = lintersToMap(getAllSupportedLinters())
|
||||
case cfg.DisableAllLinters:
|
||||
@ -182,6 +240,32 @@ func GetEnabledLinters(ctx context.Context, cfg *config.Run) ([]Linter, error) {
|
||||
resultLintersSet[name] = getLinterByName(name)
|
||||
}
|
||||
|
||||
// XXX: hacks because of sub-linters in megacheck
|
||||
megacheckWasEnabledByUser := resultLintersSet["megacheck"] != nil
|
||||
if !megacheckWasEnabledByUser {
|
||||
cfg.Megacheck.EnableGosimple = false
|
||||
cfg.Megacheck.EnableStaticcheck = false
|
||||
cfg.Megacheck.EnableUnused = false
|
||||
}
|
||||
|
||||
for _, p := range cfg.Presets {
|
||||
for _, linter := range GetAllLintersForPreset(p) {
|
||||
resultLintersSet[linter.Name()] = linter
|
||||
}
|
||||
|
||||
if !megacheckWasEnabledByUser {
|
||||
if p == PresetBugs {
|
||||
cfg.Megacheck.EnableStaticcheck = true
|
||||
}
|
||||
if p == PresetStyle {
|
||||
cfg.Megacheck.EnableGosimple = true
|
||||
}
|
||||
if p == PresetUnused {
|
||||
cfg.Megacheck.EnableUnused = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range cfg.DisabledLinters {
|
||||
delete(resultLintersSet, name)
|
||||
}
|
||||
@ -192,7 +276,10 @@ func GetEnabledLinters(ctx context.Context, cfg *config.Run) ([]Linter, error) {
|
||||
resultLinters = append(resultLinters, linter)
|
||||
resultLinterNames = append(resultLinterNames, name)
|
||||
}
|
||||
logrus.Infof("Enabled linters: %s", resultLinterNames)
|
||||
logrus.Infof("Active linters: %s", resultLinterNames)
|
||||
if len(cfg.Presets) != 0 {
|
||||
logrus.Infof("Active presets: %s", cfg.Presets)
|
||||
}
|
||||
|
||||
return resultLinters, nil
|
||||
}
|
||||
|
@ -56,6 +56,8 @@ func testOneSource(t *testing.T, sourcePath string) {
|
||||
"--print-issued-lines=false",
|
||||
"--print-linter-name=false",
|
||||
"--out-format=line-number",
|
||||
"--print-welcome=false",
|
||||
"--govet.check-shadowing=true",
|
||||
sourcePath)
|
||||
runGoErrchk(cmd, t)
|
||||
}
|
||||
|
@ -14,6 +14,10 @@ func (Deadcode) Name() string {
|
||||
return "deadcode"
|
||||
}
|
||||
|
||||
func (Deadcode) Desc() string {
|
||||
return "Finds unused code"
|
||||
}
|
||||
|
||||
func (d Deadcode) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
issues, err := deadcodeAPI.Run(lintCtx.Program)
|
||||
if err != nil {
|
||||
|
@ -15,6 +15,10 @@ func (Dupl) Name() string {
|
||||
return "dupl"
|
||||
}
|
||||
|
||||
func (Dupl) Desc() string {
|
||||
return "Tool for code clone detection"
|
||||
}
|
||||
|
||||
func (d Dupl) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
issues, err := duplAPI.Run(lintCtx.Paths.Files, lintCtx.RunCfg().Dupl.Threshold)
|
||||
if err != nil {
|
||||
|
@ -3,7 +3,6 @@ package golinters
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
errcheckAPI "github.com/kisielk/errcheck/golangci"
|
||||
@ -15,6 +14,10 @@ func (Errcheck) Name() string {
|
||||
return "errcheck"
|
||||
}
|
||||
|
||||
func (Errcheck) Desc() string {
|
||||
return "Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases"
|
||||
}
|
||||
|
||||
func (e Errcheck) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
errCfg := &lintCtx.RunCfg().Errcheck
|
||||
issues, err := errcheckAPI.Run(lintCtx.Program, errCfg.CheckAssignToBlank, errCfg.CheckTypeAssertions)
|
||||
@ -24,10 +27,6 @@ func (e Errcheck) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, er
|
||||
|
||||
var res []result.Issue
|
||||
for _, i := range issues {
|
||||
if !errCfg.CheckClose && strings.HasSuffix(i.FuncName, ".Close") {
|
||||
continue
|
||||
}
|
||||
|
||||
var text string
|
||||
if i.FuncName != "" {
|
||||
text = fmt.Sprintf("Error return value of %s is not checked", formatCode(i.FuncName, lintCtx.RunCfg()))
|
||||
|
@ -19,6 +19,10 @@ func (Gas) Name() string {
|
||||
return "gas"
|
||||
}
|
||||
|
||||
func (Gas) Desc() string {
|
||||
return "Inspects source code for security problems"
|
||||
}
|
||||
|
||||
func (lint Gas) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
gasConfig := gas.NewConfig()
|
||||
enabledRules := rules.Generate()
|
||||
|
@ -14,17 +14,27 @@ func (Goconst) Name() string {
|
||||
return "goconst"
|
||||
}
|
||||
|
||||
func (Goconst) Desc() string {
|
||||
return "Finds repeated strings that could be replaced by a constant"
|
||||
}
|
||||
|
||||
func (lint Goconst) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
issues, err := goconstAPI.Run(lintCtx.Paths.Files, true,
|
||||
lintCtx.RunCfg().Goconst.MinStringLen,
|
||||
lintCtx.RunCfg().Goconst.MinOccurrencesCount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var goconstIssues []goconstAPI.Issue
|
||||
// TODO: make it cross-package: pass package names inside goconst
|
||||
for _, files := range lintCtx.Paths.FilesGrouppedByDirs() {
|
||||
issues, err := goconstAPI.Run(files, true,
|
||||
lintCtx.RunCfg().Goconst.MinStringLen,
|
||||
lintCtx.RunCfg().Goconst.MinOccurrencesCount,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
goconstIssues = append(goconstIssues, issues...)
|
||||
}
|
||||
|
||||
var res []result.Issue
|
||||
for _, i := range issues {
|
||||
for _, i := range goconstIssues {
|
||||
textBegin := fmt.Sprintf("string %s has %d occurrences", formatCode(i.Str, lintCtx.RunCfg()), i.OccurencesCount)
|
||||
var textEnd string
|
||||
if i.MatchingConst == "" {
|
||||
|
@ -14,6 +14,10 @@ func (Gocyclo) Name() string {
|
||||
return "gocyclo"
|
||||
}
|
||||
|
||||
func (Gocyclo) Desc() string {
|
||||
return "Computes and checks the cyclomatic complexity of functions"
|
||||
}
|
||||
|
||||
func (g Gocyclo) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
stats := gocycloAPI.Run(lintCtx.Paths.MixedPaths())
|
||||
|
||||
|
@ -25,6 +25,14 @@ func (g Gofmt) Name() string {
|
||||
return "gofmt"
|
||||
}
|
||||
|
||||
func (g Gofmt) Desc() string {
|
||||
if g.UseGoimports {
|
||||
return "Goimports does everything that gofmt does. Additionally it checks unused imports"
|
||||
}
|
||||
|
||||
return "Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification"
|
||||
}
|
||||
|
||||
func getFirstDeletedAndAddedLineNumberInHunk(h *diff.Hunk) (int, int, error) {
|
||||
lines := bytes.Split(h.Body, []byte{'\n'})
|
||||
lineNumber := int(h.OrigStartLine - 1)
|
||||
|
@ -15,6 +15,10 @@ func (Golint) Name() string {
|
||||
return "golint"
|
||||
}
|
||||
|
||||
func (Golint) Desc() string {
|
||||
return "Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes"
|
||||
}
|
||||
|
||||
func (g Golint) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
var issues []result.Issue
|
||||
for _, pkgFiles := range lintCtx.Paths.FilesGrouppedByDirs() {
|
||||
|
@ -13,14 +13,23 @@ 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 *Context) ([]result.Issue, error) {
|
||||
issues, err := govetAPI.Run(lintCtx.Paths.MixedPaths(), lintCtx.RunCfg().BuildTags, lintCtx.RunCfg().Govet.CheckShadowing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// TODO: check .S asm files: govet can do it if pass dirs
|
||||
var govetIssues []govetAPI.Issue
|
||||
for _, files := range lintCtx.Paths.FilesGrouppedByDirs() {
|
||||
issues, err := govetAPI.Run(files, lintCtx.RunCfg().Govet.CheckShadowing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
govetIssues = append(govetIssues, issues...)
|
||||
}
|
||||
|
||||
var res []result.Issue
|
||||
for _, i := range issues {
|
||||
for _, i := range govetIssues {
|
||||
res = append(res, result.Issue{
|
||||
Pos: i.Pos,
|
||||
Text: i.Message,
|
||||
|
@ -14,6 +14,10 @@ func (Ineffassign) Name() string {
|
||||
return "ineffassign"
|
||||
}
|
||||
|
||||
func (Ineffassign) Desc() string {
|
||||
return "Detects when assignments to existing variables are not used"
|
||||
}
|
||||
|
||||
func (lint Ineffassign) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
issues := ineffassignAPI.Run(lintCtx.Paths.Files)
|
||||
|
||||
|
@ -14,6 +14,10 @@ func (Interfacer) Name() string {
|
||||
return "interfacer"
|
||||
}
|
||||
|
||||
func (Interfacer) Desc() string {
|
||||
return "Linter that suggests narrower interface types"
|
||||
}
|
||||
|
||||
func (lint Interfacer) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
c := new(check.Checker)
|
||||
c.Program(lintCtx.Program)
|
||||
|
@ -14,6 +14,10 @@ func (Maligned) Name() string {
|
||||
return "maligned"
|
||||
}
|
||||
|
||||
func (Maligned) Desc() string {
|
||||
return "Tool to detect Go structs that would take less memory if their fields were sorted"
|
||||
}
|
||||
|
||||
func (m Maligned) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
issues := malignedAPI.Run(lintCtx.Program)
|
||||
|
||||
|
@ -13,6 +13,10 @@ func (Megacheck) Name() string {
|
||||
return "megacheck"
|
||||
}
|
||||
|
||||
func (Megacheck) Desc() string {
|
||||
return "Megacheck: 3 sub-linters in one: staticcheck, gosimple and unused"
|
||||
}
|
||||
|
||||
func (m Megacheck) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
c := lintCtx.RunCfg().Megacheck
|
||||
issues := megacheckAPI.Run(lintCtx.Program, lintCtx.LoaderConfig, lintCtx.SSAProgram, c.EnableStaticcheck, c.EnableGosimple, c.EnableUnused)
|
||||
|
@ -14,6 +14,10 @@ func (Structcheck) Name() string {
|
||||
return "structcheck"
|
||||
}
|
||||
|
||||
func (Structcheck) Desc() string {
|
||||
return "Finds unused struct fields"
|
||||
}
|
||||
|
||||
func (s Structcheck) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
issues := structcheckAPI.Run(lintCtx.Program, lintCtx.RunCfg().Structcheck.CheckExportedFields)
|
||||
|
||||
|
@ -13,6 +13,10 @@ func (Unconvert) Name() string {
|
||||
return "unconvert"
|
||||
}
|
||||
|
||||
func (Unconvert) Desc() string {
|
||||
return "Remove unnecessary type conversions"
|
||||
}
|
||||
|
||||
func (lint Unconvert) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
positions := unconvertAPI.Run(lintCtx.Program)
|
||||
var res []result.Issue
|
||||
|
@ -14,6 +14,10 @@ func (Varcheck) Name() string {
|
||||
return "varcheck"
|
||||
}
|
||||
|
||||
func (Varcheck) Desc() string {
|
||||
return "Finds unused global variables and constants"
|
||||
}
|
||||
|
||||
func (v Varcheck) Run(ctx context.Context, lintCtx *Context) ([]result.Issue, error) {
|
||||
issues := varcheckAPI.Run(lintCtx.Program, lintCtx.RunCfg().Varcheck.CheckExportedFields)
|
||||
|
||||
|
@ -10,4 +10,5 @@ import (
|
||||
type Linter interface {
|
||||
Run(ctx context.Context, lintCtx *golinters.Context) ([]result.Issue, error)
|
||||
Name() string
|
||||
Desc() string
|
||||
}
|
||||
|
30
pkg/result/processors/cgo.go
Normal file
30
pkg/result/processors/cgo.go
Normal file
@ -0,0 +1,30 @@
|
||||
package processors
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
type Cgo struct {
|
||||
}
|
||||
|
||||
var _ Processor = Cgo{}
|
||||
|
||||
func NewCgo() *Cgo {
|
||||
return &Cgo{}
|
||||
}
|
||||
|
||||
func (p Cgo) Name() string {
|
||||
return "cgo"
|
||||
}
|
||||
|
||||
func (p Cgo) Process(issues []result.Issue) ([]result.Issue, error) {
|
||||
return filterIssues(issues, func(i *result.Issue) bool {
|
||||
// some linters (.e.g gas, deadcode) return incorrect filepaths for cgo issues,
|
||||
// it breaks next processing, so skip them
|
||||
return !strings.HasSuffix(i.FilePath(), "/C")
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (Cgo) Finish() {}
|
@ -1,6 +1,7 @@
|
||||
package processors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
@ -43,7 +44,7 @@ func (p *Nolint) shouldPassIssue(i *result.Issue) (bool, error) {
|
||||
if comments == nil {
|
||||
file, err := parser.ParseFile(p.fset, i.FilePath(), nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return true, err
|
||||
return false, fmt.Errorf("can't parse file %s", i.FilePath())
|
||||
}
|
||||
|
||||
comments = extractFileComments(p.fset, file.Comments...)
|
||||
|
@ -1,6 +1,10 @@
|
||||
package processors
|
||||
|
||||
import "github.com/golangci/golangci-lint/pkg/result"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
func filterIssues(issues []result.Issue, filter func(i *result.Issue) bool) []result.Issue {
|
||||
retIssues := make([]result.Issue, 0, len(issues))
|
||||
@ -18,8 +22,9 @@ func filterIssuesErr(issues []result.Issue, filter func(i *result.Issue) (bool,
|
||||
for _, i := range issues {
|
||||
ok, err := filter(&i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("can't filter issue %#v: %s", i, err)
|
||||
}
|
||||
|
||||
if ok {
|
||||
retIssues = append(retIssues, i)
|
||||
}
|
||||
|
@ -34,11 +34,7 @@ func (r *SimpleRunner) runLinter(ctx context.Context, linter Linter, lintCtx *go
|
||||
startedAt := time.Now()
|
||||
res, err = linter.Run(ctx, lintCtx)
|
||||
|
||||
if err == nil && len(res) != 0 {
|
||||
res = r.processIssues(ctx, res)
|
||||
}
|
||||
|
||||
logrus.Infof("worker #%d: linter %s took %s and found %d issues", i, linter.Name(),
|
||||
logrus.Infof("worker #%d: linter %s took %s and found %d issues (before processing them)", i, linter.Name(),
|
||||
time.Since(startedAt), len(res))
|
||||
return
|
||||
}
|
||||
@ -120,6 +116,11 @@ func (r SimpleRunner) runGo(ctx context.Context, linters []Linter, lintCtx *goli
|
||||
}
|
||||
|
||||
finishedN++
|
||||
|
||||
if len(res.issues) != 0 {
|
||||
res.issues = r.processIssues(ctx, res.issues)
|
||||
}
|
||||
|
||||
for _, i := range res.issues {
|
||||
retIssues <- i
|
||||
}
|
||||
|
5
pkg/testdata/with_issues/errcheck.go
vendored
5
pkg/testdata/with_issues/errcheck.go
vendored
@ -32,3 +32,8 @@ func IgnoreCloseInDeferMissingErrHandling() {
|
||||
|
||||
panic(resp)
|
||||
}
|
||||
|
||||
func IgnoreStdxWrite() {
|
||||
os.Stdout.Write([]byte{})
|
||||
os.Stderr.Write([]byte{})
|
||||
}
|
||||
|
35
vendor/github.com/golangci/govet/golangci.go
generated
vendored
35
vendor/github.com/golangci/govet/golangci.go
generated
vendored
@ -1,9 +1,7 @@
|
||||
package govet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -14,7 +12,7 @@ type Issue struct {
|
||||
|
||||
var foundIssues []Issue
|
||||
|
||||
func Run(paths, buildTags []string, checkShadowing bool) ([]Issue, error) {
|
||||
func Run(files []string, checkShadowing bool) ([]Issue, error) {
|
||||
foundIssues = nil
|
||||
|
||||
if checkShadowing {
|
||||
@ -26,37 +24,16 @@ func Run(paths, buildTags []string, checkShadowing bool) ([]Issue, error) {
|
||||
}
|
||||
}
|
||||
|
||||
tagList = buildTags
|
||||
|
||||
initPrintFlags()
|
||||
initUnusedFlags()
|
||||
|
||||
for _, name := range paths {
|
||||
// Is it a directory?
|
||||
fi, err := os.Stat(name)
|
||||
if err != nil {
|
||||
warnf("error walking tree: %s", err)
|
||||
continue
|
||||
}
|
||||
if fi.IsDir() {
|
||||
dirsRun = true
|
||||
} else {
|
||||
filesRun = true
|
||||
if !strings.HasSuffix(name, "_test.go") {
|
||||
includesNonTest = true
|
||||
}
|
||||
filesRun = true
|
||||
for _, name := range files {
|
||||
if !strings.HasSuffix(name, "_test.go") {
|
||||
includesNonTest = true
|
||||
}
|
||||
}
|
||||
if dirsRun && filesRun {
|
||||
return nil, fmt.Errorf("can't mix dirs and files")
|
||||
}
|
||||
if dirsRun {
|
||||
for _, name := range paths {
|
||||
doPackageDir(name)
|
||||
}
|
||||
return foundIssues, nil
|
||||
}
|
||||
if doPackage(paths, nil) == nil {
|
||||
if doPackage(files, nil) == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
18
vendor/github.com/kisielk/errcheck/internal/errcheck/errcheck.go
generated
vendored
18
vendor/github.com/kisielk/errcheck/internal/errcheck/errcheck.go
generated
vendored
@ -226,6 +226,18 @@ type visitor struct {
|
||||
errors []UncheckedError
|
||||
}
|
||||
|
||||
func getSelName(sel *ast.SelectorExpr) string {
|
||||
if ident, ok := sel.X.(*ast.Ident); ok {
|
||||
return fmt.Sprintf("%s.%s", ident.Name, sel.Sel.Name)
|
||||
}
|
||||
|
||||
if s, ok := sel.X.(*ast.SelectorExpr); ok {
|
||||
return fmt.Sprintf("%s.%s", getSelName(s), sel.Sel.Name)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (v *visitor) fullName(call *ast.CallExpr) (string, bool) {
|
||||
if ident, ok := call.Fun.(*ast.Ident); ok {
|
||||
return ident.Name, true
|
||||
@ -235,6 +247,12 @@ func (v *visitor) fullName(call *ast.CallExpr) (string, bool) {
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
name := getSelName(sel)
|
||||
if name != "" {
|
||||
return name, true
|
||||
}
|
||||
|
||||
fn, ok := v.pkg.ObjectOf(sel.Sel).(*types.Func)
|
||||
if !ok {
|
||||
// Shouldn't happen, but be paranoid
|
||||
|
Loading…
x
Reference in New Issue
Block a user