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:
dependabot[bot] 2022-08-14 18:21:32 +02:00 committed by GitHub
parent edeaa17fd5
commit 9da04f5070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 486 additions and 423 deletions

View File

@ -1113,7 +1113,7 @@ linters-settings:
makezero: makezero:
# Allow only slices initialized with a length of zero. # Allow only slices initialized with a length of zero.
# Default: false # Default: false
always: false always: true
maligned: maligned:
# Print struct with more effective memory layout or not. # Print struct with more effective memory layout or not.

View File

@ -27,7 +27,6 @@ linters-settings:
- ifElseChain - ifElseChain
- octalLiteral - octalLiteral
- whyNoLint - whyNoLint
- wrapperFunc
gocyclo: gocyclo:
min-complexity: 15 min-complexity: 15
goimports: goimports:

8
go.mod
View File

@ -27,7 +27,7 @@ require (
github.com/fatih/color v1.13.0 github.com/fatih/color v1.13.0
github.com/firefart/nonamedreturns v1.0.4 github.com/firefart/nonamedreturns v1.0.4
github.com/fzipp/gocyclo v0.6.0 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/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2
@ -121,8 +121,8 @@ require (
github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-toolsmith/astcast v1.0.0 // indirect github.com/go-toolsmith/astcast v1.0.0 // indirect
github.com/go-toolsmith/astcopy v1.0.0 // indirect github.com/go-toolsmith/astcopy v1.0.1 // indirect
github.com/go-toolsmith/astequal 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/astfmt v1.0.0 // indirect
github.com/go-toolsmith/astp v1.0.0 // indirect github.com/go-toolsmith/astp v1.0.0 // indirect
github.com/go-toolsmith/strparse 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/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // 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/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect

17
go.sum generated
View File

@ -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/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.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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 h1:wUAqXChk8HbwXn8AfxD9DYSCp9Bpz1L3e6Q4Roe+q9E=
github.com/daixiang0/gci v0.6.3/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= 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= 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 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= 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/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.4 h1:tucuG1pvOyYgpBIrVxw0R6gwO42lNa92Aq3VaDoIs+E=
github.com/go-critic/go-critic v0.6.3/go.mod h1:c6b3ZP1MQ7o6lPR7Rv3lEf7pYQUmAcx8ABHgdZCQt/k= 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 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-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/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-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 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= 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.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.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.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 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg= 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/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/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.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.17 h1:cDdoaSbQg11LXPDQqiCK54QmQXsEQQCTIgdcpeULGSI=
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/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.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 h1:vNkC6fC6qMLzCOGbnIHOd5ixUGgTbp3Z4fGnUgULlDA=
github.com/quasilyte/go-ruleguard/dsl v0.3.21/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= 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= 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-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-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 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 h1:+W8Qf4iJtMGKkyAygcKohjxTk4JPsL9DpzApJ22m5Ic=
golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= 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= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=

View File

@ -117,11 +117,6 @@ func NewExecutor(version, commit, date string) *Executor {
// recreate after getting config // recreate after getting config
e.DBManager = lintersdb.NewManager(e.cfg, e.log).WithCustomLinters() 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. // Slice options must be explicitly set for proper merging of config and command-line options.
fixSlicesFlags(e.runCmd.Flags()) fixSlicesFlags(e.runCmd.Flags())
fixSlicesFlags(e.lintersCmd.Flags()) fixSlicesFlags(e.lintersCmd.Flags())

View File

@ -40,8 +40,8 @@ var defaultLintersSettings = LintersSettings{
Gocognit: GocognitSettings{ Gocognit: GocognitSettings{
MinComplexity: 30, MinComplexity: 30,
}, },
Gocritic: GocriticSettings{ Gocritic: GoCriticSettings{
SettingsPerCheck: map[string]GocriticCheckSettings{}, SettingsPerCheck: map[string]GoCriticCheckSettings{},
}, },
Godox: GodoxSettings{ Godox: GodoxSettings{
Keywords: []string{}, Keywords: []string{},
@ -133,7 +133,7 @@ type LintersSettings struct {
Gci GciSettings Gci GciSettings
Gocognit GocognitSettings Gocognit GocognitSettings
Goconst GoConstSettings Goconst GoConstSettings
Gocritic GocriticSettings Gocritic GoCriticSettings
Gocyclo GoCycloSettings Gocyclo GoCycloSettings
Godot GodotSettings Godot GodotSettings
Godox GodoxSettings Godox GodoxSettings
@ -306,6 +306,16 @@ type GoConstSettings struct {
IgnoreCalls bool `mapstructure:"ignore-calls"` 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 { type GoCycloSettings struct {
MinComplexity int `mapstructure:"min-complexity"` MinComplexity int `mapstructure:"min-complexity"`
} }

View File

@ -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
}

View File

@ -11,31 +11,39 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/go-critic/go-critic/checkers"
gocriticlinter "github.com/go-critic/go-critic/framework/linter" gocriticlinter "github.com/go-critic/go-critic/framework/linter"
"github.com/pkg/errors"
"golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis"
"github.com/golangci/golangci-lint/pkg/config" "github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis" "github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter" "github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/logutils"
"github.com/golangci/golangci-lint/pkg/result" "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 mu sync.Mutex
var resIssues []goanalysis.Issue var resIssues []goanalysis.Issue
sizes := types.SizesFor("gc", runtime.GOARCH) wrapper := &goCriticWrapper{
wrapper := goCriticWrapper{
settings: settings, settings: settings,
cfg: cfg, cfg: cfg,
sizes: sizes, sizes: types.SizesFor("gc", runtime.GOARCH),
} }
analyzer := &analysis.Analyzer{ analyzer := &analysis.Analyzer{
Name: gocriticName, Name: goCriticName,
Doc: goanalysis.TheOnlyanalyzerDoc, Doc: goanalysis.TheOnlyanalyzerDoc,
Run: func(pass *analysis.Pass) (interface{}, error) { Run: func(pass *analysis.Pass) (interface{}, error) {
issues, err := wrapper.run(pass) issues, err := wrapper.run(pass)
@ -56,24 +64,56 @@ func NewGocritic(settings *config.GocriticSettings, cfg *config.Config) *goanaly
} }
return goanalysis.NewLinter( return goanalysis.NewLinter(
gocriticName, goCriticName,
`Provides diagnostics that check for bugs, performance and style issues. `Provides diagnostics that check for bugs, performance and style issues.
Extensible without recompilation through dynamic rules. Extensible without recompilation through dynamic rules.
Dynamic rules are written declaratively with AST patterns, filters, report message and optional suggestion.`, Dynamic rules are written declaratively with AST patterns, filters, report message and optional suggestion.`,
[]*analysis.Analyzer{analyzer}, []*analysis.Analyzer{analyzer},
nil, nil,
).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue { ).
return resIssues WithContextSetter(func(context *linter.Context) {
}).WithLoadMode(goanalysis.LoadModeTypesInfo) wrapper.init()
}).
WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
return resIssues
}).WithLoadMode(goanalysis.LoadModeTypesInfo)
} }
type goCriticWrapper struct { type goCriticWrapper struct {
settings *config.GocriticSettings settings *config.GoCriticSettings
cfg *config.Config settingsWrapper *goCriticSettingsWrapper
sizes types.Sizes 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) linterCtx := gocriticlinter.NewContext(pass.Fset, w.sizes)
enabledCheckers, err := w.buildEnabledCheckers(linterCtx) enabledCheckers, err := w.buildEnabledCheckers(linterCtx)
@ -93,12 +133,12 @@ func (w goCriticWrapper) run(pass *analysis.Pass) ([]goanalysis.Issue, error) {
return issues, nil return issues, nil
} }
func (w goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) { func (w *goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context) ([]*gocriticlinter.Checker, error) {
allParams := w.settings.GetLowercasedParams() allParams := w.settingsWrapper.getLowerCasedParams()
var enabledCheckers []*gocriticlinter.Checker var enabledCheckers []*gocriticlinter.Checker
for _, info := range gocriticlinter.GetCheckersInfo() { for _, info := range gocriticlinter.GetCheckersInfo() {
if !w.settings.IsCheckEnabled(info.Name) { if !w.settingsWrapper.isCheckEnabled(info.Name) {
continue continue
} }
@ -116,23 +156,23 @@ func (w goCriticWrapper) buildEnabledCheckers(linterCtx *gocriticlinter.Context)
return enabledCheckers, nil return enabledCheckers, nil
} }
func runGocriticOnPackage(linterCtx *gocriticlinter.Context, checkers []*gocriticlinter.Checker, func runGocriticOnPackage(linterCtx *gocriticlinter.Context, checks []*gocriticlinter.Checker,
files []*ast.File) []result.Issue { files []*ast.File) []result.Issue {
var res []result.Issue var res []result.Issue
for _, f := range files { for _, f := range files {
filename := filepath.Base(linterCtx.FileSet.Position(f.Pos()).Filename) filename := filepath.Base(linterCtx.FileSet.Position(f.Pos()).Filename)
linterCtx.SetFileInfo(filename, f) linterCtx.SetFileInfo(filename, f)
issues := runGocriticOnFile(linterCtx, f, checkers) issues := runGocriticOnFile(linterCtx, f, checks)
res = append(res, issues...) res = append(res, issues...)
} }
return res 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 var res []result.Issue
for _, c := range checkers { for _, c := range checks {
// All checkers are expected to use *lint.Context // All checkers are expected to use *lint.Context
// as read-only structure, so no copying is required. // as read-only structure, so no copying is required.
for _, warn := range c.Check(f) { for _, warn := range c.Check(f) {
@ -140,7 +180,7 @@ func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checkers
issue := result.Issue{ issue := result.Issue{
Pos: pos, Pos: pos,
Text: fmt.Sprintf("%s: %s", c.Info.Name, warn.Text), Text: fmt.Sprintf("%s: %s", c.Info.Name, warn.Text),
FromLinter: gocriticName, FromLinter: goCriticName,
} }
if warn.HasQuickFix() { if warn.HasQuickFix() {
@ -160,7 +200,7 @@ func runGocriticOnFile(linterCtx *gocriticlinter.Context, f *ast.File, checkers
return res 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)] params := allParams[strings.ToLower(info.Name)]
if params == nil { // no config for this checker if params == nil { // no config for this checker
return nil 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. // 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. // 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. // 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) rv := reflect.ValueOf(p)
switch rv.Type().Kind() { switch rv.Type().Kind() {
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
@ -222,3 +262,378 @@ func (w goCriticWrapper) normalizeCheckerParamsValue(p interface{}) interface{}
return p 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
}

View File

@ -1,4 +1,4 @@
package config package golinters
import ( import (
"log" "log"
@ -25,7 +25,9 @@ func Test_filterByDisableTags(t *testing.T) {
disabledTags := []string{"experimental", "opinionated"} disabledTags := []string{"experimental", "opinionated"}
enabledChecks := []string{"appendAssign", "sortSlice", "caseOrder", "dupImport"} enabledChecks := []string{"appendAssign", "sortSlice", "caseOrder", "dupImport"}
filterEnabledChecks := filterByDisableTags(enabledChecks, disabledTags, &tLog{}) settingsWrapper := newGoCriticSettingsWrapper(nil)
filterEnabledChecks := settingsWrapper.filterByDisableTags(enabledChecks, disabledTags, &tLog{})
sort.Strings(filterEnabledChecks) sort.Strings(filterEnabledChecks)

View File

@ -88,7 +88,7 @@ func getLLLIssuesForFile(filename string, maxLineLen int, tabSpaces string) ([]r
scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
line = strings.Replace(line, "\t", tabSpaces, -1) line = strings.ReplaceAll(line, "\t", tabSpaces)
lineLen := utf8.RuneCountInString(line) lineLen := utf8.RuneCountInString(line)
if lineLen > maxLineLen { if lineLen > maxLineLen {
res = append(res, result.Issue{ res = append(res, result.Issue{

View File

@ -119,7 +119,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
gciCfg *config.GciSettings gciCfg *config.GciSettings
gocognitCfg *config.GocognitSettings gocognitCfg *config.GocognitSettings
goconstCfg *config.GoConstSettings goconstCfg *config.GoConstSettings
gocriticCfg *config.GocriticSettings gocriticCfg *config.GoCriticSettings
gocycloCfg *config.GoCycloSettings gocycloCfg *config.GoCycloSettings
godotCfg *config.GodotSettings godotCfg *config.GodotSettings
godoxCfg *config.GodoxSettings godoxCfg *config.GodoxSettings
@ -436,7 +436,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithPresets(linter.PresetStyle). WithPresets(linter.PresetStyle).
WithURL("https://github.com/jgautheron/goconst"), WithURL("https://github.com/jgautheron/goconst"),
linter.NewConfig(golinters.NewGocritic(gocriticCfg, m.cfg)). linter.NewConfig(golinters.NewGoCritic(gocriticCfg, m.cfg)).
WithSince("v1.12.0"). WithSince("v1.12.0").
WithPresets(linter.PresetStyle, linter.PresetMetaLinter). WithPresets(linter.PresetStyle, linter.PresetMetaLinter).
WithLoadForGoAnalysis(). WithLoadForGoAnalysis().

View File

@ -31,8 +31,8 @@ func (p PathShortener) Name() string {
func (p PathShortener) Process(issues []result.Issue) ([]result.Issue, error) { func (p PathShortener) Process(issues []result.Issue) ([]result.Issue, error) {
return transformIssues(issues, func(i *result.Issue) *result.Issue { return transformIssues(issues, func(i *result.Issue) *result.Issue {
newI := i newI := i
newI.Text = strings.Replace(newI.Text, p.wd+"/", "", -1) newI.Text = strings.ReplaceAll(newI.Text, p.wd+"/", "")
newI.Text = strings.Replace(newI.Text, p.wd, "", -1) newI.Text = strings.ReplaceAll(newI.Text, p.wd, "")
return newI return newI
}), nil }), nil
} }

View File

@ -33,7 +33,7 @@ func errorCheck(outStr string, wantAuto bool, defaultWantedLinter string, fullsh
for i := range out { for i := range out {
for j := 0; j < len(fullshort); j += 2 { for j := 0; j < len(fullshort); j += 2 {
full, short := fullshort[j], fullshort[j+1] full, short := fullshort[j], fullshort[j+1]
out[i] = strings.Replace(out[i], full, short, -1) out[i] = strings.ReplaceAll(out[i], full, short)
} }
} }

View File

@ -3,10 +3,11 @@ linters-settings:
enabled-checks: enabled-checks:
- rangeValCopy - rangeValCopy
- flagDeref - flagDeref
- wrapperFunc
- ruleguard - ruleguard
settings: settings:
rangevalcopy: rangeValCopy:
sizethreshold: 2 sizeThreshold: 2
ruleguard: ruleguard:
debug: dupSubExpr debug: dupSubExpr
failOn: dsl,import failOn: dsl,import

View File

@ -42,3 +42,7 @@ func gocriticDup(x bool) {
log.Print("x is true") log.Print("x is true")
} }
} }
func gocriticRuleWrapperFunc() {
strings.Replace("abcabc", "a", "d", -1) // ERROR "ruleguard: this Replace call can be simplified.*"
}

View File

@ -154,7 +154,7 @@ func (r *LintRunner) RunCommandWithYamlConfig(cfg, command string, args ...strin
} }
cfg = strings.TrimSpace(cfg) cfg = strings.TrimSpace(cfg)
cfg = strings.Replace(cfg, "\t", " ", -1) cfg = strings.ReplaceAll(cfg, "\t", " ")
err = os.WriteFile(cfgPath, []byte(cfg), os.ModePerm) err = os.WriteFile(cfgPath, []byte(cfg), os.ModePerm)
assert.NoError(r.t, err) assert.NoError(r.t, err)