Skip to content

Commit e2b927f

Browse files
authored
Merge pull request #1036 from iwankgb/exclude-case-sensitive
Adding case-sensitive exclude processor
2 parents 0fb48ad + 078f44f commit e2b927f

File tree

10 files changed

+203
-27
lines changed

10 files changed

+203
-27
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,7 @@ Flags:
574574
# gosec: False positive is triggered by 'src, err := ioutil.ReadFile(filename)'
575575
- Potential file inclusion via variable
576576
(default true)
577+
--exclude-case-sensitive If set to true exclude and exclude rules regular expressions are case sensitive
577578
--max-issues-per-linter int Maximum issues count per one linter. Set to 0 to disable (default 50)
578579
--max-same-issues int Maximum count of issues with the same text. Set to 0 to disable (default 3)
579580
-n, --new Show only new issues: if there are unstaged changes or untracked files, only those changes are analyzed, else only changes in HEAD~ are analyzed.

docs/demo.svg

Lines changed: 1 addition & 1 deletion
Loading

pkg/commands/run.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ func initFlagSet(fs *pflag.FlagSet, cfg *config.Config, m *lintersdb.Manager, is
189189
ic := &cfg.Issues
190190
fs.StringSliceVarP(&ic.ExcludePatterns, "exclude", "e", nil, wh("Exclude issue by regexp"))
191191
fs.BoolVar(&ic.UseDefaultExcludes, "exclude-use-default", true, getDefaultIssueExcludeHelp())
192+
fs.BoolVar(&ic.ExcludeCaseSensitive, "exclude-case-sensitive", false, wh("If set to true exclude "+
193+
"and exclude rules regular expressions are case sensitive"))
192194

193195
fs.IntVar(&ic.MaxIssuesPerLinter, "max-issues-per-linter", 50,
194196
wh("Maximum issues count per one linter. Set to 0 to disable"))

pkg/config/config.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,9 +411,10 @@ func (e ExcludeRule) Validate() error {
411411
}
412412

413413
type Issues struct {
414-
ExcludePatterns []string `mapstructure:"exclude"`
415-
ExcludeRules []ExcludeRule `mapstructure:"exclude-rules"`
416-
UseDefaultExcludes bool `mapstructure:"exclude-use-default"`
414+
ExcludeCaseSensitive bool `mapstructure:"exclude-case-sensitive"`
415+
ExcludePatterns []string `mapstructure:"exclude"`
416+
ExcludeRules []ExcludeRule `mapstructure:"exclude-rules"`
417+
UseDefaultExcludes bool `mapstructure:"exclude-use-default"`
417418

418419
MaxIssuesPerLinter int `mapstructure:"max-issues-per-linter"`
419420
MaxSameIssues int `mapstructure:"max-same-issues"`

pkg/lint/runner.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
4040
excludeTotalPattern = fmt.Sprintf("(%s)", strings.Join(excludePatterns, "|"))
4141
}
4242

43+
var excludeProcessor processors.Processor
44+
if cfg.Issues.ExcludeCaseSensitive {
45+
excludeProcessor = processors.NewExcludeCaseSensitive(excludeTotalPattern)
46+
} else {
47+
excludeProcessor = processors.NewExclude(excludeTotalPattern)
48+
}
49+
4350
skipFilesProcessor, err := processors.NewSkipFiles(cfg.Run.SkipFiles)
4451
if err != nil {
4552
return nil, err
@@ -63,6 +70,12 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
6370
Linters: r.Linters,
6471
})
6572
}
73+
var excludeRulesProcessor processors.Processor
74+
if cfg.Issues.ExcludeCaseSensitive {
75+
excludeRulesProcessor = processors.NewExcludeRulesCaseSensitive(excludeRules, lineCache, log.Child("exclude_rules"))
76+
} else {
77+
excludeRulesProcessor = processors.NewExcludeRules(excludeRules, lineCache, log.Child("exclude_rules"))
78+
}
6679

6780
return &Runner{
6881
Processors: []processors.Processor{
@@ -81,8 +94,8 @@ func NewRunner(cfg *config.Config, log logutils.Log, goenv *goutil.Env,
8194
// Must be before exclude because users see already marked output and configure excluding by it.
8295
processors.NewIdentifierMarker(),
8396

84-
processors.NewExclude(excludeTotalPattern),
85-
processors.NewExcludeRules(excludeRules, lineCache, log.Child("exclude_rules")),
97+
excludeProcessor,
98+
excludeRulesProcessor,
8699
processors.NewNolint(log.Child("nolint"), dbManager),
87100

88101
processors.NewUniqByLine(cfg),

pkg/result/processors/exclude.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,23 @@ func (p Exclude) Process(issues []result.Issue) ([]result.Issue, error) {
3737
}
3838

3939
func (p Exclude) Finish() {}
40+
41+
type ExcludeCaseSensitive struct {
42+
*Exclude
43+
}
44+
45+
var _ Processor = ExcludeCaseSensitive{}
46+
47+
func NewExcludeCaseSensitive(pattern string) *ExcludeCaseSensitive {
48+
var patternRe *regexp.Regexp
49+
if pattern != "" {
50+
patternRe = regexp.MustCompile(pattern)
51+
}
52+
return &ExcludeCaseSensitive{
53+
&Exclude{pattern: patternRe},
54+
}
55+
}
56+
57+
func (p ExcludeCaseSensitive) Name() string {
58+
return "exclude-case-sensitive"
59+
}

pkg/result/processors/exclude_rules.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,29 @@ func NewExcludeRules(rules []ExcludeRule, lineCache *fsutils.LineCache, log logu
3737
lineCache: lineCache,
3838
log: log,
3939
}
40+
r.rules = createRules(rules, "(?i)")
4041

42+
return r
43+
}
44+
45+
func createRules(rules []ExcludeRule, prefix string) []excludeRule {
46+
parsedRules := make([]excludeRule, 0, len(rules))
4147
for _, rule := range rules {
4248
parsedRule := excludeRule{
4349
linters: rule.Linters,
4450
}
4551
if rule.Text != "" {
46-
parsedRule.text = regexp.MustCompile("(?i)" + rule.Text)
52+
parsedRule.text = regexp.MustCompile(prefix + rule.Text)
4753
}
4854
if rule.Source != "" {
49-
parsedRule.source = regexp.MustCompile("(?i)" + rule.Source)
55+
parsedRule.source = regexp.MustCompile(prefix + rule.Source)
5056
}
5157
if rule.Path != "" {
5258
parsedRule.path = regexp.MustCompile(rule.Path)
5359
}
54-
r.rules = append(r.rules, parsedRule)
60+
parsedRules = append(parsedRules, parsedRule)
5561
}
56-
57-
return r
62+
return parsedRules
5863
}
5964

6065
func (p ExcludeRules) Process(issues []result.Issue) ([]result.Issue, error) {
@@ -118,3 +123,21 @@ func (ExcludeRules) Name() string { return "exclude-rules" }
118123
func (ExcludeRules) Finish() {}
119124

120125
var _ Processor = ExcludeRules{}
126+
127+
type ExcludeRulesCaseSensitive struct {
128+
*ExcludeRules
129+
}
130+
131+
func NewExcludeRulesCaseSensitive(rules []ExcludeRule, lineCache *fsutils.LineCache, log logutils.Log) *ExcludeRulesCaseSensitive {
132+
r := &ExcludeRules{
133+
lineCache: lineCache,
134+
log: log,
135+
}
136+
r.rules = createRules(rules, "")
137+
138+
return &ExcludeRulesCaseSensitive{r}
139+
}
140+
141+
func (ExcludeRulesCaseSensitive) Name() string { return "exclude-rules-case-sensitive" }
142+
143+
var _ Processor = ExcludeCaseSensitive{}

pkg/result/processors/exclude_rules_test.go

Lines changed: 111 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,12 @@ func TestExcludeRulesMultiple(t *testing.T) {
3131
Linters: []string{"lll"},
3232
},
3333
}, lineCache, nil)
34-
type issueCase struct {
35-
Path string
36-
Line int
37-
Text string
38-
Linter string
39-
}
40-
var newIssueCase = func(c issueCase) result.Issue {
41-
return result.Issue{
42-
Text: c.Text,
43-
FromLinter: c.Linter,
44-
Pos: token.Position{
45-
Filename: c.Path,
46-
Line: c.Line,
47-
},
48-
}
49-
}
34+
5035
cases := []issueCase{
5136
{Path: "e.go", Text: "exclude", Linter: "linter"},
5237
{Path: "e.go", Text: "some", Linter: "linter"},
5338
{Path: "e_test.go", Text: "normal", Linter: "testlinter"},
39+
{Path: "e_Test.go", Text: "normal", Linter: "testlinter"},
5440
{Path: "e_test.go", Text: "another", Linter: "linter"},
5541
{Path: "e_test.go", Text: "testonly", Linter: "linter"},
5642
{Path: filepath.Join("testdata", "exclude_rules.go"), Line: 3, Linter: "lll"},
@@ -71,11 +57,30 @@ func TestExcludeRulesMultiple(t *testing.T) {
7157
}
7258
expectedCases := []issueCase{
7359
{Path: "e.go", Text: "some", Linter: "linter"},
60+
{Path: "e_Test.go", Text: "normal", Linter: "testlinter"},
7461
{Path: "e_test.go", Text: "another", Linter: "linter"},
7562
}
7663
assert.Equal(t, expectedCases, resultingCases)
7764
}
7865

66+
type issueCase struct {
67+
Path string
68+
Line int
69+
Text string
70+
Linter string
71+
}
72+
73+
func newIssueCase(c issueCase) result.Issue {
74+
return result.Issue{
75+
Text: c.Text,
76+
FromLinter: c.Linter,
77+
Pos: token.Position{
78+
Filename: c.Path,
79+
Line: c.Line,
80+
},
81+
}
82+
}
83+
7984
func TestExcludeRulesText(t *testing.T) {
8085
p := NewExcludeRules([]ExcludeRule{
8186
{
@@ -103,6 +108,96 @@ func TestExcludeRulesText(t *testing.T) {
103108
}
104109
assert.Equal(t, texts[1:], processedTexts)
105110
}
111+
106112
func TestExcludeRulesEmpty(t *testing.T) {
107113
processAssertSame(t, NewExcludeRules(nil, nil, nil), newTextIssue("test"))
108114
}
115+
116+
func TestExcludeRulesCaseSensitiveMultiple(t *testing.T) {
117+
lineCache := fsutils.NewLineCache(fsutils.NewFileCache())
118+
p := NewExcludeRulesCaseSensitive([]ExcludeRule{
119+
{
120+
Text: "^exclude$",
121+
Linters: []string{"linter"},
122+
},
123+
{
124+
Linters: []string{"testlinter"},
125+
Path: `_test\.go`,
126+
},
127+
{
128+
Text: "^testonly$",
129+
Path: `_test\.go`,
130+
},
131+
{
132+
Source: "^//go:generate ",
133+
Linters: []string{"lll"},
134+
},
135+
}, lineCache, nil)
136+
137+
cases := []issueCase{
138+
{Path: "e.go", Text: "exclude", Linter: "linter"},
139+
{Path: "e.go", Text: "excLude", Linter: "linter"},
140+
{Path: "e.go", Text: "some", Linter: "linter"},
141+
{Path: "e_test.go", Text: "normal", Linter: "testlinter"},
142+
{Path: "e_Test.go", Text: "normal", Linter: "testlinter"},
143+
{Path: "e_test.go", Text: "another", Linter: "linter"},
144+
{Path: "e_test.go", Text: "testonly", Linter: "linter"},
145+
{Path: "e_test.go", Text: "testOnly", Linter: "linter"},
146+
{Path: filepath.Join("testdata", "exclude_rules_case_sensitive.go"), Line: 3, Linter: "lll"},
147+
}
148+
var issues []result.Issue
149+
for _, c := range cases {
150+
issues = append(issues, newIssueCase(c))
151+
}
152+
processedIssues := process(t, p, issues...)
153+
var resultingCases []issueCase
154+
for _, i := range processedIssues {
155+
resultingCases = append(resultingCases, issueCase{
156+
Path: i.FilePath(),
157+
Linter: i.FromLinter,
158+
Text: i.Text,
159+
Line: i.Line(),
160+
})
161+
}
162+
expectedCases := []issueCase{
163+
{Path: "e.go", Text: "excLude", Linter: "linter"},
164+
{Path: "e.go", Text: "some", Linter: "linter"},
165+
{Path: "e_Test.go", Text: "normal", Linter: "testlinter"},
166+
{Path: "e_test.go", Text: "another", Linter: "linter"},
167+
{Path: "e_test.go", Text: "testOnly", Linter: "linter"},
168+
{Path: filepath.Join("testdata", "exclude_rules_case_sensitive.go"), Line: 3, Linter: "lll"},
169+
}
170+
assert.Equal(t, expectedCases, resultingCases)
171+
}
172+
173+
func TestExcludeRulesCaseSensitiveText(t *testing.T) {
174+
p := NewExcludeRulesCaseSensitive([]ExcludeRule{
175+
{
176+
Text: "^exclude$",
177+
Linters: []string{
178+
"linter",
179+
},
180+
},
181+
}, nil, nil)
182+
texts := []string{"exclude", "excLude", "1", "", "exclud", "notexclude"}
183+
var issues []result.Issue
184+
for _, t := range texts {
185+
issues = append(issues, result.Issue{
186+
Text: t,
187+
FromLinter: "linter",
188+
})
189+
}
190+
191+
processedIssues := process(t, p, issues...)
192+
assert.Len(t, processedIssues, len(issues)-1)
193+
194+
var processedTexts []string
195+
for _, i := range processedIssues {
196+
processedTexts = append(processedTexts, i.Text)
197+
}
198+
assert.Equal(t, texts[1:], processedTexts)
199+
}
200+
201+
func TestExcludeRulesCaseSensitiveEmpty(t *testing.T) {
202+
processAssertSame(t, NewExcludeRulesCaseSensitive(nil, nil, nil), newTextIssue("test"))
203+
}

pkg/result/processors/exclude_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,21 @@ func TestExclude(t *testing.T) {
5151
func TestNoExclude(t *testing.T) {
5252
processAssertSame(t, NewExclude(""), newTextIssue("test"))
5353
}
54+
55+
func TestExcludeCaseSensitive(t *testing.T) {
56+
p := NewExcludeCaseSensitive("^exclude$")
57+
texts := []string{"excLude", "1", "", "exclud", "exclude"}
58+
var issues []result.Issue
59+
for _, t := range texts {
60+
issues = append(issues, newTextIssue(t))
61+
}
62+
63+
processedIssues := process(t, p, issues...)
64+
assert.Len(t, processedIssues, len(issues)-1)
65+
66+
var processedTexts []string
67+
for _, i := range processedIssues {
68+
processedTexts = append(processedTexts, i.Text)
69+
}
70+
assert.Equal(t, texts[:len(texts)-1], processedTexts)
71+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package testdata
2+
3+
//GO:generate long line that will be excluded by default processor but will not be affected by case-sensitive one because of capital GO

0 commit comments

Comments
 (0)