diff --git a/pkg/commands/executor.go b/pkg/commands/executor.go index b54aad26..ecd23a33 100644 --- a/pkg/commands/executor.go +++ b/pkg/commands/executor.go @@ -2,6 +2,7 @@ package commands import ( "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/lint/lintersdb" "github.com/golangci/golangci-lint/pkg/logutils" "github.com/golangci/golangci-lint/pkg/report" "github.com/spf13/cobra" @@ -10,15 +11,14 @@ import ( type Executor struct { rootCmd *cobra.Command - cfg *config.Config - - exitCode int - + exitCode int version, commit, date string - log logutils.Log - - reportData report.Data + cfg *config.Config + log logutils.Log + reportData report.Data + DBManager *lintersdb.Manager + EnabledLintersSet *lintersdb.EnabledSet } func NewExecutor(version, commit, date string) *Executor { @@ -30,6 +30,9 @@ func NewExecutor(version, commit, date string) *Executor { } e.log = report.NewLogWrapper(logutils.NewStderrLog(""), &e.reportData) + e.DBManager = lintersdb.NewManager() + e.EnabledLintersSet = lintersdb.NewEnabledSet(e.DBManager, &lintersdb.Validator{}, + e.log.Child("lintersdb"), e.cfg) e.initRoot() e.initRun() diff --git a/pkg/commands/help.go b/pkg/commands/help.go index 61357748..984b9aa8 100644 --- a/pkg/commands/help.go +++ b/pkg/commands/help.go @@ -7,7 +7,6 @@ import ( "github.com/fatih/color" "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" "github.com/golangci/golangci-lint/pkg/logutils" "github.com/spf13/cobra" ) @@ -41,7 +40,7 @@ func printLinterConfigs(lcs []linter.Config) { func (e Executor) executeLintersHelp(cmd *cobra.Command, args []string) { var enabledLCs, disabledLCs []linter.Config - for _, lc := range lintersdb.GetAllSupportedLinterConfigs() { + for _, lc := range e.DBManager.GetAllSupportedLinterConfigs() { if lc.EnabledByDefault { enabledLCs = append(enabledLCs, lc) } else { @@ -55,8 +54,8 @@ func (e Executor) executeLintersHelp(cmd *cobra.Command, args []string) { printLinterConfigs(disabledLCs) color.Green("\nLinters presets:") - for _, p := range lintersdb.AllPresets() { - linters := lintersdb.GetAllLinterConfigsForPreset(p) + for _, p := range e.DBManager.AllPresets() { + linters := e.DBManager.GetAllLinterConfigsForPreset(p) linterNames := []string{} for _, lc := range linters { linterNames = append(linterNames, lc.Linter.Name()) diff --git a/pkg/commands/linters.go b/pkg/commands/linters.go index f559d973..f544e8c0 100644 --- a/pkg/commands/linters.go +++ b/pkg/commands/linters.go @@ -6,7 +6,6 @@ import ( "github.com/fatih/color" "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/lint/lintersdb" "github.com/spf13/cobra" ) @@ -31,7 +30,7 @@ func IsLinterInConfigsList(name string, linters []linter.Config) bool { } func (e Executor) executeLinters(cmd *cobra.Command, args []string) { - enabledLCs, err := lintersdb.GetEnabledLinters(e.cfg, e.log.Child("lintersdb")) + enabledLCs, err := e.EnabledLintersSet.Get() if err != nil { log.Fatalf("Can't get enabled linters: %s", err) } @@ -40,7 +39,7 @@ func (e Executor) executeLinters(cmd *cobra.Command, args []string) { printLinterConfigs(enabledLCs) var disabledLCs []linter.Config - for _, lc := range lintersdb.GetAllSupportedLinterConfigs() { + for _, lc := range e.DBManager.GetAllSupportedLinterConfigs() { if !IsLinterInConfigsList(lc.Linter.Name(), enabledLCs) { disabledLCs = append(disabledLCs, lc) } diff --git a/pkg/commands/run.go b/pkg/commands/run.go index ab9e2136..49a49296 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -40,7 +40,7 @@ func wh(text string) string { return color.GreenString(text) } -func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) { +func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager) { hideFlag := func(name string) { if err := fs.MarkHidden(name); err != nil { panic(err) @@ -137,7 +137,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) { fs.BoolVar(&lc.DisableAll, "disable-all", false, wh("Disable all linters")) fs.StringSliceVarP(&lc.Presets, "presets", "p", nil, wh(fmt.Sprintf("Enable presets (%s) of linters. Run 'golangci-lint linters' to see "+ - "them. This option implies option --disable-all", strings.Join(lintersdb.AllPresets(), "|")))) + "them. This option implies option --disable-all", strings.Join(m.AllPresets(), "|")))) fs.BoolVar(&lc.Fast, "fast", false, wh("Run only fast linters from enabled linters set")) // Issues config @@ -167,7 +167,7 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config) { func (e *Executor) initRunConfiguration(cmd *cobra.Command) { fs := cmd.Flags() fs.SortFlags = false // sort them as they are defined here - initFlagSet(fs, e.cfg) + initFlagSet(fs, e.cfg, e.DBManager) // init e.cfg by values from config: flags parse will see these values // like the default ones. It will overwrite them only if the same option @@ -178,7 +178,7 @@ func (e *Executor) initRunConfiguration(cmd *cobra.Command) { // `changed` variable inside string slice vars will be shared. // Use another config variable here, not e.cfg, to not // affect main parsing by this parsing of only config option. - initFlagSet(fs, cfg) + initFlagSet(fs, cfg, e.DBManager) // Parse max options, even force version option: don't want // to get access to Executor here: it's error-prone to use @@ -232,12 +232,12 @@ func fixSlicesFlags(fs *pflag.FlagSet) { func (e *Executor) runAnalysis(ctx context.Context, args []string) (<-chan result.Issue, error) { e.cfg.Run.Args = args - linters, err := lintersdb.GetEnabledLinters(e.cfg, e.log.Child("lintersdb")) + linters, err := e.EnabledLintersSet.Get() if err != nil { return nil, err } - for _, lc := range lintersdb.GetAllSupportedLinterConfigs() { + for _, lc := range e.DBManager.GetAllSupportedLinterConfigs() { isEnabled := false for _, linter := range linters { if linter.Linter.Name() == lc.Linter.Name() { diff --git a/pkg/lint/lintersdb/enabled_set.go b/pkg/lint/lintersdb/enabled_set.go new file mode 100644 index 00000000..14d36168 --- /dev/null +++ b/pkg/lint/lintersdb/enabled_set.go @@ -0,0 +1,148 @@ +package lintersdb + +import ( + "sort" + + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters" + "github.com/golangci/golangci-lint/pkg/lint/linter" + "github.com/golangci/golangci-lint/pkg/logutils" +) + +type EnabledSet struct { + m *Manager + v *Validator + log logutils.Log + cfg *config.Config +} + +func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Config) *EnabledSet { + return &EnabledSet{ + m: m, + v: v, + log: log, + cfg: cfg, + } +} + +// nolint:gocyclo +func (es EnabledSet) build(lcfg *config.Linters, enabledByDefaultLinters []linter.Config) map[string]*linter.Config { + resultLintersSet := map[string]*linter.Config{} + switch { + case len(lcfg.Presets) != 0: + break // imply --disable-all + case lcfg.EnableAll: + resultLintersSet = linterConfigsToMap(es.m.GetAllSupportedLinterConfigs()) + case lcfg.DisableAll: + break + default: + resultLintersSet = linterConfigsToMap(enabledByDefaultLinters) + } + + // --presets can only add linters to default set + for _, p := range lcfg.Presets { + for _, lc := range es.m.GetAllLinterConfigsForPreset(p) { + lc := lc + resultLintersSet[lc.Linter.Name()] = &lc + } + } + + // --fast removes slow linters from current set. + // It should be after --presets to be able to run only fast linters in preset. + // It should be before --enable and --disable to be able to enable or disable specific linter. + if lcfg.Fast { + for name := range resultLintersSet { + if es.m.getLinterConfig(name).DoesFullImport { + delete(resultLintersSet, name) + } + } + } + + for _, name := range lcfg.Enable { + resultLintersSet[name] = es.m.getLinterConfig(name) + } + + for _, name := range lcfg.Disable { + if name == "megacheck" { + for _, ln := range getAllMegacheckSubLinterNames() { + delete(resultLintersSet, ln) + } + } + delete(resultLintersSet, name) + } + + es.optimizeLintersSet(resultLintersSet) + return resultLintersSet +} + +func getAllMegacheckSubLinterNames() []string { + unusedName := golinters.Megacheck{UnusedEnabled: true}.Name() + gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name() + staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name() + return []string{unusedName, gosimpleName, staticcheckName} +} + +func (es EnabledSet) optimizeLintersSet(linters map[string]*linter.Config) { + unusedName := golinters.Megacheck{UnusedEnabled: true}.Name() + gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name() + staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name() + fullName := golinters.Megacheck{GosimpleEnabled: true, UnusedEnabled: true, StaticcheckEnabled: true}.Name() + allNames := []string{unusedName, gosimpleName, staticcheckName, fullName} + + megacheckCount := 0 + for _, n := range allNames { + if linters[n] != nil { + megacheckCount++ + } + } + + if megacheckCount <= 1 { + return + } + + isFullEnabled := linters[fullName] != nil + mega := golinters.Megacheck{ + UnusedEnabled: isFullEnabled || linters[unusedName] != nil, + GosimpleEnabled: isFullEnabled || linters[gosimpleName] != nil, + StaticcheckEnabled: isFullEnabled || linters[staticcheckName] != nil, + } + + for _, n := range allNames { + delete(linters, n) + } + + lc := *es.m.getLinterConfig("megacheck") + lc.Linter = mega + linters[mega.Name()] = &lc +} + +func (es EnabledSet) Get() ([]linter.Config, error) { + if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil { + return nil, err + } + + resultLintersSet := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters()) + + var resultLinters []linter.Config + for _, lc := range resultLintersSet { + resultLinters = append(resultLinters, *lc) + } + + es.verbosePrintLintersStatus(resultLinters) + + return resultLinters, nil +} + +func (es EnabledSet) verbosePrintLintersStatus(lcs []linter.Config) { + var linterNames []string + for _, lc := range lcs { + linterNames = append(linterNames, lc.Linter.Name()) + } + sort.StringSlice(linterNames).Sort() + es.log.Infof("Active %d linters: %s", len(linterNames), linterNames) + + if len(es.cfg.Linters.Presets) != 0 { + sort.StringSlice(es.cfg.Linters.Presets).Sort() + es.log.Infof("Active presets: %s", es.cfg.Linters.Presets) + } +} diff --git a/pkg/lint/lintersdb/lintersdb_test.go b/pkg/lint/lintersdb/enabled_set_test.go similarity index 89% rename from pkg/lint/lintersdb/lintersdb_test.go rename to pkg/lint/lintersdb/enabled_set_test.go index 7a1205aa..33365171 100644 --- a/pkg/lint/lintersdb/lintersdb_test.go +++ b/pkg/lint/lintersdb/enabled_set_test.go @@ -44,13 +44,15 @@ func TestGetEnabledLintersSet(t *testing.T) { }, } + m := NewManager() + es := NewEnabledSet(m, &Validator{}, nil, nil) for _, c := range cases { t.Run(c.name, func(t *testing.T) { defaultLinters := []linter.Config{} for _, ln := range c.def { - defaultLinters = append(defaultLinters, *getLinterConfig(ln)) + defaultLinters = append(defaultLinters, *m.getLinterConfig(ln)) } - els := getEnabledLintersSet(&c.cfg, defaultLinters) + els := es.build(&c.cfg, defaultLinters) var enabledLinters []string for ln, lc := range els { assert.Equal(t, ln, lc.Linter.Name()) diff --git a/pkg/lint/lintersdb/lintersdb.go b/pkg/lint/lintersdb/manager.go similarity index 50% rename from pkg/lint/lintersdb/lintersdb.go rename to pkg/lint/lintersdb/manager.go index d2edcb41..76b24d3d 100644 --- a/pkg/lint/lintersdb/lintersdb.go +++ b/pkg/lint/lintersdb/manager.go @@ -1,43 +1,42 @@ package lintersdb import ( - "fmt" "os" - "sort" - "strings" - "sync" - "github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/golinters" "github.com/golangci/golangci-lint/pkg/lint/linter" - "github.com/golangci/golangci-lint/pkg/logutils" ) -func AllPresets() []string { +type Manager struct { + nameToLC map[string]linter.Config +} + +func NewManager() *Manager { + m := &Manager{} + nameToLC := make(map[string]linter.Config) + for _, lc := range m.GetAllSupportedLinterConfigs() { + nameToLC[lc.Linter.Name()] = lc + } + + m.nameToLC = nameToLC + return m +} + +func (Manager) AllPresets() []string { return []string{linter.PresetBugs, linter.PresetUnused, linter.PresetFormatting, linter.PresetStyle, linter.PresetComplexity, linter.PresetPerformance} } -func allPresetsSet() map[string]bool { +func (m Manager) allPresetsSet() map[string]bool { ret := map[string]bool{} - for _, p := range AllPresets() { + for _, p := range m.AllPresets() { ret[p] = true } return ret } -var nameToLC map[string]linter.Config -var nameToLCOnce sync.Once - -func getLinterConfig(name string) *linter.Config { - nameToLCOnce.Do(func() { - nameToLC = make(map[string]linter.Config) - for _, lc := range GetAllSupportedLinterConfigs() { - nameToLC[lc.Linter.Name()] = lc - } - }) - - lc, ok := nameToLC[name] +func (m Manager) getLinterConfig(name string) *linter.Config { + lc, ok := m.nameToLC[name] if !ok { return nil } @@ -55,7 +54,7 @@ func enableLinterConfigs(lcs []linter.Config, isEnabled func(lc *linter.Config) return ret } -func GetAllSupportedLinterConfigs() []linter.Config { +func (Manager) GetAllSupportedLinterConfigs() []linter.Config { lcs := []linter.Config{ linter.NewConfig(golinters.Govet{}). WithFullImport(). // TODO: depend on it's configuration here @@ -207,9 +206,9 @@ func GetAllSupportedLinterConfigs() []linter.Config { }) } -func GetAllEnabledByDefaultLinters() []linter.Config { +func (m Manager) GetAllEnabledByDefaultLinters() []linter.Config { var ret []linter.Config - for _, lc := range GetAllSupportedLinterConfigs() { + for _, lc := range m.GetAllSupportedLinterConfigs() { if lc.EnabledByDefault { ret = append(ret, lc) } @@ -228,89 +227,9 @@ func linterConfigsToMap(lcs []linter.Config) map[string]*linter.Config { return ret } -func validateLintersNames(cfg *config.Linters) error { - allNames := append([]string{}, cfg.Enable...) - allNames = append(allNames, cfg.Disable...) - for _, name := range allNames { - if getLinterConfig(name) == nil { - return fmt.Errorf("no such linter %q", name) - } - } - - return nil -} - -func validatePresets(cfg *config.Linters) 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.EnableAll { - return fmt.Errorf("--presets is incompatible with --enable-all") - } - - return nil -} - -func validateAllDisableEnableOptions(cfg *config.Linters) error { - if cfg.EnableAll && cfg.DisableAll { - return fmt.Errorf("--enable-all and --disable-all options must not be combined") - } - - if cfg.DisableAll { - if len(cfg.Enable) == 0 && len(cfg.Presets) == 0 { - return fmt.Errorf("all linters were disabled, but no one linter was enabled: must enable at least one") - } - - if len(cfg.Disable) != 0 { - return fmt.Errorf("can't combine options --disable-all and --disable %s", cfg.Disable[0]) - } - } - - if cfg.EnableAll && len(cfg.Enable) != 0 && !cfg.Fast { - return fmt.Errorf("can't combine options --enable-all and --enable %s", cfg.Enable[0]) - } - - return nil -} - -func validateDisabledAndEnabledAtOneMoment(cfg *config.Linters) error { - enabledLintersSet := map[string]bool{} - for _, name := range cfg.Enable { - enabledLintersSet[name] = true - } - - for _, name := range cfg.Disable { - if enabledLintersSet[name] { - return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name) - } - } - - return nil -} - -func validateEnabledDisabledLintersConfig(cfg *config.Linters) error { - validators := []func(cfg *config.Linters) error{ - validateLintersNames, - validatePresets, - validateAllDisableEnableOptions, - validateDisabledAndEnabledAtOneMoment, - } - for _, v := range validators { - if err := v(cfg); err != nil { - return err - } - } - - return nil -} - -func GetAllLinterConfigsForPreset(p string) []linter.Config { +func (m Manager) GetAllLinterConfigsForPreset(p string) []linter.Config { ret := []linter.Config{} - for _, lc := range GetAllSupportedLinterConfigs() { + for _, lc := range m.GetAllSupportedLinterConfigs() { for _, ip := range lc.InPresets { if p == ip { ret = append(ret, lc) @@ -321,127 +240,3 @@ func GetAllLinterConfigsForPreset(p string) []linter.Config { return ret } - -// nolint:gocyclo -func getEnabledLintersSet(lcfg *config.Linters, - enabledByDefaultLinters []linter.Config) map[string]*linter.Config { - - resultLintersSet := map[string]*linter.Config{} - switch { - case len(lcfg.Presets) != 0: - break // imply --disable-all - case lcfg.EnableAll: - resultLintersSet = linterConfigsToMap(GetAllSupportedLinterConfigs()) - case lcfg.DisableAll: - break - default: - resultLintersSet = linterConfigsToMap(enabledByDefaultLinters) - } - - // --presets can only add linters to default set - for _, p := range lcfg.Presets { - for _, lc := range GetAllLinterConfigsForPreset(p) { - lc := lc - resultLintersSet[lc.Linter.Name()] = &lc - } - } - - // --fast removes slow linters from current set. - // It should be after --presets to be able to run only fast linters in preset. - // It should be before --enable and --disable to be able to enable or disable specific linter. - if lcfg.Fast { - for name := range resultLintersSet { - if getLinterConfig(name).DoesFullImport { - delete(resultLintersSet, name) - } - } - } - - for _, name := range lcfg.Enable { - resultLintersSet[name] = getLinterConfig(name) - } - - for _, name := range lcfg.Disable { - if name == "megacheck" { - for _, ln := range getAllMegacheckSubLinterNames() { - delete(resultLintersSet, ln) - } - } - delete(resultLintersSet, name) - } - - optimizeLintersSet(resultLintersSet) - return resultLintersSet -} - -func getAllMegacheckSubLinterNames() []string { - unusedName := golinters.Megacheck{UnusedEnabled: true}.Name() - gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name() - staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name() - return []string{unusedName, gosimpleName, staticcheckName} -} - -func optimizeLintersSet(linters map[string]*linter.Config) { - unusedName := golinters.Megacheck{UnusedEnabled: true}.Name() - gosimpleName := golinters.Megacheck{GosimpleEnabled: true}.Name() - staticcheckName := golinters.Megacheck{StaticcheckEnabled: true}.Name() - fullName := golinters.Megacheck{GosimpleEnabled: true, UnusedEnabled: true, StaticcheckEnabled: true}.Name() - allNames := []string{unusedName, gosimpleName, staticcheckName, fullName} - - megacheckCount := 0 - for _, n := range allNames { - if linters[n] != nil { - megacheckCount++ - } - } - - if megacheckCount <= 1 { - return - } - - isFullEnabled := linters[fullName] != nil - m := golinters.Megacheck{ - UnusedEnabled: isFullEnabled || linters[unusedName] != nil, - GosimpleEnabled: isFullEnabled || linters[gosimpleName] != nil, - StaticcheckEnabled: isFullEnabled || linters[staticcheckName] != nil, - } - - for _, n := range allNames { - delete(linters, n) - } - - lc := *getLinterConfig("megacheck") - lc.Linter = m - linters[m.Name()] = &lc -} - -func GetEnabledLinters(cfg *config.Config, log logutils.Log) ([]linter.Config, error) { - if err := validateEnabledDisabledLintersConfig(&cfg.Linters); err != nil { - return nil, err - } - - resultLintersSet := getEnabledLintersSet(&cfg.Linters, GetAllEnabledByDefaultLinters()) - - var resultLinters []linter.Config - for _, lc := range resultLintersSet { - resultLinters = append(resultLinters, *lc) - } - - verbosePrintLintersStatus(cfg, resultLinters, log) - - return resultLinters, nil -} - -func verbosePrintLintersStatus(cfg *config.Config, lcs []linter.Config, log logutils.Log) { - var linterNames []string - for _, lc := range lcs { - linterNames = append(linterNames, lc.Linter.Name()) - } - sort.StringSlice(linterNames).Sort() - log.Infof("Active %d linters: %s", len(linterNames), linterNames) - - if len(cfg.Linters.Presets) != 0 { - sort.StringSlice(cfg.Linters.Presets).Sort() - log.Infof("Active presets: %s", cfg.Linters.Presets) - } -} diff --git a/pkg/lint/lintersdb/validator.go b/pkg/lint/lintersdb/validator.go new file mode 100644 index 00000000..4ccc5726 --- /dev/null +++ b/pkg/lint/lintersdb/validator.go @@ -0,0 +1,93 @@ +package lintersdb + +import ( + "fmt" + "strings" + + "github.com/golangci/golangci-lint/pkg/config" +) + +type Validator struct { + m *Manager +} + +func (v Validator) validateLintersNames(cfg *config.Linters) error { + allNames := append([]string{}, cfg.Enable...) + allNames = append(allNames, cfg.Disable...) + for _, name := range allNames { + if v.m.getLinterConfig(name) == nil { + return fmt.Errorf("no such linter %q", name) + } + } + + return nil +} + +func (v Validator) validatePresets(cfg *config.Linters) error { + allPresets := v.m.allPresetsSet() + for _, p := range cfg.Presets { + if !allPresets[p] { + return fmt.Errorf("no such preset %q: only next presets exist: (%s)", + p, strings.Join(v.m.AllPresets(), "|")) + } + } + + if len(cfg.Presets) != 0 && cfg.EnableAll { + return fmt.Errorf("--presets is incompatible with --enable-all") + } + + return nil +} + +func (v Validator) validateAllDisableEnableOptions(cfg *config.Linters) error { + if cfg.EnableAll && cfg.DisableAll { + return fmt.Errorf("--enable-all and --disable-all options must not be combined") + } + + if cfg.DisableAll { + if len(cfg.Enable) == 0 && len(cfg.Presets) == 0 { + return fmt.Errorf("all linters were disabled, but no one linter was enabled: must enable at least one") + } + + if len(cfg.Disable) != 0 { + return fmt.Errorf("can't combine options --disable-all and --disable %s", cfg.Disable[0]) + } + } + + if cfg.EnableAll && len(cfg.Enable) != 0 && !cfg.Fast { + return fmt.Errorf("can't combine options --enable-all and --enable %s", cfg.Enable[0]) + } + + return nil +} + +func (v Validator) validateDisabledAndEnabledAtOneMoment(cfg *config.Linters) error { + enabledLintersSet := map[string]bool{} + for _, name := range cfg.Enable { + enabledLintersSet[name] = true + } + + for _, name := range cfg.Disable { + if enabledLintersSet[name] { + return fmt.Errorf("linter %q can't be disabled and enabled at one moment", name) + } + } + + return nil +} + +func (v Validator) validateEnabledDisabledLintersConfig(cfg *config.Linters) error { + validators := []func(cfg *config.Linters) error{ + v.validateLintersNames, + v.validatePresets, + v.validateAllDisableEnableOptions, + v.validateDisabledAndEnabledAtOneMoment, + } + for _, v := range validators { + if err := v(cfg); err != nil { + return err + } + } + + return nil +}