Skip to content

Commit 00cc233

Browse files
committed
feat: [gocritic] support disabled-tags
1 parent 6771bea commit 00cc233

File tree

4 files changed

+127
-5
lines changed

4 files changed

+127
-5
lines changed

.golangci.example.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ linters-settings:
117117
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
118118
enabled-tags:
119119
- performance
120+
disabled-tags:
121+
- experimental
120122

121123
settings: # settings passed to gocritic
122124
captLocal: # must be valid enabled check name

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,8 @@ linters-settings:
727727
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
728728
enabled-tags:
729729
- performance
730+
disabled-tags:
731+
- experimental
730732
731733
settings: # settings passed to gocritic
732734
captLocal: # must be valid enabled check name

pkg/config/config_gocritic.go

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,26 @@ import (
1515

1616
const gocriticDebugKey = "gocritic"
1717

18-
var gocriticDebugf = logutils.Debug(gocriticDebugKey)
19-
var isGocriticDebug = logutils.HaveDebugTag(gocriticDebugKey)
20-
21-
var allGocriticCheckers = lintpack.GetCheckersInfo()
18+
var (
19+
gocriticDebugf = logutils.Debug(gocriticDebugKey)
20+
isGocriticDebug = logutils.HaveDebugTag(gocriticDebugKey)
21+
allGocriticCheckers = lintpack.GetCheckersInfo()
22+
allGocriticCheckerMap = func() map[string]*lintpack.CheckerInfo {
23+
checkInfoMap := make(map[string]*lintpack.CheckerInfo)
24+
for _, checkInfo := range allGocriticCheckers {
25+
checkInfoMap[checkInfo.Name] = checkInfo
26+
}
27+
return checkInfoMap
28+
}()
29+
)
2230

2331
type GocriticCheckSettings map[string]interface{}
2432

2533
type GocriticSettings struct {
2634
EnabledChecks []string `mapstructure:"enabled-checks"`
2735
DisabledChecks []string `mapstructure:"disabled-checks"`
2836
EnabledTags []string `mapstructure:"enabled-tags"`
37+
DisabledTags []string `mapstructure:"disabled-tags"`
2938
SettingsPerCheck map[string]GocriticCheckSettings `mapstructure:"settings"`
3039

3140
inferredEnabledChecks map[string]bool
@@ -107,6 +116,8 @@ func (s *GocriticSettings) InferEnabledChecks(log logutils.Log) {
107116
debugChecksListf(disabledByDefaultChecks, "Disabled by default")
108117

109118
var enabledChecks []string
119+
120+
// EnabledTags
110121
if len(s.EnabledTags) != 0 {
111122
tagToCheckers := buildGocriticTagToCheckersMap()
112123
for _, tag := range s.EnabledTags {
@@ -120,6 +131,12 @@ func (s *GocriticSettings) InferEnabledChecks(log logutils.Log) {
120131
enabledChecks = append(enabledChecks, enabledByDefaultChecks...)
121132
}
122133

134+
// DisabledTags
135+
if len(s.DisabledTags) != 0 {
136+
enabledChecks = filterByDisableTags(enabledChecks, s.DisabledTags, log)
137+
}
138+
139+
// EnabledChecks
123140
if len(s.EnabledChecks) != 0 {
124141
debugChecksListf(s.EnabledChecks, "Enabled by config")
125142

@@ -133,6 +150,7 @@ func (s *GocriticSettings) InferEnabledChecks(log logutils.Log) {
133150
}
134151
}
135152

153+
// DisabledChecks
136154
if len(s.DisabledChecks) != 0 {
137155
debugChecksListf(s.DisabledChecks, "Disabled by config")
138156

@@ -174,6 +192,22 @@ func validateStringsUniq(ss []string) error {
174192
return nil
175193
}
176194

195+
func intersectStringSlice(s1, s2 []string) []string {
196+
s1Map := make(map[string]struct{})
197+
for _, s := range s1 {
198+
s1Map[s] = struct{}{}
199+
}
200+
201+
result := make([]string, 0)
202+
for _, s := range s2 {
203+
if _, exists := s1Map[s]; exists {
204+
result = append(result, s)
205+
}
206+
}
207+
208+
return result
209+
}
210+
177211
func (s *GocriticSettings) Validate(log logutils.Log) error {
178212
if len(s.EnabledTags) == 0 {
179213
if len(s.EnabledChecks) != 0 && len(s.DisabledChecks) != 0 {
@@ -187,7 +221,16 @@ func (s *GocriticSettings) Validate(log logutils.Log) error {
187221
tagToCheckers := buildGocriticTagToCheckersMap()
188222
for _, tag := range s.EnabledTags {
189223
if _, ok := tagToCheckers[tag]; !ok {
190-
return fmt.Errorf("gocritic tag %q doesn't exist", tag)
224+
return fmt.Errorf("gocritic [enabled]tag %q doesn't exist", tag)
225+
}
226+
}
227+
}
228+
229+
if len(s.DisabledTags) > 0 {
230+
tagToCheckers := buildGocriticTagToCheckersMap()
231+
for _, tag := range s.EnabledTags {
232+
if _, ok := tagToCheckers[tag]; !ok {
233+
return fmt.Errorf("gocritic [disabled]tag %q doesn't exist", tag)
191234
}
192235
}
193236
}
@@ -301,3 +344,24 @@ func (s *GocriticSettings) GetLowercasedParams() map[string]GocriticCheckSetting
301344
}
302345
return ret
303346
}
347+
348+
func filterByDisableTags(enabledChecks, disableTags []string, log logutils.Log) []string {
349+
enabledChecksSet := stringsSliceToSet(enabledChecks)
350+
for _, enabledCheck := range enabledChecks {
351+
checkInfo, checkInfoExists := allGocriticCheckerMap[enabledCheck]
352+
if !checkInfoExists {
353+
log.Warnf("Gocritic check %q was not exists via filtering disabled tags", enabledCheck)
354+
continue
355+
}
356+
hitTags := intersectStringSlice(checkInfo.Tags, disableTags)
357+
if len(hitTags) != 0 {
358+
delete(enabledChecksSet, enabledCheck)
359+
}
360+
debugChecksListf(enabledChecks, "Disabled by config tags %s", sprintStrings(disableTags))
361+
}
362+
enabledChecks = nil
363+
for enabledCheck := range enabledChecksSet {
364+
enabledChecks = append(enabledChecks, enabledCheck)
365+
}
366+
return enabledChecks
367+
}

pkg/config/config_gocritic_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"sort"
6+
"testing"
7+
8+
"github.com/golangci/golangci-lint/pkg/logutils"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestUtils(t *testing.T) {
14+
s1 := []string{"diagnostic", "experimental", "opinionated"}
15+
s2 := []string{"opinionated", "experimental"}
16+
s3 := intersectStringSlice(s1, s2)
17+
sort.Strings(s3)
18+
assert.Equal(t, s3, []string{"experimental", "opinionated"})
19+
}
20+
21+
type tLog struct{}
22+
23+
func (l *tLog) Fatalf(format string, args ...interface{}) {
24+
fmt.Printf(fmt.Sprintf(format, args...) + "\n")
25+
}
26+
27+
func (l *tLog) Panicf(format string, args ...interface{}) {
28+
fmt.Printf(fmt.Sprintf(format, args...) + "\n")
29+
}
30+
31+
func (l *tLog) Errorf(format string, args ...interface{}) {
32+
fmt.Printf(fmt.Sprintf(format, args...) + "\n")
33+
}
34+
35+
func (l *tLog) Warnf(format string, args ...interface{}) {
36+
fmt.Printf(fmt.Sprintf(format, args...) + "\n")
37+
}
38+
39+
func (l *tLog) Infof(format string, args ...interface{}) {
40+
fmt.Printf(fmt.Sprintf(format, args...) + "\n")
41+
}
42+
43+
func (l *tLog) Child(name string) logutils.Log { return nil }
44+
45+
func (l *tLog) SetLevel(level logutils.LogLevel) {}
46+
47+
func TestFilterByDisableTags(t *testing.T) {
48+
testLog := &tLog{}
49+
disabledTags := []string{"experimental", "opinionated"}
50+
enabledChecks := []string{"appendAssign", "argOrder", "caseOrder", "codegenComment"}
51+
filterEnabledChecks := filterByDisableTags(enabledChecks, disabledTags, testLog)
52+
sort.Strings(filterEnabledChecks)
53+
assert.Equal(t, []string{"appendAssign", "caseOrder"}, filterEnabledChecks)
54+
}

0 commit comments

Comments
 (0)