286 lines
7.5 KiB
Go
286 lines
7.5 KiB
Go
package pkg
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/golangci/golangci-lint/pkg/config"
|
|
"github.com/golangci/golangci-lint/pkg/golinters"
|
|
"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 {
|
|
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
|
|
var nameToLCOnce sync.Once
|
|
|
|
func GetLinterConfig(name string) *LinterConfig {
|
|
nameToLCOnce.Do(func() {
|
|
nameToLC = make(map[string]LinterConfig)
|
|
for _, lc := range GetAllSupportedLinterConfigs() {
|
|
nameToLC[lc.Linter.Name()] = lc
|
|
}
|
|
})
|
|
|
|
lc, ok := nameToLC[name]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
return &lc
|
|
}
|
|
|
|
func GetAllSupportedLinterConfigs() []LinterConfig {
|
|
return []LinterConfig{
|
|
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),
|
|
|
|
newLinterConfig(golinters.Gofmt{}).WithDisabledByDefault().WithPresets(PresetFormatting),
|
|
newLinterConfig(golinters.Gofmt{UseGoimports: true}).WithDisabledByDefault().WithPresets(PresetFormatting),
|
|
newLinterConfig(golinters.Maligned{}).WithFullImport().WithDisabledByDefault().WithPresets(PresetPerformance),
|
|
}
|
|
}
|
|
|
|
func getAllSupportedLinters() []Linter {
|
|
var ret []Linter
|
|
for _, lc := range GetAllSupportedLinterConfigs() {
|
|
ret = append(ret, lc.Linter)
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func getAllEnabledByDefaultLinters() []Linter {
|
|
var ret []Linter
|
|
for _, lc := range GetAllSupportedLinterConfigs() {
|
|
if lc.EnabledByDefault {
|
|
ret = append(ret, lc.Linter)
|
|
}
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
var supportedLintersByName map[string]Linter
|
|
var linterByNameMapOnce sync.Once
|
|
|
|
func getLinterByName(name string) Linter {
|
|
linterByNameMapOnce.Do(func() {
|
|
supportedLintersByName = make(map[string]Linter)
|
|
for _, lc := range GetAllSupportedLinterConfigs() {
|
|
supportedLintersByName[lc.Linter.Name()] = lc.Linter
|
|
}
|
|
})
|
|
|
|
return supportedLintersByName[name]
|
|
}
|
|
|
|
func lintersToMap(linters []Linter) map[string]Linter {
|
|
ret := map[string]Linter{}
|
|
for _, linter := range linters {
|
|
ret[linter.Name()] = linter
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func validateEnabledDisabledLintersConfig(cfg *config.Run) error {
|
|
allNames := append([]string{}, cfg.EnabledLinters...)
|
|
allNames = append(allNames, cfg.DisabledLinters...)
|
|
for _, name := range allNames {
|
|
if getLinterByName(name) == nil {
|
|
return fmt.Errorf("no such linter %q", name)
|
|
}
|
|
}
|
|
|
|
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")
|
|
}
|
|
|
|
if cfg.DisableAllLinters {
|
|
if len(cfg.EnabledLinters) == 0 {
|
|
return fmt.Errorf("all linters were disabled, but no one linter was enabled: must enable at least one")
|
|
}
|
|
|
|
if len(cfg.DisabledLinters) != 0 {
|
|
return fmt.Errorf("can't combine options --disable-all and --disable %s", cfg.DisabledLinters[0])
|
|
}
|
|
}
|
|
|
|
if cfg.EnableAllLinters && len(cfg.EnabledLinters) != 0 {
|
|
return fmt.Errorf("can't combine options --enable-all and --enable %s", cfg.EnabledLinters[0])
|
|
}
|
|
|
|
enabledLintersSet := map[string]bool{}
|
|
for _, name := range cfg.EnabledLinters {
|
|
enabledLintersSet[name] = true
|
|
}
|
|
|
|
for _, name := range cfg.DisabledLinters {
|
|
if enabledLintersSet[name] {
|
|
return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name)
|
|
}
|
|
}
|
|
|
|
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:
|
|
break
|
|
default:
|
|
resultLintersSet = lintersToMap(getAllEnabledByDefaultLinters())
|
|
}
|
|
|
|
for _, name := range cfg.EnabledLinters {
|
|
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)
|
|
}
|
|
|
|
var resultLinters []Linter
|
|
var resultLinterNames []string
|
|
for name, linter := range resultLintersSet {
|
|
resultLinters = append(resultLinters, linter)
|
|
resultLinterNames = append(resultLinterNames, name)
|
|
}
|
|
logrus.Infof("Active linters: %s", resultLinterNames)
|
|
if len(cfg.Presets) != 0 {
|
|
logrus.Infof("Active presets: %s", cfg.Presets)
|
|
}
|
|
|
|
return resultLinters, nil
|
|
}
|