dev: rewrite linters Manager ()

This commit is contained in:
Ludovic Fernandez 2024-03-02 21:43:28 +01:00 committed by GitHub
parent 26f8088b38
commit b14d05cdb4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 1749 additions and 1825 deletions

View file

@ -0,0 +1,712 @@
package lintersdb
import (
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters"
"github.com/golangci/golangci-lint/pkg/lint/linter"
)
// LinterBuilder builds the "internal" linters based on the configuration.
type LinterBuilder struct{}
// NewLinterBuilder creates a new LinterBuilder.
func NewLinterBuilder() *LinterBuilder {
return &LinterBuilder{}
}
// Build loads all the "internal" linters.
// The configuration is use for the linter settings.
func (b LinterBuilder) Build(cfg *config.Config) []*linter.Config {
if cfg == nil {
return nil
}
const megacheckName = "megacheck"
// The linters are sorted in the alphabetical order (case-insensitive).
// When a new linter is added the version in `WithSince(...)` must be the next minor version of golangci-lint.
return []*linter.Config{
linter.NewConfig(golinters.NewAsasalint(&cfg.LintersSettings.Asasalint)).
WithSince("1.47.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/alingse/asasalint"),
linter.NewConfig(golinters.NewAsciicheck()).
WithSince("v1.26.0").
WithPresets(linter.PresetBugs, linter.PresetStyle).
WithURL("https://github.com/tdakkota/asciicheck"),
linter.NewConfig(golinters.NewBiDiChkFuncName(&cfg.LintersSettings.BiDiChk)).
WithSince("1.43.0").
WithPresets(linter.PresetBugs).
WithURL("https://github.com/breml/bidichk"),
linter.NewConfig(golinters.NewBodyclose()).
WithSince("v1.18.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetPerformance, linter.PresetBugs).
WithURL("https://github.com/timakin/bodyclose"),
linter.NewConfig(golinters.NewContainedCtx()).
WithSince("1.44.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithURL("https://github.com/sivchari/containedctx"),
linter.NewConfig(golinters.NewContextCheck()).
WithSince("v1.43.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/kkHAIKE/contextcheck"),
linter.NewConfig(golinters.NewCopyLoopVar()).
WithSince("v1.57.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/karamaru-alpha/copyloopvar").
WithNoopFallback(cfg, linter.IsGoLowerThanGo122()),
linter.NewConfig(golinters.NewCyclop(&cfg.LintersSettings.Cyclop)).
WithSince("v1.37.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetComplexity).
WithURL("https://github.com/bkielbasa/cyclop"),
linter.NewConfig(golinters.NewDecorder(&cfg.LintersSettings.Decorder)).
WithSince("v1.44.0").
WithPresets(linter.PresetFormatting, linter.PresetStyle).
WithURL("https://gitlab.com/bosi/decorder"),
linter.NewConfig(golinters.NewDeadcode()).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetUnused).
WithURL("https://github.com/remyoudompheng/go-misc/tree/master/deadcode").
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
linter.NewConfig(golinters.NewDepguard(&cfg.LintersSettings.Depguard)).
WithSince("v1.4.0").
WithPresets(linter.PresetStyle, linter.PresetImport, linter.PresetModule).
WithURL("https://github.com/OpenPeeDeeP/depguard"),
linter.NewConfig(golinters.NewDogsled(&cfg.LintersSettings.Dogsled)).
WithSince("v1.19.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/alexkohler/dogsled"),
linter.NewConfig(golinters.NewDupl(&cfg.LintersSettings.Dupl)).
WithSince("v1.0.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/mibk/dupl"),
linter.NewConfig(golinters.NewDupWord(&cfg.LintersSettings.DupWord)).
WithSince("1.50.0").
WithPresets(linter.PresetComment).
WithAutoFix().
WithURL("https://github.com/Abirdcfly/dupword"),
linter.NewConfig(golinters.NewDurationCheck()).
WithSince("v1.37.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/charithe/durationcheck"),
linter.NewConfig(golinters.NewErrcheck(&cfg.LintersSettings.Errcheck)).
WithEnabledByDefault().
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs, linter.PresetError).
WithURL("https://github.com/kisielk/errcheck"),
linter.NewConfig(golinters.NewErrChkJSONFuncName(&cfg.LintersSettings.ErrChkJSON)).
WithSince("1.44.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/breml/errchkjson"),
linter.NewConfig(golinters.NewErrName()).
WithSince("v1.42.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/Antonboom/errname"),
linter.NewConfig(golinters.NewErrorLint(&cfg.LintersSettings.ErrorLint)).
WithSince("v1.32.0").
WithPresets(linter.PresetBugs, linter.PresetError).
WithLoadForGoAnalysis().
WithURL("https://github.com/polyfloyd/go-errorlint"),
linter.NewConfig(golinters.NewExecInQuery()).
WithSince("v1.46.0").
WithPresets(linter.PresetSQL).
WithLoadForGoAnalysis().
WithURL("https://github.com/lufeee/execinquery"),
linter.NewConfig(golinters.NewExhaustive(&cfg.LintersSettings.Exhaustive)).
WithSince(" v1.28.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/nishanths/exhaustive"),
linter.NewConfig(golinters.NewExhaustiveStruct(&cfg.LintersSettings.ExhaustiveStruct)).
WithSince("v1.32.0").
WithPresets(linter.PresetStyle, linter.PresetTest).
WithLoadForGoAnalysis().
WithURL("https://github.com/mbilski/exhaustivestruct").
Deprecated("The owner seems to have abandoned the linter.", "v1.46.0", "exhaustruct"),
linter.NewConfig(golinters.NewExhaustruct(&cfg.LintersSettings.Exhaustruct)).
WithSince("v1.46.0").
WithPresets(linter.PresetStyle, linter.PresetTest).
WithLoadForGoAnalysis().
WithURL("https://github.com/GaijinEntertainment/go-exhaustruct"),
linter.NewConfig(golinters.NewExportLoopRef()).
WithSince("v1.28.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/kyoh86/exportloopref"),
linter.NewConfig(golinters.NewForbidigo(&cfg.LintersSettings.Forbidigo)).
WithSince("v1.34.0").
WithPresets(linter.PresetStyle).
// Strictly speaking,
// the additional information is only needed when forbidigoCfg.AnalyzeTypes is chosen by the user.
// But we don't know that here in all cases (sometimes config is not loaded),
// so we have to assume that it is needed to be on the safe side.
WithLoadForGoAnalysis().
WithURL("https://github.com/ashanbrown/forbidigo"),
linter.NewConfig(golinters.NewForceTypeAssert()).
WithSince("v1.38.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/gostaticanalysis/forcetypeassert"),
linter.NewConfig(golinters.NewFunlen(&cfg.LintersSettings.Funlen)).
WithSince("v1.18.0").
WithPresets(linter.PresetComplexity).
WithURL("https://github.com/ultraware/funlen"),
linter.NewConfig(golinters.NewGci(&cfg.LintersSettings.Gci)).
WithSince("v1.30.0").
WithPresets(linter.PresetFormatting, linter.PresetImport).
WithURL("https://github.com/daixiang0/gci"),
linter.NewConfig(golinters.NewGinkgoLinter(&cfg.LintersSettings.GinkgoLinter)).
WithSince("v1.51.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithURL("https://github.com/nunnatsa/ginkgolinter"),
linter.NewConfig(golinters.NewGoCheckCompilerDirectives()).
WithSince("v1.51.0").
WithPresets(linter.PresetBugs).
WithURL("https://github.com/leighmcculloch/gocheckcompilerdirectives"),
linter.NewConfig(golinters.NewGochecknoglobals()).
WithSince("v1.12.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/leighmcculloch/gochecknoglobals"),
linter.NewConfig(golinters.NewGochecknoinits()).
WithSince("v1.12.0").
WithPresets(linter.PresetStyle),
linter.NewConfig(golinters.NewGoCheckSumType()).
WithSince("v1.55.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/alecthomas/go-check-sumtype"),
linter.NewConfig(golinters.NewGocognit(&cfg.LintersSettings.Gocognit)).
WithSince("v1.20.0").
WithPresets(linter.PresetComplexity).
WithURL("https://github.com/uudashr/gocognit"),
linter.NewConfig(golinters.NewGoconst(&cfg.LintersSettings.Goconst)).
WithSince("v1.0.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/jgautheron/goconst"),
linter.NewConfig(golinters.NewGoCritic(&cfg.LintersSettings.Gocritic, cfg)).
WithSince("v1.12.0").
WithPresets(linter.PresetStyle, linter.PresetMetaLinter).
WithLoadForGoAnalysis().
WithURL("https://github.com/go-critic/go-critic"),
linter.NewConfig(golinters.NewGocyclo(&cfg.LintersSettings.Gocyclo)).
WithSince("v1.0.0").
WithPresets(linter.PresetComplexity).
WithURL("https://github.com/fzipp/gocyclo"),
linter.NewConfig(golinters.NewGodot(&cfg.LintersSettings.Godot)).
WithSince("v1.25.0").
WithPresets(linter.PresetStyle, linter.PresetComment).
WithAutoFix().
WithURL("https://github.com/tetafro/godot"),
linter.NewConfig(golinters.NewGodox(&cfg.LintersSettings.Godox)).
WithSince("v1.19.0").
WithPresets(linter.PresetStyle, linter.PresetComment).
WithURL("https://github.com/matoous/godox"),
linter.NewConfig(golinters.NewGoerr113()).
WithSince("v1.26.0").
WithPresets(linter.PresetStyle, linter.PresetError).
WithLoadForGoAnalysis().
WithURL("https://github.com/Djarvur/go-err113"),
linter.NewConfig(golinters.NewGofmt(&cfg.LintersSettings.Gofmt)).
WithSince("v1.0.0").
WithPresets(linter.PresetFormatting).
WithAutoFix().
WithURL("https://pkg.go.dev/cmd/gofmt"),
linter.NewConfig(golinters.NewGofumpt(&cfg.LintersSettings.Gofumpt)).
WithSince("v1.28.0").
WithPresets(linter.PresetFormatting).
WithAutoFix().
WithURL("https://github.com/mvdan/gofumpt"),
linter.NewConfig(golinters.NewGoHeader(&cfg.LintersSettings.Goheader)).
WithSince("v1.28.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/denis-tingaikin/go-header"),
linter.NewConfig(golinters.NewGoimports(&cfg.LintersSettings.Goimports)).
WithSince("v1.20.0").
WithPresets(linter.PresetFormatting, linter.PresetImport).
WithAutoFix().
WithURL("https://pkg.go.dev/golang.org/x/tools/cmd/goimports"),
linter.NewConfig(golinters.NewGolint(&cfg.LintersSettings.Golint)).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithURL("https://github.com/golang/lint").
Deprecated("The repository of the linter has been archived by the owner.", "v1.41.0", "revive"),
linter.NewConfig(golinters.NewGoMND(&cfg.LintersSettings.Gomnd)).
WithSince("v1.22.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/tommy-muehle/go-mnd"),
linter.NewConfig(golinters.NewGoModDirectives(&cfg.LintersSettings.GoModDirectives)).
WithSince("v1.39.0").
WithPresets(linter.PresetStyle, linter.PresetModule).
WithURL("https://github.com/ldez/gomoddirectives"),
linter.NewConfig(golinters.NewGomodguard(&cfg.LintersSettings.Gomodguard)).
WithSince("v1.25.0").
WithPresets(linter.PresetStyle, linter.PresetImport, linter.PresetModule).
WithURL("https://github.com/ryancurrah/gomodguard"),
linter.NewConfig(golinters.NewGoPrintfFuncName()).
WithSince("v1.23.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/jirfag/go-printf-func-name"),
linter.NewConfig(golinters.NewGosec(&cfg.LintersSettings.Gosec)).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs).
WithURL("https://github.com/securego/gosec").
WithAlternativeNames("gas"),
linter.NewConfig(golinters.NewGosimple(&cfg.LintersSettings.Gosimple)).
WithEnabledByDefault().
WithSince("v1.20.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithAlternativeNames(megacheckName).
WithURL("https://github.com/dominikh/go-tools/tree/master/simple"),
linter.NewConfig(golinters.NewGosmopolitan(&cfg.LintersSettings.Gosmopolitan)).
WithSince("v1.53.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs).
WithURL("https://github.com/xen0n/gosmopolitan"),
linter.NewConfig(golinters.NewGovet(&cfg.LintersSettings.Govet)).
WithEnabledByDefault().
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs, linter.PresetMetaLinter).
WithAlternativeNames("vet", "vetshadow").
WithURL("https://pkg.go.dev/cmd/vet"),
linter.NewConfig(golinters.NewGrouper(&cfg.LintersSettings.Grouper)).
WithSince("v1.44.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/leonklingele/grouper"),
linter.NewConfig(golinters.NewIfshort(&cfg.LintersSettings.Ifshort)).
WithSince("v1.36.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/esimonov/ifshort").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.0", ""),
linter.NewConfig(golinters.NewImportAs(&cfg.LintersSettings.ImportAs)).
WithSince("v1.38.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/julz/importas"),
linter.NewConfig(golinters.NewINamedParam(&cfg.LintersSettings.Inamedparam)).
WithSince("v1.55.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/macabu/inamedparam"),
linter.NewConfig(golinters.NewIneffassign()).
WithEnabledByDefault().
WithSince("v1.0.0").
WithPresets(linter.PresetUnused).
WithURL("https://github.com/gordonklaus/ineffassign"),
linter.NewConfig(golinters.NewInterfaceBloat(&cfg.LintersSettings.InterfaceBloat)).
WithSince("v1.49.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/sashamelentyev/interfacebloat"),
linter.NewConfig(golinters.NewInterfacer()).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithURL("https://github.com/mvdan/interfacer").
Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", ""),
linter.NewConfig(golinters.NewIntrange()).
WithSince("v1.57.0").
WithURL("https://github.com/ckaznocha/intrange").
WithNoopFallback(cfg, linter.IsGoLowerThanGo122()),
linter.NewConfig(golinters.NewIreturn(&cfg.LintersSettings.Ireturn)).
WithSince("v1.43.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/butuzov/ireturn"),
linter.NewConfig(golinters.NewLLL(&cfg.LintersSettings.Lll)).
WithSince("v1.8.0").
WithPresets(linter.PresetStyle),
linter.NewConfig(golinters.NewLoggerCheck(&cfg.LintersSettings.LoggerCheck)).
WithSince("v1.49.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle, linter.PresetBugs).
WithAlternativeNames("logrlint").
WithURL("https://github.com/timonwong/loggercheck"),
linter.NewConfig(golinters.NewMaintIdx(&cfg.LintersSettings.MaintIdx)).
WithSince("v1.44.0").
WithPresets(linter.PresetComplexity).
WithURL("https://github.com/yagipy/maintidx"),
linter.NewConfig(golinters.NewMakezero(&cfg.LintersSettings.Makezero)).
WithSince("v1.34.0").
WithPresets(linter.PresetStyle, linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/ashanbrown/makezero"),
linter.NewConfig(golinters.NewMaligned(&cfg.LintersSettings.Maligned)).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetPerformance).
WithURL("https://github.com/mdempsky/maligned").
Deprecated("The repository of the linter has been archived by the owner.", "v1.38.0", "govet 'fieldalignment'"),
linter.NewConfig(golinters.NewMirror()).
WithSince("v1.53.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/butuzov/mirror"),
linter.NewConfig(golinters.NewMisspell(&cfg.LintersSettings.Misspell)).
WithSince("v1.8.0").
WithPresets(linter.PresetStyle, linter.PresetComment).
WithAutoFix().
WithURL("https://github.com/client9/misspell"),
linter.NewConfig(golinters.NewMustTag(&cfg.LintersSettings.MustTag)).
WithSince("v1.51.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle, linter.PresetBugs).
WithURL("https://github.com/go-simpler/musttag"),
linter.NewConfig(golinters.NewNakedret(&cfg.LintersSettings.Nakedret)).
WithSince("v1.19.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/alexkohler/nakedret"),
linter.NewConfig(golinters.NewNestif(&cfg.LintersSettings.Nestif)).
WithSince("v1.25.0").
WithPresets(linter.PresetComplexity).
WithURL("https://github.com/nakabonne/nestif"),
linter.NewConfig(golinters.NewNilErr()).
WithSince("v1.38.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs).
WithURL("https://github.com/gostaticanalysis/nilerr"),
linter.NewConfig(golinters.NewNilNil(&cfg.LintersSettings.NilNil)).
WithSince("v1.43.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/Antonboom/nilnil"),
linter.NewConfig(golinters.NewNLReturn(&cfg.LintersSettings.Nlreturn)).
WithSince("v1.30.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/ssgreg/nlreturn"),
linter.NewConfig(golinters.NewNoctx()).
WithSince("v1.28.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetPerformance, linter.PresetBugs).
WithURL("https://github.com/sonatard/noctx"),
linter.NewConfig(golinters.NewNoNamedReturns(&cfg.LintersSettings.NoNamedReturns)).
WithSince("v1.46.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithURL("https://github.com/firefart/nonamedreturns"),
linter.NewConfig(golinters.NewNoSnakeCase()).
WithSince("v1.47.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/sivchari/nosnakecase").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.48.1", "revive(var-naming)"),
linter.NewConfig(golinters.NewNoSprintfHostPort()).
WithSince("v1.46.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/stbenjam/no-sprintf-host-port"),
linter.NewConfig(golinters.NewParallelTest(&cfg.LintersSettings.ParallelTest)).
WithSince("v1.33.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle, linter.PresetTest).
WithURL("https://github.com/kunwardeep/paralleltest"),
linter.NewConfig(golinters.NewPerfSprint(&cfg.LintersSettings.PerfSprint)).
WithSince("v1.55.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetPerformance).
WithURL("https://github.com/catenacyber/perfsprint"),
linter.NewConfig(golinters.NewPreAlloc(&cfg.LintersSettings.Prealloc)).
WithSince("v1.19.0").
WithPresets(linter.PresetPerformance).
WithURL("https://github.com/alexkohler/prealloc"),
linter.NewConfig(golinters.NewPredeclared(&cfg.LintersSettings.Predeclared)).
WithSince("v1.35.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/nishanths/predeclared"),
linter.NewConfig(golinters.NewPromlinter(&cfg.LintersSettings.Promlinter)).
WithSince("v1.40.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/yeya24/promlinter"),
linter.NewConfig(golinters.NewProtoGetter(&cfg.LintersSettings.ProtoGetter)).
WithSince("v1.55.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithAutoFix().
WithURL("https://github.com/ghostiam/protogetter"),
linter.NewConfig(golinters.NewReassign(&cfg.LintersSettings.Reassign)).
WithSince("1.49.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/curioswitch/go-reassign"),
linter.NewConfig(golinters.NewRevive(&cfg.LintersSettings.Revive)).
WithSince("v1.37.0").
WithPresets(linter.PresetStyle, linter.PresetMetaLinter).
ConsiderSlow().
WithURL("https://github.com/mgechev/revive"),
linter.NewConfig(golinters.NewRowsErrCheck(&cfg.LintersSettings.RowsErrCheck)).
WithSince("v1.23.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs, linter.PresetSQL).
WithURL("https://github.com/jingyugao/rowserrcheck"),
linter.NewConfig(golinters.NewSlogLint(&cfg.LintersSettings.SlogLint)).
WithSince("v1.55.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle, linter.PresetFormatting).
WithURL("https://github.com/go-simpler/sloglint"),
linter.NewConfig(golinters.NewScopelint()).
WithSince("v1.12.0").
WithPresets(linter.PresetBugs).
WithURL("https://github.com/kyoh86/scopelint").
Deprecated("The repository of the linter has been deprecated by the owner.", "v1.39.0", "exportloopref"),
linter.NewConfig(golinters.NewSQLCloseCheck()).
WithSince("v1.28.0").
WithPresets(linter.PresetBugs, linter.PresetSQL).
WithLoadForGoAnalysis().
WithURL("https://github.com/ryanrolds/sqlclosecheck"),
linter.NewConfig(golinters.NewSpancheck(&cfg.LintersSettings.Spancheck)).
WithSince("v1.56.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs).
WithURL("https://github.com/jjti/go-spancheck"),
linter.NewConfig(golinters.NewStaticcheck(&cfg.LintersSettings.Staticcheck)).
WithEnabledByDefault().
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs, linter.PresetMetaLinter).
WithAlternativeNames(megacheckName).
WithURL("https://staticcheck.io/"),
linter.NewConfig(golinters.NewStructcheck(&cfg.LintersSettings.Structcheck)).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetUnused).
WithURL("https://github.com/opennota/check").
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
linter.NewConfig(golinters.NewStylecheck(&cfg.LintersSettings.Stylecheck)).
WithSince("v1.20.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithURL("https://github.com/dominikh/go-tools/tree/master/stylecheck"),
linter.NewConfig(golinters.NewTagAlign(&cfg.LintersSettings.TagAlign)).
WithSince("v1.53.0").
WithPresets(linter.PresetStyle, linter.PresetFormatting).
WithAutoFix().
WithURL("https://github.com/4meepo/tagalign"),
linter.NewConfig(golinters.NewTagliatelle(&cfg.LintersSettings.Tagliatelle)).
WithSince("v1.40.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/ldez/tagliatelle"),
linter.NewConfig(golinters.NewTenv(&cfg.LintersSettings.Tenv)).
WithSince("v1.43.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/sivchari/tenv"),
linter.NewConfig(golinters.NewTestableexamples()).
WithSince("v1.50.0").
WithPresets(linter.PresetTest).
WithURL("https://github.com/maratori/testableexamples"),
linter.NewConfig(golinters.NewTestifylint(&cfg.LintersSettings.Testifylint)).
WithSince("v1.55.0").
WithPresets(linter.PresetTest, linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/Antonboom/testifylint"),
linter.NewConfig(golinters.NewTestpackage(&cfg.LintersSettings.Testpackage)).
WithSince("v1.25.0").
WithPresets(linter.PresetStyle, linter.PresetTest).
WithURL("https://github.com/maratori/testpackage"),
linter.NewConfig(golinters.NewThelper(&cfg.LintersSettings.Thelper)).
WithSince("v1.34.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/kulti/thelper"),
linter.NewConfig(golinters.NewTparallel()).
WithSince("v1.32.0").
WithPresets(linter.PresetStyle, linter.PresetTest).
WithLoadForGoAnalysis().
WithURL("https://github.com/moricho/tparallel"),
linter.NewConfig(golinters.NewTypecheck()).
WithInternal().
WithEnabledByDefault().
WithSince("v1.3.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetBugs).
WithURL(""),
linter.NewConfig(golinters.NewUnconvert()).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetStyle).
WithURL("https://github.com/mdempsky/unconvert"),
linter.NewConfig(golinters.NewUnparam(&cfg.LintersSettings.Unparam)).
WithSince("v1.9.0").
WithPresets(linter.PresetUnused).
WithLoadForGoAnalysis().
WithURL("https://github.com/mvdan/unparam"),
linter.NewConfig(golinters.NewUnused(&cfg.LintersSettings.Unused, &cfg.LintersSettings.Staticcheck)).
WithEnabledByDefault().
WithSince("v1.20.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetUnused).
WithAlternativeNames(megacheckName).
ConsiderSlow().
WithChangeTypes().
WithURL("https://github.com/dominikh/go-tools/tree/master/unused"),
linter.NewConfig(golinters.NewUseStdlibVars(&cfg.LintersSettings.UseStdlibVars)).
WithSince("v1.48.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/sashamelentyev/usestdlibvars"),
linter.NewConfig(golinters.NewVarcheck(&cfg.LintersSettings.Varcheck)).
WithSince("v1.0.0").
WithLoadForGoAnalysis().
WithPresets(linter.PresetUnused).
WithURL("https://github.com/opennota/check").
Deprecated("The owner seems to have abandoned the linter.", "v1.49.0", "unused"),
linter.NewConfig(golinters.NewVarnamelen(&cfg.LintersSettings.Varnamelen)).
WithSince("v1.43.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/blizzy78/varnamelen"),
linter.NewConfig(golinters.NewWastedAssign()).
WithSince("v1.38.0").
WithPresets(linter.PresetStyle).
WithLoadForGoAnalysis().
WithURL("https://github.com/sanposhiho/wastedassign"),
linter.NewConfig(golinters.NewWhitespace(&cfg.LintersSettings.Whitespace)).
WithSince("v1.19.0").
WithPresets(linter.PresetStyle).
WithAutoFix().
WithURL("https://github.com/ultraware/whitespace"),
linter.NewConfig(golinters.NewWrapcheck(&cfg.LintersSettings.Wrapcheck)).
WithSince("v1.32.0").
WithPresets(linter.PresetStyle, linter.PresetError).
WithLoadForGoAnalysis().
WithURL("https://github.com/tomarrell/wrapcheck"),
linter.NewConfig(golinters.NewWSL(&cfg.LintersSettings.WSL)).
WithSince("v1.20.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/bombsimon/wsl"),
linter.NewConfig(golinters.NewZerologLint()).
WithSince("v1.53.0").
WithPresets(linter.PresetBugs).
WithLoadForGoAnalysis().
WithURL("https://github.com/ykadowak/zerologlint"),
// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
linter.NewConfig(golinters.NewNoLintLint(&cfg.LintersSettings.NoLintLint)).
WithSince("v1.26.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/golangci/golangci-lint/blob/master/pkg/golinters/nolintlint/README.md"),
}
}

View file

@ -11,24 +11,35 @@ import (
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/logutils"
)
type AnalyzerPlugin interface {
GetAnalyzers() []*analysis.Analyzer
}
// getCustomLinterConfigs loads private linters that are specified in the golangci config file.
func (m *Manager) getCustomLinterConfigs() []*linter.Config {
if m.cfg == nil || m.log == nil {
// PluginBuilder builds the custom linters (plugins) based on the configuration.
type PluginBuilder struct {
log logutils.Log
}
// NewPluginBuilder creates new PluginBuilder.
func NewPluginBuilder(log logutils.Log) *PluginBuilder {
return &PluginBuilder{log: log}
}
// Build loads custom linters that are specified in the golangci-lint config file.
func (b *PluginBuilder) Build(cfg *config.Config) []*linter.Config {
if cfg == nil || b.log == nil {
return nil
}
var linters []*linter.Config
for name, settings := range m.cfg.LintersSettings.Custom {
lc, err := m.loadCustomLinterConfig(name, settings)
for name, settings := range cfg.LintersSettings.Custom {
lc, err := b.loadConfig(cfg, name, settings)
if err != nil {
m.log.Errorf("Unable to load custom analyzer %s:%s, %v", name, settings.Path, err)
b.log.Errorf("Unable to load custom analyzer %s:%s, %v", name, settings.Path, err)
} else {
linters = append(linters, lc)
}
@ -37,15 +48,15 @@ func (m *Manager) getCustomLinterConfigs() []*linter.Config {
return linters
}
// loadCustomLinterConfig loads the configuration of private linters.
// loadConfig loads the configuration of private linters.
// Private linters are dynamically loaded from .so plugin files.
func (m *Manager) loadCustomLinterConfig(name string, settings config.CustomLinterSettings) (*linter.Config, error) {
analyzers, err := m.getAnalyzerPlugin(settings.Path, settings.Settings)
func (b *PluginBuilder) loadConfig(cfg *config.Config, name string, settings config.CustomLinterSettings) (*linter.Config, error) {
analyzers, err := b.getAnalyzerPlugin(cfg, settings.Path, settings.Settings)
if err != nil {
return nil, err
}
m.log.Infof("Loaded %s: %s", settings.Path, name)
b.log.Infof("Loaded %s: %s", settings.Path, name)
customLinter := goanalysis.NewLinter(name, settings.Description, analyzers, nil).
WithLoadMode(goanalysis.LoadModeTypesInfo)
@ -63,10 +74,10 @@ func (m *Manager) loadCustomLinterConfig(name string, settings config.CustomLint
// and returns the 'AnalyzerPlugin' interface implemented by the private plugin.
// An error is returned if the private linter cannot be loaded
// or the linter does not implement the AnalyzerPlugin interface.
func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Analyzer, error) {
func (b *PluginBuilder) getAnalyzerPlugin(cfg *config.Config, path string, settings any) ([]*analysis.Analyzer, error) {
if !filepath.IsAbs(path) {
// resolve non-absolute paths relative to config file's directory
path = filepath.Join(m.cfg.GetConfigDir(), path)
path = filepath.Join(cfg.GetConfigDir(), path)
}
plug, err := plugin.Open(path)
@ -74,7 +85,7 @@ func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Anal
return nil, err
}
analyzers, err := m.lookupPlugin(plug, settings)
analyzers, err := b.lookupPlugin(plug, settings)
if err != nil {
return nil, fmt.Errorf("lookup plugin %s: %w", path, err)
}
@ -82,10 +93,10 @@ func (m *Manager) getAnalyzerPlugin(path string, settings any) ([]*analysis.Anal
return analyzers, nil
}
func (m *Manager) lookupPlugin(plug *plugin.Plugin, settings any) ([]*analysis.Analyzer, error) {
func (b *PluginBuilder) lookupPlugin(plug *plugin.Plugin, settings any) ([]*analysis.Analyzer, error) {
symbol, err := plug.Lookup("New")
if err != nil {
analyzers, errP := m.lookupAnalyzerPlugin(plug)
analyzers, errP := b.lookupAnalyzerPlugin(plug)
if errP != nil {
return nil, errors.Join(err, errP)
}
@ -102,13 +113,13 @@ func (m *Manager) lookupPlugin(plug *plugin.Plugin, settings any) ([]*analysis.A
return constructor(settings)
}
func (m *Manager) lookupAnalyzerPlugin(plug *plugin.Plugin) ([]*analysis.Analyzer, error) {
func (b *PluginBuilder) lookupAnalyzerPlugin(plug *plugin.Plugin) ([]*analysis.Analyzer, error) {
symbol, err := plug.Lookup("AnalyzerPlugin")
if err != nil {
return nil, err
}
m.log.Warnf("plugin: 'AnalyzerPlugin' plugins are deprecated, please use the new plugin signature: " +
b.log.Warnf("plugin: 'AnalyzerPlugin' plugins are deprecated, please use the new plugin signature: " +
"https://golangci-lint.run/contributing/new-linters/#create-a-plugin")
analyzerPlugin, ok := symbol.(AnalyzerPlugin)

View file

@ -1,224 +0,0 @@
package lintersdb
import (
"os"
"sort"
"golang.org/x/exp/maps"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/logutils"
)
// EnvTestRun value: "1"
const EnvTestRun = "GL_TEST_RUN"
type EnabledSet struct {
m *Manager
v *Validator
log logutils.Log
cfg *config.Config
debugf logutils.DebugFunc
}
func NewEnabledSet(m *Manager, v *Validator, log logutils.Log, cfg *config.Config) *EnabledSet {
return &EnabledSet{
m: m,
v: v,
log: log,
cfg: cfg,
debugf: logutils.Debug(logutils.DebugKeyEnabledLinters),
}
}
//nolint:gocyclo // the complexity cannot be reduced.
func (es EnabledSet) build(lcfg *config.Linters, enabledByDefaultLinters []*linter.Config) map[string]*linter.Config {
es.debugf("Linters config: %#v", lcfg)
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.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, lc := range resultLintersSet {
if lc.IsSlowLinter() {
delete(resultLintersSet, name)
}
}
}
for _, name := range lcfg.Enable {
for _, lc := range es.m.GetLinterConfigs(name) {
// it's important to use lc.Name() nor name because name can be alias
resultLintersSet[lc.Name()] = lc
}
}
for _, name := range lcfg.Disable {
for _, lc := range es.m.GetLinterConfigs(name) {
// it's important to use lc.Name() nor name because name can be alias
delete(resultLintersSet, lc.Name())
}
}
// typecheck is not a real linter and cannot be disabled.
if _, ok := resultLintersSet["typecheck"]; !ok && (es.cfg == nil || !es.cfg.InternalCmdTest) {
for _, lc := range es.m.GetLinterConfigs("typecheck") {
// it's important to use lc.Name() nor name because name can be alias
resultLintersSet[lc.Name()] = lc
}
}
return resultLintersSet
}
func (es EnabledSet) GetEnabledLintersMap() (map[string]*linter.Config, error) {
if err := es.v.validateEnabledDisabledLintersConfig(&es.cfg.Linters); err != nil {
return nil, err
}
enabledLinters := es.build(&es.cfg.Linters, es.m.GetAllEnabledByDefaultLinters())
if os.Getenv(EnvTestRun) == "1" {
es.verbosePrintLintersStatus(enabledLinters)
}
return enabledLinters, nil
}
// GetOptimizedLinters returns enabled linters after optimization (merging) of multiple linters
// into a fewer number of linters. E.g. some go/analysis linters can be optimized into
// one metalinter for data reuse and speed up.
func (es EnabledSet) GetOptimizedLinters() ([]*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())
es.verbosePrintLintersStatus(resultLintersSet)
es.combineGoAnalysisLinters(resultLintersSet)
resultLinters := maps.Values(resultLintersSet)
// Make order of execution of linters (go/analysis metalinter and unused) stable.
sort.Slice(resultLinters, func(i, j int) bool {
a, b := resultLinters[i], resultLinters[j]
if b.Name() == linter.LastLinter {
return true
}
if a.Name() == linter.LastLinter {
return false
}
if a.DoesChangeTypes != b.DoesChangeTypes {
return b.DoesChangeTypes // move type-changing linters to the end to optimize speed
}
return a.Name() < b.Name()
})
return resultLinters, nil
}
func (es EnabledSet) combineGoAnalysisLinters(linters map[string]*linter.Config) {
var goanalysisLinters []*goanalysis.Linter
goanalysisPresets := map[string]bool{}
for _, lc := range linters {
lnt, ok := lc.Linter.(*goanalysis.Linter)
if !ok {
continue
}
if lnt.LoadMode() == goanalysis.LoadModeWholeProgram {
// It's ineffective by CPU and memory to run whole-program and incremental analyzers at once.
continue
}
goanalysisLinters = append(goanalysisLinters, lnt)
for _, p := range lc.InPresets {
goanalysisPresets[p] = true
}
}
if len(goanalysisLinters) <= 1 {
es.debugf("Didn't combine go/analysis linters: got only %d linters", len(goanalysisLinters))
return
}
for _, lnt := range goanalysisLinters {
delete(linters, lnt.Name())
}
// Make order of execution of go/analysis analyzers stable.
sort.Slice(goanalysisLinters, func(i, j int) bool {
a, b := goanalysisLinters[i], goanalysisLinters[j]
if b.Name() == linter.LastLinter {
return true
}
if a.Name() == linter.LastLinter {
return false
}
return a.Name() <= b.Name()
})
ml := goanalysis.NewMetaLinter(goanalysisLinters)
presets := maps.Keys(goanalysisPresets)
sort.Strings(presets)
mlConfig := &linter.Config{
Linter: ml,
EnabledByDefault: false,
InPresets: presets,
AlternativeNames: nil,
OriginalURL: "",
}
mlConfig = mlConfig.WithLoadForGoAnalysis()
linters[ml.Name()] = mlConfig
es.debugf("Combined %d go/analysis linters into one metalinter", len(goanalysisLinters))
}
func (es EnabledSet) verbosePrintLintersStatus(lcs map[string]*linter.Config) {
var linterNames []string
for _, lc := range lcs {
if lc.Internal {
continue
}
linterNames = append(linterNames, lc.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)
}
}

View file

@ -1,263 +0,0 @@
package lintersdb
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/logutils"
)
type dummyLogger struct{}
func (d dummyLogger) Fatalf(_ string, _ ...any) {}
func (d dummyLogger) Panicf(_ string, _ ...any) {}
func (d dummyLogger) Errorf(_ string, _ ...any) {}
func (d dummyLogger) Warnf(_ string, _ ...any) {}
func (d dummyLogger) Infof(_ string, _ ...any) {}
func (d dummyLogger) Child(_ string) logutils.Log {
return nil
}
func (d dummyLogger) SetLevel(_ logutils.LogLevel) {}
func TestEnabledSet_GetEnabledLintersMap(t *testing.T) {
m := NewManager(nil, nil)
cfg := config.NewDefault()
cfg.Linters.DisableAll = true
cfg.Linters.Enable = []string{"gofmt"}
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, cfg)
lintersMap, err := es.GetEnabledLintersMap()
require.NoError(t, err)
gofmtConfigs := m.GetLinterConfigs("gofmt")
typecheckConfigs := m.GetLinterConfigs("typecheck")
expected := map[string]*linter.Config{
"gofmt": gofmtConfigs[0],
"typecheck": typecheckConfigs[0],
}
assert.Equal(t, expected, lintersMap)
}
func TestEnabledSet_GetOptimizedLinters(t *testing.T) {
m := NewManager(nil, nil)
cfg := config.NewDefault()
cfg.Linters.DisableAll = true
cfg.Linters.Enable = []string{"gofmt"}
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, cfg)
optimizedLinters, err := es.GetOptimizedLinters()
require.NoError(t, err)
gofmtConfigs := m.GetLinterConfigs("gofmt")
typecheckConfigs := m.GetLinterConfigs("typecheck")
var gaLinters []*goanalysis.Linter
for _, l := range gofmtConfigs {
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
}
for _, l := range typecheckConfigs {
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
}
mlConfig := &linter.Config{
Linter: goanalysis.NewMetaLinter(gaLinters),
InPresets: []string{"bugs", "format"},
}
expected := []*linter.Config{mlConfig.WithLoadForGoAnalysis()}
assert.Equal(t, expected, optimizedLinters)
}
func TestEnabledSet_build(t *testing.T) {
type cs struct {
cfg config.Linters
name string // test case name
def []string // enabled by default linters
exp []string // alphabetically ordered enabled linter names
}
allMegacheckLinterNames := []string{"gosimple", "staticcheck", "unused"}
cases := []cs{
{
cfg: config.Linters{
Disable: []string{"megacheck"},
},
name: "disable all linters from megacheck",
def: allMegacheckLinterNames,
exp: []string{"typecheck"}, // all disabled
},
{
cfg: config.Linters{
Disable: []string{"staticcheck"},
},
name: "disable only staticcheck",
def: allMegacheckLinterNames,
exp: []string{"gosimple", "typecheck", "unused"},
},
{
name: "don't merge into megacheck",
def: allMegacheckLinterNames,
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
},
{
name: "expand megacheck",
cfg: config.Linters{
Enable: []string{"megacheck"},
},
def: nil,
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
},
{
name: "don't disable anything",
def: []string{"gofmt", "govet", "typecheck"},
exp: []string{"gofmt", "govet", "typecheck"},
},
{
name: "enable gosec by gas alias",
cfg: config.Linters{
Enable: []string{"gas"},
},
exp: []string{"gosec", "typecheck"},
},
{
name: "enable gosec by primary name",
cfg: config.Linters{
Enable: []string{"gosec"},
},
exp: []string{"gosec", "typecheck"},
},
{
name: "enable gosec by both names",
cfg: config.Linters{
Enable: []string{"gosec", "gas"},
},
exp: []string{"gosec", "typecheck"},
},
{
name: "disable gosec by gas alias",
cfg: config.Linters{
Disable: []string{"gas"},
},
def: []string{"gosec"},
exp: []string{"typecheck"},
},
{
name: "disable gosec by primary name",
cfg: config.Linters{
Disable: []string{"gosec"},
},
def: []string{"gosec"},
exp: []string{"typecheck"},
},
}
m := NewManager(nil, nil)
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, nil)
for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
var defaultLinters []*linter.Config
for _, ln := range c.def {
lcs := m.GetLinterConfigs(ln)
assert.NotNil(t, lcs, ln)
defaultLinters = append(defaultLinters, lcs...)
}
els := es.build(&c.cfg, defaultLinters)
var enabledLinters []string
for ln, lc := range els {
assert.Equal(t, ln, lc.Name())
enabledLinters = append(enabledLinters, ln)
}
assert.ElementsMatch(t, c.exp, enabledLinters)
})
}
}
func TestEnabledSet_combineGoAnalysisLinters(t *testing.T) {
m := NewManager(nil, nil)
es := NewEnabledSet(m, NewValidator(m), dummyLogger{}, config.NewDefault())
foo := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
bar := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
testCases := []struct {
desc string
linters map[string]*linter.Config
expected map[string]*linter.Config
}{
{
desc: "no combined, one linter",
linters: map[string]*linter.Config{
"foo": {
Linter: foo,
InPresets: []string{"A"},
},
},
expected: map[string]*linter.Config{
"foo": {
Linter: foo,
InPresets: []string{"A"},
},
},
},
{
desc: "combined, several linters",
linters: map[string]*linter.Config{
"foo": {
Linter: foo,
InPresets: []string{"A"},
},
"bar": {
Linter: bar,
InPresets: []string{"B"},
},
},
expected: func() map[string]*linter.Config {
mlConfig := &linter.Config{
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{bar, foo}),
InPresets: []string{"A", "B"},
}
return map[string]*linter.Config{
"goanalysis_metalinter": mlConfig.WithLoadForGoAnalysis(),
}
}(),
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
es.combineGoAnalysisLinters(test.linters)
assert.Equal(t, test.expected, test.linters)
})
}
}

File diff suppressed because it is too large Load diff

View file

@ -4,43 +4,223 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/logutils"
)
func Test_trimGoVersion(t *testing.T) {
func TestManager_GetEnabledLintersMap(t *testing.T) {
cfg := config.NewDefault()
cfg.Linters.DisableAll = true
cfg.Linters.Enable = []string{"gofmt"}
m, err := NewManager(logutils.NewStderrLog("skip"), cfg, NewLinterBuilder())
require.NoError(t, err)
lintersMap, err := m.GetEnabledLintersMap()
require.NoError(t, err)
gofmtConfigs := m.GetLinterConfigs("gofmt")
typecheckConfigs := m.GetLinterConfigs("typecheck")
expected := map[string]*linter.Config{
"gofmt": gofmtConfigs[0],
"typecheck": typecheckConfigs[0],
}
assert.Equal(t, expected, lintersMap)
}
func TestManager_GetOptimizedLinters(t *testing.T) {
cfg := config.NewDefault()
cfg.Linters.DisableAll = true
cfg.Linters.Enable = []string{"gofmt"}
m, err := NewManager(logutils.NewStderrLog("skip"), cfg, NewLinterBuilder())
require.NoError(t, err)
optimizedLinters, err := m.GetOptimizedLinters()
require.NoError(t, err)
var gaLinters []*goanalysis.Linter
for _, l := range m.GetLinterConfigs("gofmt") {
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
}
for _, l := range m.GetLinterConfigs("typecheck") {
gaLinters = append(gaLinters, l.Linter.(*goanalysis.Linter))
}
mlConfig := &linter.Config{
Linter: goanalysis.NewMetaLinter(gaLinters),
InPresets: []string{"bugs", "format"},
}
expected := []*linter.Config{mlConfig.WithLoadForGoAnalysis()}
assert.Equal(t, expected, optimizedLinters)
}
func TestManager_build(t *testing.T) {
type cs struct {
cfg config.Linters
name string // test case name
def []string // enabled by default linters
exp []string // alphabetically ordered enabled linter names
}
allMegacheckLinterNames := []string{"gosimple", "staticcheck", "unused"}
cases := []cs{
{
cfg: config.Linters{
Disable: []string{"megacheck"},
},
name: "disable all linters from megacheck",
def: allMegacheckLinterNames,
exp: []string{"typecheck"}, // all disabled
},
{
cfg: config.Linters{
Disable: []string{"staticcheck"},
},
name: "disable only staticcheck",
def: allMegacheckLinterNames,
exp: []string{"gosimple", "typecheck", "unused"},
},
{
name: "don't merge into megacheck",
def: allMegacheckLinterNames,
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
},
{
name: "expand megacheck",
cfg: config.Linters{
Enable: []string{"megacheck"},
},
def: nil,
exp: []string{"gosimple", "staticcheck", "typecheck", "unused"},
},
{
name: "don't disable anything",
def: []string{"gofmt", "govet", "typecheck"},
exp: []string{"gofmt", "govet", "typecheck"},
},
{
name: "enable gosec by gas alias",
cfg: config.Linters{
Enable: []string{"gas"},
},
exp: []string{"gosec", "typecheck"},
},
{
name: "enable gosec by primary name",
cfg: config.Linters{
Enable: []string{"gosec"},
},
exp: []string{"gosec", "typecheck"},
},
{
name: "enable gosec by both names",
cfg: config.Linters{
Enable: []string{"gosec", "gas"},
},
exp: []string{"gosec", "typecheck"},
},
{
name: "disable gosec by gas alias",
cfg: config.Linters{
Disable: []string{"gas"},
},
def: []string{"gosec"},
exp: []string{"typecheck"},
},
{
name: "disable gosec by primary name",
cfg: config.Linters{
Disable: []string{"gosec"},
},
def: []string{"gosec"},
exp: []string{"typecheck"},
},
}
for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
m, err := NewManager(logutils.NewStderrLog("skip"), &config.Config{Linters: c.cfg}, NewLinterBuilder())
require.NoError(t, err)
var defaultLinters []*linter.Config
for _, ln := range c.def {
lcs := m.GetLinterConfigs(ln)
assert.NotNil(t, lcs, ln)
defaultLinters = append(defaultLinters, lcs...)
}
els := m.build(defaultLinters)
var enabledLinters []string
for ln, lc := range els {
assert.Equal(t, ln, lc.Name())
enabledLinters = append(enabledLinters, ln)
}
assert.ElementsMatch(t, c.exp, enabledLinters)
})
}
}
func TestManager_combineGoAnalysisLinters(t *testing.T) {
m, err := NewManager(nil, nil)
require.NoError(t, err)
foo := goanalysis.NewLinter("foo", "example foo", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
bar := goanalysis.NewLinter("bar", "example bar", nil, nil).WithLoadMode(goanalysis.LoadModeTypesInfo)
testCases := []struct {
desc string
version string
expected string
linters map[string]*linter.Config
expected map[string]*linter.Config
}{
{
desc: "patched version",
version: "1.22.0",
expected: "1.22",
desc: "no combined, one linter",
linters: map[string]*linter.Config{
"foo": {
Linter: foo,
InPresets: []string{"A"},
},
},
expected: map[string]*linter.Config{
"foo": {
Linter: foo,
InPresets: []string{"A"},
},
},
},
{
desc: "minor version",
version: "1.22",
expected: "1.22",
},
{
desc: "RC version",
version: "1.22rc1",
expected: "1.22",
},
{
desc: "alpha version",
version: "1.22alpha1",
expected: "1.22",
},
{
desc: "beta version",
version: "1.22beta1",
expected: "1.22",
},
{
desc: "semver RC version",
version: "1.22.0-rc1",
expected: "1.22",
desc: "combined, several linters",
linters: map[string]*linter.Config{
"foo": {
Linter: foo,
InPresets: []string{"A"},
},
"bar": {
Linter: bar,
InPresets: []string{"B"},
},
},
expected: func() map[string]*linter.Config {
mlConfig := &linter.Config{
Linter: goanalysis.NewMetaLinter([]*goanalysis.Linter{bar, foo}),
InPresets: []string{"A", "B"},
}
return map[string]*linter.Config{
"goanalysis_metalinter": mlConfig.WithLoadForGoAnalysis(),
}
}(),
},
}
@ -49,8 +229,9 @@ func Test_trimGoVersion(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
version := trimGoVersion(test.version)
assert.Equal(t, test.expected, version)
m.combineGoAnalysisLinters(test.linters)
assert.Equal(t, test.expected, test.linters)
})
}
}

View file

@ -14,9 +14,29 @@ type Validator struct {
}
func NewValidator(m *Manager) *Validator {
return &Validator{
m: m,
return &Validator{m: m}
}
// Validate validates the configuration by calling all other validators for different
// sections in the configuration and then some additional linter validation functions.
func (v Validator) Validate(cfg *config.Config) error {
err := cfg.Validate()
if err != nil {
return err
}
validators := []func(cfg *config.Linters) error{
v.validateLintersNames,
v.validatePresets,
}
for _, v := range validators {
if err := v(&cfg.Linters); err != nil {
return err
}
}
return nil
}
func (v Validator) validateLintersNames(cfg *config.Linters) error {
@ -55,56 +75,3 @@ func (v Validator) validatePresets(cfg *config.Linters) error {
return nil
}
func (v Validator) validateAllDisableEnableOptions(cfg *config.Linters) error {
if cfg.EnableAll && cfg.DisableAll {
return errors.New("--enable-all and --disable-all options must not be combined")
}
if cfg.DisableAll {
if len(cfg.Enable) == 0 && len(cfg.Presets) == 0 {
return errors.New("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
}

View file

@ -53,72 +53,6 @@ var validatePresetsErrorTestCases = []validateErrorTestCase{
},
}
var validateDisabledAndEnabledAtOneMomentErrorTestCases = []validateErrorTestCase{
{
desc: "disable one linter of the enabled linters",
cfg: &config.Linters{
Enable: []string{"dupl", "gofmt", "misspell"},
Disable: []string{"dupl", "gosec", "nolintlint"},
},
expected: `linter "dupl" can't be disabled and enabled at one moment`,
},
{
desc: "disable multiple enabled linters",
cfg: &config.Linters{
Enable: []string{"dupl", "gofmt", "misspell"},
Disable: []string{"dupl", "gofmt", "misspell"},
},
expected: `linter "dupl" can't be disabled and enabled at one moment`,
},
}
var validateAllDisableEnableOptionsErrorTestCases = []validateErrorTestCase{
{
desc: "enable-all and disable-all",
cfg: &config.Linters{
Enable: nil,
EnableAll: true,
Disable: nil,
DisableAll: true,
Fast: false,
},
expected: "--enable-all and --disable-all options must not be combined",
},
{
desc: "disable-all and disable no enable no preset",
cfg: &config.Linters{
Enable: nil,
EnableAll: false,
Disable: []string{"dupl", "gofmt", "misspell"},
DisableAll: true,
Fast: false,
},
expected: "all linters were disabled, but no one linter was enabled: must enable at least one",
},
{
desc: "disable-all and disable with enable",
cfg: &config.Linters{
Enable: []string{"nolintlint"},
EnableAll: false,
Disable: []string{"dupl", "gofmt", "misspell"},
DisableAll: true,
Fast: false,
},
expected: "can't combine options --disable-all and --disable dupl",
},
{
desc: "enable-all and enable",
cfg: &config.Linters{
Enable: []string{"dupl", "gofmt", "misspell"},
EnableAll: true,
Disable: nil,
DisableAll: false,
Fast: false,
},
expected: "can't combine options --enable-all and --enable dupl",
},
}
type validatorTestCase struct {
desc string
cfg *config.Linters
@ -172,116 +106,43 @@ var validatePresetsTestCases = []validatorTestCase{
},
}
var validateDisabledAndEnabledAtOneMomentTestCases = []validatorTestCase{
{
desc: "2 different sets",
cfg: &config.Linters{
Enable: []string{"dupl", "gofmt", "misspell"},
Disable: []string{"goimports", "gosec", "nolintlint"},
},
},
{
desc: "only enable",
cfg: &config.Linters{
Enable: []string{"goimports", "gosec", "nolintlint"},
Disable: nil,
},
},
{
desc: "only disable",
cfg: &config.Linters{
Enable: nil,
Disable: []string{"dupl", "gofmt", "misspell"},
},
},
{
desc: "no sets",
cfg: &config.Linters{
Enable: nil,
Disable: nil,
},
},
}
func TestValidator_Validate(t *testing.T) {
m, err := NewManager(nil, nil, NewLinterBuilder())
require.NoError(t, err)
var validateAllDisableEnableOptionsTestCases = []validatorTestCase{
{
desc: "nothing",
cfg: &config.Linters{},
},
{
desc: "enable and disable",
cfg: &config.Linters{
Enable: []string{"goimports", "gosec", "nolintlint"},
EnableAll: false,
Disable: []string{"dupl", "gofmt", "misspell"},
DisableAll: false,
},
},
{
desc: "disable-all and enable",
cfg: &config.Linters{
Enable: []string{"goimports", "gosec", "nolintlint"},
EnableAll: false,
Disable: nil,
DisableAll: true,
},
},
{
desc: "enable-all and disable",
cfg: &config.Linters{
Enable: nil,
EnableAll: true,
Disable: []string{"goimports", "gosec", "nolintlint"},
DisableAll: false,
},
},
{
desc: "enable-all and enable and fast",
cfg: &config.Linters{
Enable: []string{"dupl", "gofmt", "misspell"},
EnableAll: true,
Disable: nil,
DisableAll: false,
Fast: true,
},
},
}
func TestValidator_validateEnabledDisabledLintersConfig(t *testing.T) {
v := NewValidator(NewManager(nil, nil))
v := NewValidator(m)
var testCases []validatorTestCase
testCases = append(testCases, validateLintersNamesTestCases...)
testCases = append(testCases, validatePresetsTestCases...)
testCases = append(testCases, validateDisabledAndEnabledAtOneMomentTestCases...)
testCases = append(testCases, validateAllDisableEnableOptionsTestCases...)
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
err := v.validateEnabledDisabledLintersConfig(test.cfg)
err := v.Validate(&config.Config{Linters: *test.cfg})
require.NoError(t, err)
})
}
}
func TestValidator_validateEnabledDisabledLintersConfig_error(t *testing.T) {
v := NewValidator(NewManager(nil, nil))
func TestValidator_Validate_error(t *testing.T) {
m, err := NewManager(nil, nil, NewLinterBuilder())
require.NoError(t, err)
v := NewValidator(m)
var testCases []validateErrorTestCase
testCases = append(testCases, validateLintersNamesErrorTestCases...)
testCases = append(testCases, validatePresetsErrorTestCases...)
testCases = append(testCases, validateDisabledAndEnabledAtOneMomentErrorTestCases...)
testCases = append(testCases, validateAllDisableEnableOptionsErrorTestCases...)
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
err := v.validateEnabledDisabledLintersConfig(test.cfg)
err := v.Validate(&config.Config{Linters: *test.cfg})
require.Error(t, err)
require.EqualError(t, err, test.expected)
@ -290,7 +151,10 @@ func TestValidator_validateEnabledDisabledLintersConfig_error(t *testing.T) {
}
func TestValidator_validateLintersNames(t *testing.T) {
v := NewValidator(NewManager(nil, nil))
m, err := NewManager(nil, nil, NewLinterBuilder())
require.NoError(t, err)
v := NewValidator(m)
for _, test := range validateLintersNamesTestCases {
test := test
@ -304,7 +168,10 @@ func TestValidator_validateLintersNames(t *testing.T) {
}
func TestValidator_validateLintersNames_error(t *testing.T) {
v := NewValidator(NewManager(nil, nil))
m, err := NewManager(nil, nil, NewLinterBuilder())
require.NoError(t, err)
v := NewValidator(m)
for _, test := range validateLintersNamesErrorTestCases {
test := test
@ -348,63 +215,3 @@ func TestValidator_validatePresets_error(t *testing.T) {
})
}
}
func TestValidator_validateDisabledAndEnabledAtOneMoment(t *testing.T) {
v := NewValidator(nil)
for _, test := range validateDisabledAndEnabledAtOneMomentTestCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
err := v.validateDisabledAndEnabledAtOneMoment(test.cfg)
require.NoError(t, err)
})
}
}
func TestValidator_validateDisabledAndEnabledAtOneMoment_error(t *testing.T) {
v := NewValidator(nil)
for _, test := range validateDisabledAndEnabledAtOneMomentErrorTestCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
err := v.validateDisabledAndEnabledAtOneMoment(test.cfg)
require.Error(t, err)
require.EqualError(t, err, test.expected)
})
}
}
func TestValidator_validateAllDisableEnableOptions(t *testing.T) {
v := NewValidator(nil)
for _, test := range validateAllDisableEnableOptionsTestCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
err := v.validateAllDisableEnableOptions(test.cfg)
require.NoError(t, err)
})
}
}
func TestValidator_validateAllDisableEnableOptions_error(t *testing.T) {
v := NewValidator(nil)
for _, test := range validateAllDisableEnableOptionsErrorTestCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
err := v.validateAllDisableEnableOptions(test.cfg)
require.Error(t, err)
require.EqualError(t, err, test.expected)
})
}
}

View file

@ -27,8 +27,7 @@ type Runner struct {
Log logutils.Log
}
func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
es *lintersdb.EnabledSet,
func NewRunner(log logutils.Log, cfg *config.Config, goenv *goutil.Env,
lineCache *fsutils.LineCache, fileCache *fsutils.FileCache,
dbManager *lintersdb.Manager, pkgs []*gopackages.Package) (*Runner, error) {
// Beware that some processors need to add the path prefix when working with paths
@ -50,7 +49,7 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
return nil, err
}
enabledLinters, err := es.GetEnabledLintersMap()
enabledLinters, err := dbManager.GetEnabledLintersMap()
if err != nil {
return nil, fmt.Errorf("failed to get enabled linters: %w", err)
}