Skip to content

Commit

Permalink
govet: implement analyzers config
Browse files Browse the repository at this point in the history
  • Loading branch information
ernado committed Sep 14, 2019
1 parent fc8d614 commit 7de6ae1
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 8 deletions.
8 changes: 8 additions & 0 deletions .golangci.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ linters-settings:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf

# enable or disable analyzers by name
enable:
- atomicalign
enable-all: false
disable:
- shadow
disable-all: false
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,14 @@ linters-settings:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# enable or disable analyzers by name
enable:
- atomicalign
enable-all: false
disable:
- shadow
disable-all: false
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
Expand Down
5 changes: 5 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ type LintersSettings struct {
type GovetSettings struct {
CheckShadowing bool `mapstructure:"check-shadowing"`
Settings map[string]map[string]interface{}

Enable []string
Disable []string
EnableAll bool `mapstructure:"enable-all"`
DisableAll bool `mapstructure:"disable-all"`
}

type ErrcheckSettings struct {
Expand Down
89 changes: 81 additions & 8 deletions pkg/golinters/govet.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ 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"
Expand All @@ -33,9 +34,37 @@ import (
"golang.org/x/tools/go/analysis/passes/unusedresult"
)

func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter {
analyzers := []*analysis.Analyzer{
// the traditional vet suite:
func getAllAnalyzers() []*analysis.Analyzer {
return []*analysis.Analyzer{
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,
nilfunc.Analyzer,
printf.Analyzer,
shadow.Analyzer,
shift.Analyzer,
stdmethods.Analyzer,
structtag.Analyzer,
tests.Analyzer,
unmarshal.Analyzer,
unreachable.Analyzer,
unsafeptr.Analyzer,
unusedresult.Analyzer,
}
}

func getDefaultAnalyzers() []*analysis.Analyzer {
return []*analysis.Analyzer{
asmdecl.Analyzer,
assign.Analyzer,
atomic.Analyzer,
Expand All @@ -59,20 +88,64 @@ func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter {
unsafeptr.Analyzer,
unusedresult.Analyzer,
}
}

func isAnalyzerEnabled(name string, cfg *config.GovetSettings, defaultAnalyzers []*analysis.Analyzer) bool {
if cfg.EnableAll {
return true
}
// Raw for loops should be OK on small slice lengths.
for _, n := range cfg.Enable {
if n == name {
return true
}
}
for _, n := range cfg.Disable {
if n == name {
return true
}
}
if cfg.DisableAll {
return false
}
for _, a := range defaultAnalyzers {
if a.Name == name {
return true
}
}
return false
}

func analyzersFromConfig(cfg *config.GovetSettings) []*analysis.Analyzer {
if cfg == nil {
return getDefaultAnalyzers()
}
if cfg.CheckShadowing {
// Keeping for backward compatibility.
cfg.Enable = append(cfg.Enable, shadow.Analyzer.Name)
}

var enabledAnalyzers []*analysis.Analyzer
defaultAnalyzers := getDefaultAnalyzers()
for _, a := range getAllAnalyzers() {
if isAnalyzerEnabled(a.Name, cfg, defaultAnalyzers) {
enabledAnalyzers = append(enabledAnalyzers, a)
}
}

return enabledAnalyzers
}

func NewGovet(cfg *config.GovetSettings) *goanalysis.Linter {
var settings map[string]map[string]interface{}
if cfg != nil {
if cfg.CheckShadowing {
analyzers = append(analyzers, shadow.Analyzer)
}
settings = cfg.Settings
}

return goanalysis.NewLinter(
"govet",
"Vet examines Go source code and reports suspicious constructs, "+
"such as Printf calls whose arguments do not align with the format string",
analyzers,
analyzersFromConfig(cfg),
settings,
)
}
49 changes: 49 additions & 0 deletions pkg/golinters/govet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package golinters

import (
"sort"
"testing"

"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/shadow"
)

func TestGovet(t *testing.T) {
// Checking that every default analyzer is in "all analyzers" list.
allAnalyzers := getAllAnalyzers()
checkList := append(getDefaultAnalyzers(),
shadow.Analyzer, // special case, used in analyzersFromConfig
)
for _, defaultAnalyzer := range checkList {
found := false
for _, a := range allAnalyzers {
if a.Name == defaultAnalyzer.Name {
found = true
break
}
}
if !found {
t.Errorf("%s is not in allAnalyzers", defaultAnalyzer.Name)
}
}
}

type sortedAnalyzers []*analysis.Analyzer

func (p sortedAnalyzers) Len() int { return len(p) }
func (p sortedAnalyzers) Less(i, j int) bool { return p[i].Name < p[j].Name }
func (p sortedAnalyzers) Swap(i, j int) { p[i].Name, p[j].Name = p[j].Name, p[i].Name }

func TestGovetSorted(t *testing.T) {
// Keeping analyzers sorted so their order match the import order.
t.Run("All", func(t *testing.T) {
if !sort.IsSorted(sortedAnalyzers(getAllAnalyzers())) {
t.Error("please keep all analyzers list sorted by name")
}
})
t.Run("Default", func(t *testing.T) {
if !sort.IsSorted(sortedAnalyzers(getDefaultAnalyzers())) {
t.Error("please keep default analyzers list sorted by name")
}
})
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ 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
Expand Down

0 comments on commit 7de6ae1

Please sign in to comment.