build(deps): bump github.com/go-critic/go-critic from 0.6.3 to 0.6.4 (#3089)
Co-authored-by: Fernandez Ludovic <ldez@users.noreply.github.com>
This commit is contained in:
parent
edeaa17fd5
commit
9da04f5070
@ -1113,7 +1113,7 @@ linters-settings:
|
||||
makezero:
|
||||
# Allow only slices initialized with a length of zero.
|
||||
# Default: false
|
||||
always: false
|
||||
always: true
|
||||
|
||||
maligned:
|
||||
# Print struct with more effective memory layout or not.
|
||||
|
@ -27,7 +27,6 @@ linters-settings:
|
||||
- ifElseChain
|
||||
- octalLiteral
|
||||
- whyNoLint
|
||||
- wrapperFunc
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
goimports:
|
||||
|
8
go.mod
8
go.mod
@ -27,7 +27,7 @@ require (
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/firefart/nonamedreturns v1.0.4
|
||||
github.com/fzipp/gocyclo v0.6.0
|
||||
github.com/go-critic/go-critic v0.6.3
|
||||
github.com/go-critic/go-critic v0.6.4
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2
|
||||
@ -121,8 +121,8 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-toolsmith/astcast v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astcopy v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astequal v1.0.1 // indirect
|
||||
github.com/go-toolsmith/astcopy v1.0.1 // indirect
|
||||
github.com/go-toolsmith/astequal v1.0.2 // indirect
|
||||
github.com/go-toolsmith/astfmt v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astp v1.0.0 // indirect
|
||||
github.com/go-toolsmith/strparse v1.0.0 // indirect
|
||||
@ -153,7 +153,7 @@ require (
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a // indirect
|
||||
github.com/quasilyte/go-ruleguard v0.3.17 // indirect
|
||||
github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
|
||||
|
17
go.sum
generated
17
go.sum
generated
@ -131,6 +131,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cristalhq/acmd v0.7.0/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ=
|
||||
github.com/daixiang0/gci v0.6.3 h1:wUAqXChk8HbwXn8AfxD9DYSCp9Bpz1L3e6Q4Roe+q9E=
|
||||
github.com/daixiang0/gci v0.6.3/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -170,8 +171,8 @@ github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3n
|
||||
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
||||
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-critic/go-critic v0.6.3 h1:abibh5XYBTASawfTQ0rA7dVtQT+6KzpGqb/J+DxRDaw=
|
||||
github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k=
|
||||
github.com/go-critic/go-critic v0.6.4 h1:tucuG1pvOyYgpBIrVxw0R6gwO42lNa92Aq3VaDoIs+E=
|
||||
github.com/go-critic/go-critic v0.6.4/go.mod h1:qL5SOlk7NtY6sJPoVCTKDIgzNOxHkkkOCVDyi9wJe1U=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@ -190,11 +191,13 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
|
||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
||||
github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8=
|
||||
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
|
||||
github.com/go-toolsmith/astcopy v1.0.1 h1:l09oBhAPyV74kLJ3ZO31iBU8htZGTwr9LTjuMCyL8go=
|
||||
github.com/go-toolsmith/astcopy v1.0.1/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y=
|
||||
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLponh3Moc=
|
||||
github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw=
|
||||
github.com/go-toolsmith/astequal v1.0.2 h1:+XvaV8zNxua+9+Oa4AHmgmpo4RYAbwr/qjNppLfX2yM=
|
||||
github.com/go-toolsmith/astequal v1.0.2/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
|
||||
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
|
||||
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
|
||||
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
|
||||
@ -570,10 +573,9 @@ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA=
|
||||
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
|
||||
github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30=
|
||||
github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a h1:sWFavxtIctGrVs5SYZ5Ml1CvrDAs8Kf5kx2PI3C41dA=
|
||||
github.com/quasilyte/go-ruleguard v0.3.16-0.20220213074421-6aa060fab41a/go.mod h1:VMX+OnnSw4LicdiEGtRSD/1X8kW7GuEscjYNr4cOIT4=
|
||||
github.com/quasilyte/go-ruleguard v0.3.17 h1:cDdoaSbQg11LXPDQqiCK54QmQXsEQQCTIgdcpeULGSI=
|
||||
github.com/quasilyte/go-ruleguard v0.3.17/go.mod h1:sST5PvaR7yb/Az5ksX8oc88usJ4EGjmJv7cK7y3jyig=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.21 h1:vNkC6fC6qMLzCOGbnIHOd5ixUGgTbp3Z4fGnUgULlDA=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.21/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
|
||||
@ -780,6 +782,7 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
|
||||
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic=
|
||||
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
|
@ -117,11 +117,6 @@ func NewExecutor(version, commit, date string) *Executor {
|
||||
// recreate after getting config
|
||||
e.DBManager = lintersdb.NewManager(e.cfg, e.log).WithCustomLinters()
|
||||
|
||||
e.cfg.LintersSettings.Gocritic.InferEnabledChecks(e.log)
|
||||
if err = e.cfg.LintersSettings.Gocritic.Validate(e.log); err != nil {
|
||||
e.log.Fatalf("Invalid gocritic settings: %s", err)
|
||||
}
|
||||
|
||||
// Slice options must be explicitly set for proper merging of config and command-line options.
|
||||
fixSlicesFlags(e.runCmd.Flags())
|
||||
fixSlicesFlags(e.lintersCmd.Flags())
|
||||
|
@ -40,8 +40,8 @@ var defaultLintersSettings = LintersSettings{
|
||||
Gocognit: GocognitSettings{
|
||||
MinComplexity: 30,
|
||||
},
|
||||
Gocritic: GocriticSettings{
|
||||
SettingsPerCheck: map[string]GocriticCheckSettings{},
|
||||
Gocritic: GoCriticSettings{
|
||||
SettingsPerCheck: map[string]GoCriticCheckSettings{},
|
||||
},
|
||||
Godox: GodoxSettings{
|
||||
Keywords: []string{},
|
||||
@ -133,7 +133,7 @@ type LintersSettings struct {
|
||||
Gci GciSettings
|
||||
Gocognit GocognitSettings
|
||||
Goconst GoConstSettings
|
||||
Gocritic GocriticSettings
|
||||
Gocritic GoCriticSettings
|
||||
Gocyclo GoCycloSettings
|
||||
Godot GodotSettings
|
||||
Godox GodoxSettings
|
||||
@ -306,6 +306,16 @@ type GoConstSettings struct {
|
||||
IgnoreCalls bool `mapstructure:"ignore-calls"`
|
||||
}
|
||||
|
||||
type GoCriticSettings struct {
|
||||
EnabledChecks []string `mapstructure:"enabled-checks"`
|
||||
DisabledChecks []string `mapstructure:"disabled-checks"`
|
||||
EnabledTags []string `mapstructure:"enabled-tags"`
|
||||
DisabledTags []string `mapstructure:"disabled-tags"`
|
||||
SettingsPerCheck map[string]GoCriticCheckSettings `mapstructure:"settings"`
|
||||
}
|
||||
|
||||
type GoCriticCheckSettings map[string]interface{}
|
||||
|
||||
type GoCycloSettings struct {
|
||||
MinComplexity int `mapstructure:"min-complexity"`
|
||||
}
|
||||
|
@ -1,366 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
_ "github.com/go-critic/go-critic/checkers" // this import register checkers
|
||||
"github.com/go-critic/go-critic/framework/linter"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/logutils"
|
||||
)
|
||||
|
||||
const gocriticDebugKey = "gocritic"
|
||||
|
||||
var (
|
||||
gocriticDebugf = logutils.Debug(gocriticDebugKey)
|
||||
isGocriticDebug = logutils.HaveDebugTag(gocriticDebugKey)
|
||||
allGocriticCheckers = linter.GetCheckersInfo()
|
||||
allGocriticCheckerMap = func() map[string]*linter.CheckerInfo {
|
||||
checkInfoMap := make(map[string]*linter.CheckerInfo)
|
||||
for _, checkInfo := range allGocriticCheckers {
|
||||
checkInfoMap[checkInfo.Name] = checkInfo
|
||||
}
|
||||
return checkInfoMap
|
||||
}()
|
||||
)
|
||||
|
||||
type GocriticCheckSettings map[string]interface{}
|
||||
|
||||
type GocriticSettings struct {
|
||||
EnabledChecks []string `mapstructure:"enabled-checks"`
|
||||
DisabledChecks []string `mapstructure:"disabled-checks"`
|
||||
EnabledTags []string `mapstructure:"enabled-tags"`
|
||||
DisabledTags []string `mapstructure:"disabled-tags"`
|
||||
SettingsPerCheck map[string]GocriticCheckSettings `mapstructure:"settings"`
|
||||
|
||||
inferredEnabledChecks map[string]bool
|
||||
}
|
||||
|
||||
func debugChecksListf(checks []string, format string, args ...interface{}) {
|
||||
if isGocriticDebug {
|
||||
prefix := fmt.Sprintf(format, args...)
|
||||
gocriticDebugf(prefix+" checks (%d): %s", len(checks), sprintStrings(checks))
|
||||
}
|
||||
}
|
||||
|
||||
func stringsSliceToSet(ss []string) map[string]bool {
|
||||
ret := make(map[string]bool, len(ss))
|
||||
for _, s := range ss {
|
||||
ret[s] = true
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func buildGocriticTagToCheckersMap() map[string][]string {
|
||||
tagToCheckers := map[string][]string{}
|
||||
for _, checker := range allGocriticCheckers {
|
||||
for _, tag := range checker.Tags {
|
||||
tagToCheckers[tag] = append(tagToCheckers[tag], checker.Name)
|
||||
}
|
||||
}
|
||||
return tagToCheckers
|
||||
}
|
||||
|
||||
func gocriticCheckerTagsDebugf() {
|
||||
if !isGocriticDebug {
|
||||
return
|
||||
}
|
||||
|
||||
tagToCheckers := buildGocriticTagToCheckersMap()
|
||||
|
||||
allTags := make([]string, 0, len(tagToCheckers))
|
||||
for tag := range tagToCheckers {
|
||||
allTags = append(allTags, tag)
|
||||
}
|
||||
sort.Strings(allTags)
|
||||
|
||||
gocriticDebugf("All gocritic existing tags and checks:")
|
||||
for _, tag := range allTags {
|
||||
debugChecksListf(tagToCheckers[tag], " tag %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *GocriticSettings) gocriticDisabledCheckersDebugf() {
|
||||
if !isGocriticDebug {
|
||||
return
|
||||
}
|
||||
|
||||
var disabledCheckers []string
|
||||
for _, checker := range allGocriticCheckers {
|
||||
if s.inferredEnabledChecks[strings.ToLower(checker.Name)] {
|
||||
continue
|
||||
}
|
||||
|
||||
disabledCheckers = append(disabledCheckers, checker.Name)
|
||||
}
|
||||
|
||||
if len(disabledCheckers) == 0 {
|
||||
gocriticDebugf("All checks are enabled")
|
||||
} else {
|
||||
debugChecksListf(disabledCheckers, "Final not used")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *GocriticSettings) InferEnabledChecks(log logutils.Log) {
|
||||
gocriticCheckerTagsDebugf()
|
||||
|
||||
enabledByDefaultChecks := getDefaultEnabledGocriticCheckersNames()
|
||||
debugChecksListf(enabledByDefaultChecks, "Enabled by default")
|
||||
|
||||
disabledByDefaultChecks := getDefaultDisabledGocriticCheckersNames()
|
||||
debugChecksListf(disabledByDefaultChecks, "Disabled by default")
|
||||
|
||||
enabledChecks := make([]string, 0, len(s.EnabledTags)+len(enabledByDefaultChecks))
|
||||
|
||||
// EnabledTags
|
||||
if len(s.EnabledTags) != 0 {
|
||||
tagToCheckers := buildGocriticTagToCheckersMap()
|
||||
for _, tag := range s.EnabledTags {
|
||||
enabledChecks = append(enabledChecks, tagToCheckers[tag]...)
|
||||
}
|
||||
debugChecksListf(enabledChecks, "Enabled by config tags %s", sprintStrings(s.EnabledTags))
|
||||
}
|
||||
|
||||
if !(len(s.EnabledTags) == 0 && len(s.EnabledChecks) != 0) {
|
||||
// don't use default checks only if we have no enabled tags and enable some checks manually
|
||||
enabledChecks = append(enabledChecks, enabledByDefaultChecks...)
|
||||
}
|
||||
|
||||
// DisabledTags
|
||||
if len(s.DisabledTags) != 0 {
|
||||
enabledChecks = filterByDisableTags(enabledChecks, s.DisabledTags, log)
|
||||
}
|
||||
|
||||
// EnabledChecks
|
||||
if len(s.EnabledChecks) != 0 {
|
||||
debugChecksListf(s.EnabledChecks, "Enabled by config")
|
||||
|
||||
alreadyEnabledChecksSet := stringsSliceToSet(enabledChecks)
|
||||
for _, enabledCheck := range s.EnabledChecks {
|
||||
if alreadyEnabledChecksSet[enabledCheck] {
|
||||
log.Warnf("No need to enable check %q: it's already enabled", enabledCheck)
|
||||
continue
|
||||
}
|
||||
enabledChecks = append(enabledChecks, enabledCheck)
|
||||
}
|
||||
}
|
||||
|
||||
// DisabledChecks
|
||||
if len(s.DisabledChecks) != 0 {
|
||||
debugChecksListf(s.DisabledChecks, "Disabled by config")
|
||||
|
||||
enabledChecksSet := stringsSliceToSet(enabledChecks)
|
||||
for _, disabledCheck := range s.DisabledChecks {
|
||||
if !enabledChecksSet[disabledCheck] {
|
||||
log.Warnf("Gocritic check %q was explicitly disabled via config. However, as this check "+
|
||||
"is disabled by default, there is no need to explicitly disable it via config.", disabledCheck)
|
||||
continue
|
||||
}
|
||||
delete(enabledChecksSet, disabledCheck)
|
||||
}
|
||||
|
||||
enabledChecks = nil
|
||||
for enabledCheck := range enabledChecksSet {
|
||||
enabledChecks = append(enabledChecks, enabledCheck)
|
||||
}
|
||||
}
|
||||
|
||||
s.inferredEnabledChecks = map[string]bool{}
|
||||
for _, check := range enabledChecks {
|
||||
s.inferredEnabledChecks[strings.ToLower(check)] = true
|
||||
}
|
||||
|
||||
debugChecksListf(enabledChecks, "Final used")
|
||||
s.gocriticDisabledCheckersDebugf()
|
||||
}
|
||||
|
||||
func validateStringsUniq(ss []string) error {
|
||||
set := map[string]bool{}
|
||||
for _, s := range ss {
|
||||
_, ok := set[s]
|
||||
if ok {
|
||||
return fmt.Errorf("%q occurs multiple times in list", s)
|
||||
}
|
||||
set[s] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func intersectStringSlice(s1, s2 []string) []string {
|
||||
s1Map := make(map[string]struct{}, len(s1))
|
||||
for _, s := range s1 {
|
||||
s1Map[s] = struct{}{}
|
||||
}
|
||||
|
||||
result := make([]string, 0)
|
||||
for _, s := range s2 {
|
||||
if _, exists := s1Map[s]; exists {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *GocriticSettings) Validate(log logutils.Log) error {
|
||||
if len(s.EnabledTags) == 0 {
|
||||
if len(s.EnabledChecks) != 0 && len(s.DisabledChecks) != 0 {
|
||||
return errors.New("both enabled and disabled check aren't allowed for gocritic")
|
||||
}
|
||||
} else {
|
||||
if err := validateStringsUniq(s.EnabledTags); err != nil {
|
||||
return errors.Wrap(err, "validate enabled tags")
|
||||
}
|
||||
|
||||
tagToCheckers := buildGocriticTagToCheckersMap()
|
||||
for _, tag := range s.EnabledTags {
|
||||
if _, ok := tagToCheckers[tag]; !ok {
|
||||
return fmt.Errorf("gocritic [enabled]tag %q doesn't exist", tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.DisabledTags) > 0 {
|
||||
tagToCheckers := buildGocriticTagToCheckersMap()
|
||||
for _, tag := range s.EnabledTags {
|
||||
if _, ok := tagToCheckers[tag]; !ok {
|
||||
return fmt.Errorf("gocritic [disabled]tag %q doesn't exist", tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateStringsUniq(s.EnabledChecks); err != nil {
|
||||
return errors.Wrap(err, "validate enabled checks")
|
||||
}
|
||||
if err := validateStringsUniq(s.DisabledChecks); err != nil {
|
||||
return errors.Wrap(err, "validate disabled checks")
|
||||
}
|
||||
|
||||
if err := s.validateCheckerNames(log); err != nil {
|
||||
return errors.Wrap(err, "validation failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *GocriticSettings) IsCheckEnabled(name string) bool {
|
||||
return s.inferredEnabledChecks[strings.ToLower(name)]
|
||||
}
|
||||
|
||||
func sprintAllowedCheckerNames(allowedNames map[string]bool) string {
|
||||
namesSlice := make([]string, 0, len(allowedNames))
|
||||
for name := range allowedNames {
|
||||
namesSlice = append(namesSlice, name)
|
||||
}
|
||||
return sprintStrings(namesSlice)
|
||||
}
|
||||
|
||||
func sprintStrings(ss []string) string {
|
||||
sort.Strings(ss)
|
||||
return fmt.Sprint(ss)
|
||||
}
|
||||
|
||||
// getAllCheckerNames returns a map containing all checker names supported by gocritic.
|
||||
func getAllCheckerNames() map[string]bool {
|
||||
allCheckerNames := make(map[string]bool, len(allGocriticCheckers))
|
||||
for _, checker := range allGocriticCheckers {
|
||||
allCheckerNames[strings.ToLower(checker.Name)] = true
|
||||
}
|
||||
|
||||
return allCheckerNames
|
||||
}
|
||||
|
||||
func isEnabledByDefaultGocriticCheck(info *linter.CheckerInfo) bool {
|
||||
return !info.HasTag("experimental") &&
|
||||
!info.HasTag("opinionated") &&
|
||||
!info.HasTag("performance")
|
||||
}
|
||||
|
||||
func getDefaultEnabledGocriticCheckersNames() []string {
|
||||
var enabled []string
|
||||
for _, info := range allGocriticCheckers {
|
||||
enable := isEnabledByDefaultGocriticCheck(info)
|
||||
if enable {
|
||||
enabled = append(enabled, info.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return enabled
|
||||
}
|
||||
|
||||
func getDefaultDisabledGocriticCheckersNames() []string {
|
||||
var disabled []string
|
||||
for _, info := range allGocriticCheckers {
|
||||
enable := isEnabledByDefaultGocriticCheck(info)
|
||||
if !enable {
|
||||
disabled = append(disabled, info.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return disabled
|
||||
}
|
||||
|
||||
func (s *GocriticSettings) validateCheckerNames(log logutils.Log) error {
|
||||
allowedNames := getAllCheckerNames()
|
||||
|
||||
for _, name := range s.EnabledChecks {
|
||||
if !allowedNames[strings.ToLower(name)] {
|
||||
return fmt.Errorf("enabled checker %s doesn't exist, all existing checkers: %s",
|
||||
name, sprintAllowedCheckerNames(allowedNames))
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range s.DisabledChecks {
|
||||
if !allowedNames[strings.ToLower(name)] {
|
||||
return fmt.Errorf("disabled checker %s doesn't exist, all existing checkers: %s",
|
||||
name, sprintAllowedCheckerNames(allowedNames))
|
||||
}
|
||||
}
|
||||
|
||||
for checkName := range s.SettingsPerCheck {
|
||||
if _, ok := allowedNames[checkName]; !ok {
|
||||
return fmt.Errorf("invalid setting, checker %s doesn't exist, all existing checkers: %s",
|
||||
checkName, sprintAllowedCheckerNames(allowedNames))
|
||||
}
|
||||
if !s.IsCheckEnabled(checkName) {
|
||||
log.Warnf("Gocritic settings were provided for not enabled check %q", checkName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *GocriticSettings) GetLowercasedParams() map[string]GocriticCheckSettings {
|
||||
ret := make(map[string]GocriticCheckSettings, len(s.SettingsPerCheck))
|
||||
for checker, params := range s.SettingsPerCheck {
|
||||
ret[strings.ToLower(checker)] = params
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func filterByDisableTags(enabledChecks, disableTags []string, log logutils.Log) []string {
|
||||
enabledChecksSet := stringsSliceToSet(enabledChecks)
|
||||
for _, enabledCheck := range enabledChecks {
|
||||
checkInfo, checkInfoExists := allGocriticCheckerMap[enabledCheck]
|
||||
if !checkInfoExists {
|
||||
log.Warnf("Gocritic check %q was not exists via filtering disabled tags", enabledCheck)
|
||||
continue
|
||||
}
|
||||
hitTags := intersectStringSlice(checkInfo.Tags, disableTags)
|
||||
if len(hitTags) != 0 {
|
||||
delete(enabledChecksSet, enabledCheck)
|
||||
}
|
||||
}
|
||||
debugChecksListf(enabledChecks, "Disabled by config tags %s", sprintStrings(disableTags))
|
||||
|
||||
enabledChecks = nil
|
||||
for enabledCheck := range enabledChecksSet {
|
||||
enabledChecks = append(enabledChecks, enabledCheck)
|
||||
}
|
||||
return enabledChecks
|
||||
}
|
@ -11,31 +11,39 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-critic/go-critic/checkers"
|
||||
gocriticlinter "github.com/go-critic/go-critic/framework/linter"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
|
||||
"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"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
const gocriticName = "gocritic"
|
||||
const goCriticName = "gocritic"
|
||||
|
||||
func NewGocritic(settings *config.GocriticSettings, cfg *config.Config) *goanalysis.Linter {
|
||||
const goCriticDebugKey = "gocritic"
|
||||
|
||||
var (
|
||||
goCriticDebugf = logutils.Debug(goCriticDebugKey)
|
||||
isGoCriticDebug = logutils.HaveDebugTag(goCriticDebugKey)
|
||||
)
|
||||
|
||||
func NewGoCritic(settings *config.GoCriticSettings, cfg *config.Config) *goanalysis.Linter {
|
||||
var mu sync.Mutex
|
||||
var resIssues []goanalysis.Issue
|
||||
|
||||
sizes := types.SizesFor("gc", runtime.GOARCH)
|
||||
|
||||
wrapper := goCriticWrapper{
|
||||
wrapper := &goCriticWrapper{
|
||||
settings: settings,
|
||||
cfg: cfg,
|
||||
sizes: sizes,
|
||||
sizes: types.SizesFor("gc", runtime.GOARCH),
|
||||
}
|
||||
|
||||
analyzer := &analysis.Analyzer{
|
||||
Name: gocriticName,
|
||||
Name: goCriticName,
|
||||
Doc: goanalysis.TheOnlyanalyzerDoc,
|
||||
Run: func(pass *analysis.Pass) (interface{}, error) {
|
||||
issues, err := wrapper.run(pass)
|
||||
@ -56,24 +64,56 @@ func NewGocritic(settings *config.GocriticSettings, cfg *config.Config) *goanaly
|
||||
}
|
||||
|
||||
return goanalysis.NewLinter(
|
||||
gocriticName,
|
||||
goCriticName,
|
||||
`Provides diagnostics that check for bugs, performance and style issues.
|
||||
Extensible without recompilation through dynamic rules.
|
||||
Dynamic rules are written declaratively with AST patterns, filters, report message and optional suggestion.`,
|
||||
[]*analysis.Analyzer{analyzer},
|
||||
nil,
|
||||
).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
||||
return resIssues
|
||||
}).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
).
|
||||
WithContextSetter(func(context *linter.Context) {
|
||||
wrapper.init()
|
||||
}).
|
||||
WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
||||
return resIssues
|
||||
}).WithLoadMode(goanalysis.LoadModeTypesInfo)
|
||||
}
|
||||
|
||||
type goCriticWrapper struct {
|
||||
settings *config.GocriticSettings
|
||||
cfg *config.Config
|
||||
sizes types.Sizes
|
||||
settings *config.GoCriticSettings
|
||||
settingsWrapper *goCriticSettingsWrapper
|
||||
cfg *config.Config
|
||||
sizes types.Sizes
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (w goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) {
|
||||
func (w *goCriticWrapper) init() {
|
||||
if w.settings != nil {
|
||||
// the 'defer' is here to catch the panic from checkers.InitEmbeddedRules()
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
linterLogger.Fatalf("%s: %v: setting an explicit GOROOT can fix this problem.", goCriticName, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
w.once.Do(checkers.InitEmbeddedRules)
|
||||
|
||||
settingsWrapper := newGoCriticSettingsWrapper(w.settings)
|
||||
|
||||
settingsWrapper.inferEnabledChecks(linterLogger)
|
||||
if err := settingsWrapper.validate(linterLogger); err != nil {
|
||||
linterLogger.Fatalf("%s: invalid settings: %s", goCriticName, err)
|
||||
}
|
||||
|
||||
w.settingsWrapper = settingsWrapper
|
||||
}
|
||||
}
|
||||
|
||||
func (w *goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) {
|
||||
if w.settingsWrapper == nil {
|
||||
return nil, fmt.Errorf("the settings wrapper is nil")
|
||||
}
|
||||
|
||||
linterCtx := gocriticlinter.NewContext(pass.Fset, w.sizes)
|
||||
|
||||
enabledCheckers, err := w.buildEnabledCheckers(linterCtx)
|
||||
@ -93,12 +133,12 @@ func (w goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) {
|
||||
return issues, nil
|
||||
}
|
||||
|
||||
func (w goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) {
|
||||
allParams := w.settings.GetLowercasedParams()
|
||||
func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) {
|
||||
allParams := w.settingsWrapper.getLowerCasedParams()
|
||||
|
||||
var enabledCheckers []*gocriticlinter.Checker
|
||||
for _, info := range gocriticlinter.GetCheckersInfo() {
|
||||
if !w.settings.IsCheckEnabled(info.Name) {
|
||||
if !w.settingsWrapper.isCheckEnabled(info.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -116,23 +156,23 @@ func (w goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context)
|
||||
return enabledCheckers, nil
|
||||
}
|
||||
|
||||
func runGocriticOnPackage(linterCtx *gocriticlinter.Context, checkers []*gocriticlinter.Checker,
|
||||
func runGocriticOnPackage(linterCtx *gocriticlinter.Context, checks []*gocriticlinter.Checker,
|
||||
files []*ast.File) []result.Issue {
|
||||
var res []result.Issue
|
||||
for _, f := range files {
|
||||
filename := filepath.Base(linterCtx.FileSet.Position(f.Pos()).Filename)
|
||||
linterCtx.SetFileInfo(filename, f)
|
||||
|
||||
issues := runGocriticOnFile(linterCtx, f, checkers)
|
||||
issues := runGocriticOnFile(linterCtx, f, checks)
|
||||
res = append(res, issues...)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checkers []*gocriticlinter.Checker) []result.Issue {
|
||||
func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checks []*gocriticlinter.Checker) []result.Issue {
|
||||
var res []result.Issue
|
||||
|
||||
for _, c := range checkers {
|
||||
for _, c := range checks {
|
||||
// All checkers are expected to use *lint.Context
|
||||
// as read-only structure, so no copying is required.
|
||||
for _, warn := range c.Check(f) {
|
||||
@ -140,7 +180,7 @@ func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checkers
|
||||
issue := result.Issue{
|
||||
Pos: pos,
|
||||
Text: fmt.Sprintf("%s: %s", c.Info.Name, warn.Text),
|
||||
FromLinter: gocriticName,
|
||||
FromLinter: goCriticName,
|
||||
}
|
||||
|
||||
if warn.HasQuickFix() {
|
||||
@ -160,7 +200,7 @@ func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checkers
|
||||
return res
|
||||
}
|
||||
|
||||
func (w goCriticWrapper) configureCheckerInfo(info *gocriticlinter.CheckerInfo, allParams map[string]config.GocriticCheckSettings) error {
|
||||
func (w *goCriticWrapper) configureCheckerInfo(info *gocriticlinter.CheckerInfo, allParams map[string]config.GoCriticCheckSettings) error {
|
||||
params := allParams[strings.ToLower(info.Name)]
|
||||
if params == nil { // no config for this checker
|
||||
return nil
|
||||
@ -208,7 +248,7 @@ func normalizeCheckerInfoParams(info *gocriticlinter.CheckerInfo) gocriticlinter
|
||||
// but the file parsers (TOML, YAML, JSON) don't create the same representation for raw type.
|
||||
// then we have to convert value types into the expected value types.
|
||||
// Maybe in the future, this kind of conversion will be done in go-critic itself.
|
||||
func (w goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{} {
|
||||
func (w *goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{} {
|
||||
rv := reflect.ValueOf(p)
|
||||
switch rv.Type().Kind() {
|
||||
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
|
||||
@ -222,3 +262,378 @@ func (w goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{}
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(ldez): rewrite and simplify goCriticSettingsWrapper.
|
||||
|
||||
type goCriticSettingsWrapper struct {
|
||||
*config.GoCriticSettings
|
||||
|
||||
allCheckers []*gocriticlinter.CheckerInfo
|
||||
allCheckerMap map[string]*gocriticlinter.CheckerInfo
|
||||
|
||||
inferredEnabledChecks map[string]bool
|
||||
}
|
||||
|
||||
func newGoCriticSettingsWrapper(settings *config.GoCriticSettings) *goCriticSettingsWrapper {
|
||||
allCheckers := gocriticlinter.GetCheckersInfo()
|
||||
|
||||
allCheckerMap := make(map[string]*gocriticlinter.CheckerInfo)
|
||||
for _, checkInfo := range allCheckers {
|
||||
allCheckerMap[checkInfo.Name] = checkInfo
|
||||
}
|
||||
|
||||
return &goCriticSettingsWrapper{
|
||||
GoCriticSettings: settings,
|
||||
allCheckers: allCheckers,
|
||||
allCheckerMap: allCheckerMap,
|
||||
inferredEnabledChecks: map[string]bool{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) buildTagToCheckersMap() map[string][]string {
|
||||
tagToCheckers := map[string][]string{}
|
||||
|
||||
for _, checker := range s.allCheckers {
|
||||
for _, tag := range checker.Tags {
|
||||
tagToCheckers[tag] = append(tagToCheckers[tag], checker.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return tagToCheckers
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) checkerTagsDebugf() {
|
||||
if !isGoCriticDebug {
|
||||
return
|
||||
}
|
||||
|
||||
tagToCheckers := s.buildTagToCheckersMap()
|
||||
|
||||
allTags := make([]string, 0, len(tagToCheckers))
|
||||
for tag := range tagToCheckers {
|
||||
allTags = append(allTags, tag)
|
||||
}
|
||||
|
||||
sort.Strings(allTags)
|
||||
|
||||
goCriticDebugf("All gocritic existing tags and checks:")
|
||||
for _, tag := range allTags {
|
||||
debugChecksListf(tagToCheckers[tag], " tag %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) disabledCheckersDebugf() {
|
||||
if !isGoCriticDebug {
|
||||
return
|
||||
}
|
||||
|
||||
var disabledCheckers []string
|
||||
for _, checker := range s.allCheckers {
|
||||
if s.inferredEnabledChecks[strings.ToLower(checker.Name)] {
|
||||
continue
|
||||
}
|
||||
|
||||
disabledCheckers = append(disabledCheckers, checker.Name)
|
||||
}
|
||||
|
||||
if len(disabledCheckers) == 0 {
|
||||
goCriticDebugf("All checks are enabled")
|
||||
} else {
|
||||
debugChecksListf(disabledCheckers, "Final not used")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) inferEnabledChecks(log logutils.Log) {
|
||||
s.checkerTagsDebugf()
|
||||
|
||||
enabledByDefaultChecks := s.getDefaultEnabledCheckersNames()
|
||||
debugChecksListf(enabledByDefaultChecks, "Enabled by default")
|
||||
|
||||
disabledByDefaultChecks := s.getDefaultDisabledCheckersNames()
|
||||
debugChecksListf(disabledByDefaultChecks, "Disabled by default")
|
||||
|
||||
enabledChecks := make([]string, 0, len(s.EnabledTags)+len(enabledByDefaultChecks))
|
||||
|
||||
// EnabledTags
|
||||
if len(s.EnabledTags) != 0 {
|
||||
tagToCheckers := s.buildTagToCheckersMap()
|
||||
for _, tag := range s.EnabledTags {
|
||||
enabledChecks = append(enabledChecks, tagToCheckers[tag]...)
|
||||
}
|
||||
|
||||
debugChecksListf(enabledChecks, "Enabled by config tags %s", sprintStrings(s.EnabledTags))
|
||||
}
|
||||
|
||||
if !(len(s.EnabledTags) == 0 && len(s.EnabledChecks) != 0) {
|
||||
// don't use default checks only if we have no enabled tags and enable some checks manually
|
||||
enabledChecks = append(enabledChecks, enabledByDefaultChecks...)
|
||||
}
|
||||
|
||||
// DisabledTags
|
||||
if len(s.DisabledTags) != 0 {
|
||||
enabledChecks = s.filterByDisableTags(enabledChecks, s.DisabledTags, log)
|
||||
}
|
||||
|
||||
// EnabledChecks
|
||||
if len(s.EnabledChecks) != 0 {
|
||||
debugChecksListf(s.EnabledChecks, "Enabled by config")
|
||||
|
||||
alreadyEnabledChecksSet := stringsSliceToSet(enabledChecks)
|
||||
for _, enabledCheck := range s.EnabledChecks {
|
||||
if alreadyEnabledChecksSet[enabledCheck] {
|
||||
log.Warnf("No need to enable check %q: it's already enabled", enabledCheck)
|
||||
continue
|
||||
}
|
||||
enabledChecks = append(enabledChecks, enabledCheck)
|
||||
}
|
||||
}
|
||||
|
||||
// DisabledChecks
|
||||
if len(s.DisabledChecks) != 0 {
|
||||
debugChecksListf(s.DisabledChecks, "Disabled by config")
|
||||
|
||||
enabledChecksSet := stringsSliceToSet(enabledChecks)
|
||||
for _, disabledCheck := range s.DisabledChecks {
|
||||
if !enabledChecksSet[disabledCheck] {
|
||||
log.Warnf("Gocritic check %q was explicitly disabled via config. However, as this check "+
|
||||
"is disabled by default, there is no need to explicitly disable it via config.", disabledCheck)
|
||||
continue
|
||||
}
|
||||
delete(enabledChecksSet, disabledCheck)
|
||||
}
|
||||
|
||||
enabledChecks = nil
|
||||
for enabledCheck := range enabledChecksSet {
|
||||
enabledChecks = append(enabledChecks, enabledCheck)
|
||||
}
|
||||
}
|
||||
|
||||
s.inferredEnabledChecks = map[string]bool{}
|
||||
for _, check := range enabledChecks {
|
||||
s.inferredEnabledChecks[strings.ToLower(check)] = true
|
||||
}
|
||||
|
||||
debugChecksListf(enabledChecks, "Final used")
|
||||
|
||||
s.disabledCheckersDebugf()
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) validate(log logutils.Log) error {
|
||||
if len(s.EnabledTags) == 0 {
|
||||
if len(s.EnabledChecks) != 0 && len(s.DisabledChecks) != 0 {
|
||||
return errors.New("both enabled and disabled check aren't allowed for gocritic")
|
||||
}
|
||||
} else {
|
||||
if err := validateStringsUniq(s.EnabledTags); err != nil {
|
||||
return errors.Wrap(err, "validate enabled tags")
|
||||
}
|
||||
|
||||
tagToCheckers := s.buildTagToCheckersMap()
|
||||
|
||||
for _, tag := range s.EnabledTags {
|
||||
if _, ok := tagToCheckers[tag]; !ok {
|
||||
return fmt.Errorf("gocritic [enabled]tag %q doesn't exist", tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.DisabledTags) > 0 {
|
||||
tagToCheckers := s.buildTagToCheckersMap()
|
||||
for _, tag := range s.EnabledTags {
|
||||
if _, ok := tagToCheckers[tag]; !ok {
|
||||
return fmt.Errorf("gocritic [disabled]tag %q doesn't exist", tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateStringsUniq(s.EnabledChecks); err != nil {
|
||||
return errors.Wrap(err, "validate enabled checks")
|
||||
}
|
||||
|
||||
if err := validateStringsUniq(s.DisabledChecks); err != nil {
|
||||
return errors.Wrap(err, "validate disabled checks")
|
||||
}
|
||||
|
||||
if err := s.validateCheckerNames(log); err != nil {
|
||||
return errors.Wrap(err, "validation failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) isCheckEnabled(name string) bool {
|
||||
return s.inferredEnabledChecks[strings.ToLower(name)]
|
||||
}
|
||||
|
||||
// getAllCheckerNames returns a map containing all checker names supported by gocritic.
|
||||
func (s *goCriticSettingsWrapper) getAllCheckerNames() map[string]bool {
|
||||
allCheckerNames := make(map[string]bool, len(s.allCheckers))
|
||||
|
||||
for _, checker := range s.allCheckers {
|
||||
allCheckerNames[strings.ToLower(checker.Name)] = true
|
||||
}
|
||||
|
||||
return allCheckerNames
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) getDefaultEnabledCheckersNames() []string {
|
||||
var enabled []string
|
||||
|
||||
for _, info := range s.allCheckers {
|
||||
enable := s.isEnabledByDefaultCheck(info)
|
||||
if enable {
|
||||
enabled = append(enabled, info.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return enabled
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) getDefaultDisabledCheckersNames() []string {
|
||||
var disabled []string
|
||||
|
||||
for _, info := range s.allCheckers {
|
||||
enable := s.isEnabledByDefaultCheck(info)
|
||||
if !enable {
|
||||
disabled = append(disabled, info.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return disabled
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) validateCheckerNames(log logutils.Log) error {
|
||||
allowedNames := s.getAllCheckerNames()
|
||||
|
||||
for _, name := range s.EnabledChecks {
|
||||
if !allowedNames[strings.ToLower(name)] {
|
||||
return fmt.Errorf("enabled checker %s doesn't exist, all existing checkers: %s",
|
||||
name, sprintAllowedCheckerNames(allowedNames))
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range s.DisabledChecks {
|
||||
if !allowedNames[strings.ToLower(name)] {
|
||||
return fmt.Errorf("disabled checker %s doesn't exist, all existing checkers: %s",
|
||||
name, sprintAllowedCheckerNames(allowedNames))
|
||||
}
|
||||
}
|
||||
|
||||
for checkName := range s.SettingsPerCheck {
|
||||
if _, ok := allowedNames[checkName]; !ok {
|
||||
return fmt.Errorf("invalid setting, checker %s doesn't exist, all existing checkers: %s",
|
||||
checkName, sprintAllowedCheckerNames(allowedNames))
|
||||
}
|
||||
|
||||
if !s.isCheckEnabled(checkName) {
|
||||
log.Warnf("%s: settings were provided for not enabled check %q", goCriticName, checkName)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) getLowerCasedParams() map[string]config.GoCriticCheckSettings {
|
||||
ret := make(map[string]config.GoCriticCheckSettings, len(s.SettingsPerCheck))
|
||||
|
||||
for checker, params := range s.SettingsPerCheck {
|
||||
ret[strings.ToLower(checker)] = params
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) filterByDisableTags(enabledChecks, disableTags []string, log logutils.Log) []string {
|
||||
enabledChecksSet := stringsSliceToSet(enabledChecks)
|
||||
|
||||
for _, enabledCheck := range enabledChecks {
|
||||
checkInfo, checkInfoExists := s.allCheckerMap[enabledCheck]
|
||||
if !checkInfoExists {
|
||||
log.Warnf("%s: check %q was not exists via filtering disabled tags", goCriticName, enabledCheck)
|
||||
continue
|
||||
}
|
||||
|
||||
hitTags := intersectStringSlice(checkInfo.Tags, disableTags)
|
||||
if len(hitTags) != 0 {
|
||||
delete(enabledChecksSet, enabledCheck)
|
||||
}
|
||||
}
|
||||
|
||||
debugChecksListf(enabledChecks, "Disabled by config tags %s", sprintStrings(disableTags))
|
||||
|
||||
enabledChecks = nil
|
||||
for enabledCheck := range enabledChecksSet {
|
||||
enabledChecks = append(enabledChecks, enabledCheck)
|
||||
}
|
||||
|
||||
return enabledChecks
|
||||
}
|
||||
|
||||
func (s *goCriticSettingsWrapper) isEnabledByDefaultCheck(info *gocriticlinter.CheckerInfo) bool {
|
||||
return !info.HasTag("experimental") &&
|
||||
!info.HasTag("opinionated") &&
|
||||
!info.HasTag("performance")
|
||||
}
|
||||
|
||||
func validateStringsUniq(ss []string) error {
|
||||
set := map[string]bool{}
|
||||
|
||||
for _, s := range ss {
|
||||
_, ok := set[s]
|
||||
if ok {
|
||||
return fmt.Errorf("%q occurs multiple times in list", s)
|
||||
}
|
||||
set[s] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func intersectStringSlice(s1, s2 []string) []string {
|
||||
s1Map := make(map[string]struct{}, len(s1))
|
||||
|
||||
for _, s := range s1 {
|
||||
s1Map[s] = struct{}{}
|
||||
}
|
||||
|
||||
results := make([]string, 0)
|
||||
for _, s := range s2 {
|
||||
if _, exists := s1Map[s]; exists {
|
||||
results = append(results, s)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
func sprintAllowedCheckerNames(allowedNames map[string]bool) string {
|
||||
namesSlice := make([]string, 0, len(allowedNames))
|
||||
|
||||
for name := range allowedNames {
|
||||
namesSlice = append(namesSlice, name)
|
||||
}
|
||||
|
||||
return sprintStrings(namesSlice)
|
||||
}
|
||||
|
||||
func sprintStrings(ss []string) string {
|
||||
sort.Strings(ss)
|
||||
return fmt.Sprint(ss)
|
||||
}
|
||||
|
||||
func debugChecksListf(checks []string, format string, args ...interface{}) {
|
||||
if !isGoCriticDebug {
|
||||
return
|
||||
}
|
||||
|
||||
goCriticDebugf("%s checks (%d): %s", fmt.Sprintf(format, args...), len(checks), sprintStrings(checks))
|
||||
}
|
||||
|
||||
func stringsSliceToSet(ss []string) map[string]bool {
|
||||
ret := make(map[string]bool, len(ss))
|
||||
for _, s := range ss {
|
||||
ret[s] = true
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package config
|
||||
package golinters
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -25,7 +25,9 @@ func Test_filterByDisableTags(t *testing.T) {
|
||||
disabledTags := []string{"experimental", "opinionated"}
|
||||
enabledChecks := []string{"appendAssign", "sortSlice", "caseOrder", "dupImport"}
|
||||
|
||||
filterEnabledChecks := filterByDisableTags(enabledChecks, disabledTags, &tLog{})
|
||||
settingsWrapper := newGoCriticSettingsWrapper(nil)
|
||||
|
||||
filterEnabledChecks := settingsWrapper.filterByDisableTags(enabledChecks, disabledTags, &tLog{})
|
||||
|
||||
sort.Strings(filterEnabledChecks)
|
||||
|
@ -88,7 +88,7 @@ func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]r
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
line = strings.Replace(line, "\t", tabSpaces, -1)
|
||||
line = strings.ReplaceAll(line, "\t", tabSpaces)
|
||||
lineLen := utf8.RuneCountInString(line)
|
||||
if lineLen > maxLineLen {
|
||||
res = append(res, result.Issue{
|
||||
|
@ -119,7 +119,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
gciCfg *config.GciSettings
|
||||
gocognitCfg *config.GocognitSettings
|
||||
goconstCfg *config.GoConstSettings
|
||||
gocriticCfg *config.GocriticSettings
|
||||
gocriticCfg *config.GoCriticSettings
|
||||
gocycloCfg *config.GoCycloSettings
|
||||
godotCfg *config.GodotSettings
|
||||
godoxCfg *config.GodoxSettings
|
||||
@ -436,7 +436,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/jgautheron/goconst"),
|
||||
|
||||
linter.NewConfig(golinters.NewGocritic(gocriticCfg, m.cfg)).
|
||||
linter.NewConfig(golinters.NewGoCritic(gocriticCfg, m.cfg)).
|
||||
WithSince("v1.12.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetMetaLinter).
|
||||
WithLoadForGoAnalysis().
|
||||
|
@ -31,8 +31,8 @@ func (p PathShortener) Name() string {
|
||||
func (p PathShortener) Process(issues []result.Issue) ([]result.Issue, error) {
|
||||
return transformIssues(issues, func(i *result.Issue) *result.Issue {
|
||||
newI := i
|
||||
newI.Text = strings.Replace(newI.Text, p.wd+"/", "", -1)
|
||||
newI.Text = strings.Replace(newI.Text, p.wd, "", -1)
|
||||
newI.Text = strings.ReplaceAll(newI.Text, p.wd+"/", "")
|
||||
newI.Text = strings.ReplaceAll(newI.Text, p.wd, "")
|
||||
return newI
|
||||
}), nil
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ func errorCheck(outStr string, wantAuto bool, defaultWantedLinter string, fullsh
|
||||
for i := range out {
|
||||
for j := 0; j < len(fullshort); j += 2 {
|
||||
full, short := fullshort[j], fullshort[j+1]
|
||||
out[i] = strings.Replace(out[i], full, short, -1)
|
||||
out[i] = strings.ReplaceAll(out[i], full, short)
|
||||
}
|
||||
}
|
||||
|
||||
|
5
test/testdata/configs/gocritic.yml
vendored
5
test/testdata/configs/gocritic.yml
vendored
@ -3,10 +3,11 @@ linters-settings:
|
||||
enabled-checks:
|
||||
- rangeValCopy
|
||||
- flagDeref
|
||||
- wrapperFunc
|
||||
- ruleguard
|
||||
settings:
|
||||
rangevalcopy:
|
||||
sizethreshold: 2
|
||||
rangeValCopy:
|
||||
sizeThreshold: 2
|
||||
ruleguard:
|
||||
debug: dupSubExpr
|
||||
failOn: dsl,import
|
||||
|
4
test/testdata/gocritic.go
vendored
4
test/testdata/gocritic.go
vendored
@ -42,3 +42,7 @@ func gocriticDup(x bool) {
|
||||
log.Print("x is true")
|
||||
}
|
||||
}
|
||||
|
||||
func gocriticRuleWrapperFunc() {
|
||||
strings.Replace("abcabc", "a", "d", -1) // ERROR "ruleguard: this Replace call can be simplified.*"
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ func (r *LintRunner) RunCommandWithYamlConfig(cfg, command string, args ...strin
|
||||
}
|
||||
|
||||
cfg = strings.TrimSpace(cfg)
|
||||
cfg = strings.Replace(cfg, "\t", " ", -1)
|
||||
cfg = strings.ReplaceAll(cfg, "\t", " ")
|
||||
|
||||
err = os.WriteFile(cfgPath, []byte(cfg), os.ModePerm)
|
||||
assert.NoError(r.t, err)
|
||||
|
Loading…
x
Reference in New Issue
Block a user