1
1
package processors
2
2
3
3
import (
4
- "errors "
4
+ "cmp "
5
5
"fmt"
6
6
"slices"
7
- "sort"
8
7
"strings"
9
8
10
9
"github.com/golangci/golangci-lint/pkg/config"
@@ -22,24 +21,32 @@ const (
22
21
orderNameSeverity = "severity"
23
22
)
24
23
24
+ const (
25
+ less = iota - 1
26
+ equal
27
+ greater
28
+ )
29
+
25
30
var _ Processor = (* SortResults )(nil )
26
31
32
+ type issueComparator func (a , b * result.Issue ) int
33
+
27
34
type SortResults struct {
28
- cmps map [string ]* comparator
35
+ cmps map [string ][] issueComparator
29
36
30
37
cfg * config.Output
31
38
}
32
39
33
40
func NewSortResults (cfg * config.Config ) * SortResults {
34
41
return & SortResults {
35
- cmps : map [string ]* comparator {
42
+ cmps : map [string ][] issueComparator {
36
43
// For sorting we are comparing (in next order):
37
44
// file names, line numbers, position, and finally - giving up.
38
- orderNameFile : byFileName (). SetNext ( byLine (). SetNext ( byColumn ())) ,
45
+ orderNameFile : { byFileName , byLine , byColumn } ,
39
46
// For sorting we are comparing: linter name
40
- orderNameLinter : byLinter () ,
47
+ orderNameLinter : { byLinter } ,
41
48
// For sorting we are comparing: severity
42
- orderNameSeverity : bySeverity () ,
49
+ orderNameSeverity : { bySeverity } ,
43
50
},
44
51
cfg : & cfg .Output ,
45
52
}
@@ -57,171 +64,54 @@ func (p SortResults) Process(issues []result.Issue) ([]result.Issue, error) {
57
64
p .cfg .SortOrder = []string {orderNameFile }
58
65
}
59
66
60
- var cmps []* comparator
67
+ var cmps []issueComparator
68
+
61
69
for _ , name := range p .cfg .SortOrder {
62
70
c , ok := p .cmps [name ]
63
71
if ! ok {
64
72
return nil , fmt .Errorf ("unsupported sort-order name %q" , name )
65
73
}
66
74
67
- cmps = append (cmps , c )
75
+ cmps = append (cmps , c ... )
68
76
}
69
77
70
- cmp , err := mergeComparators (cmps )
71
- if err != nil {
72
- return nil , err
73
- }
78
+ comp := mergeComparators (cmps ... )
74
79
75
- sort . Slice (issues , func (i , j int ) bool {
76
- return cmp . Compare ( & issues [ i ] , & issues [ j ]) == less
80
+ slices . SortFunc (issues , func (a , b result. Issue ) int {
81
+ return comp ( & a , & b )
77
82
})
78
83
79
84
return issues , nil
80
85
}
81
86
82
87
func (SortResults ) Finish () {}
83
88
84
- type compareResult int
85
-
86
- const (
87
- less compareResult = iota - 1
88
- equal
89
- greater
90
- none
91
- )
92
-
93
- func (c compareResult ) isNeutral () bool {
94
- // return true if compare result is incomparable or equal.
95
- return c == none || c == equal
96
- }
97
-
98
- func (c compareResult ) String () string {
99
- switch c {
100
- case less :
101
- return "less"
102
- case equal :
103
- return "equal"
104
- case greater :
105
- return "greater"
106
- default :
107
- return "none"
108
- }
109
- }
110
-
111
- // comparator describes how to implement compare for two "issues".
112
- type comparator struct {
113
- name string
114
- compare func (a , b * result.Issue ) compareResult
115
- next * comparator
116
- }
117
-
118
- func (cmp * comparator ) Next () * comparator { return cmp .next }
119
-
120
- func (cmp * comparator ) SetNext (c * comparator ) * comparator {
121
- cmp .next = c
122
- return cmp
89
+ func byFileName (a , b * result.Issue ) int {
90
+ return strings .Compare (a .FilePath (), b .FilePath ())
123
91
}
124
92
125
- func (cmp * comparator ) String () string {
126
- s := cmp .name
127
- if cmp .Next () != nil {
128
- s += " > " + cmp .Next ().String ()
129
- }
130
-
131
- return s
93
+ func byLine (a , b * result.Issue ) int {
94
+ return numericCompare (a .Line (), b .Line ())
132
95
}
133
96
134
- func (cmp * comparator ) Compare (a , b * result.Issue ) compareResult {
135
- res := cmp .compare (a , b )
136
- if ! res .isNeutral () {
137
- return res
138
- }
139
-
140
- if next := cmp .Next (); next != nil {
141
- return next .Compare (a , b )
142
- }
143
-
144
- return res
97
+ func byColumn (a , b * result.Issue ) int {
98
+ return numericCompare (a .Column (), b .Column ())
145
99
}
146
100
147
- func byFileName () * comparator {
148
- return & comparator {
149
- name : "byFileName" ,
150
- compare : func (a , b * result.Issue ) compareResult {
151
- return compareResult (strings .Compare (a .FilePath (), b .FilePath ()))
152
- },
153
- }
101
+ func byLinter (a , b * result.Issue ) int {
102
+ return strings .Compare (a .FromLinter , b .FromLinter )
154
103
}
155
104
156
- func byLine () * comparator {
157
- return & comparator {
158
- name : "byLine" ,
159
- compare : func (a , b * result.Issue ) compareResult {
160
- return numericCompare (a .Line (), b .Line ())
161
- },
162
- }
105
+ func bySeverity (a , b * result.Issue ) int {
106
+ return severityCompare (a .Severity , b .Severity )
163
107
}
164
108
165
- func byColumn () * comparator {
166
- return & comparator {
167
- name : "byColumn" ,
168
- compare : func (a , b * result.Issue ) compareResult {
169
- return numericCompare (a .Column (), b .Column ())
170
- },
171
- }
172
- }
173
-
174
- func byLinter () * comparator {
175
- return & comparator {
176
- name : "byLinter" ,
177
- compare : func (a , b * result.Issue ) compareResult {
178
- return compareResult (strings .Compare (a .FromLinter , b .FromLinter ))
179
- },
180
- }
181
- }
182
-
183
- func bySeverity () * comparator {
184
- return & comparator {
185
- name : "bySeverity" ,
186
- compare : func (a , b * result.Issue ) compareResult {
187
- return severityCompare (a .Severity , b .Severity )
188
- },
189
- }
190
- }
191
-
192
- func mergeComparators (cmps []* comparator ) (* comparator , error ) {
193
- if len (cmps ) == 0 {
194
- return nil , errors .New ("no comparator" )
195
- }
196
-
197
- for i := range len (cmps ) - 1 {
198
- findComparatorTip (cmps [i ]).SetNext (cmps [i + 1 ])
199
- }
200
-
201
- return cmps [0 ], nil
202
- }
203
-
204
- func findComparatorTip (cmp * comparator ) * comparator {
205
- if cmp .Next () != nil {
206
- return findComparatorTip (cmp .Next ())
207
- }
208
-
209
- return cmp
210
- }
211
-
212
- func severityCompare (a , b string ) compareResult {
109
+ func severityCompare (a , b string ) int {
213
110
// The position inside the slice define the importance (lower to higher).
214
111
classic := []string {"low" , "medium" , "high" , "warning" , "error" }
215
112
216
113
if slices .Contains (classic , a ) && slices .Contains (classic , b ) {
217
- switch {
218
- case slices .Index (classic , a ) > slices .Index (classic , b ):
219
- return greater
220
- case slices .Index (classic , a ) < slices .Index (classic , b ):
221
- return less
222
- default :
223
- return equal
224
- }
114
+ return cmp .Compare (slices .Index (classic , a ), slices .Index (classic , b ))
225
115
}
226
116
227
117
if slices .Contains (classic , a ) {
@@ -232,28 +122,27 @@ func severityCompare(a, b string) compareResult {
232
122
return less
233
123
}
234
124
235
- return compareResult ( strings .Compare (a , b ) )
125
+ return strings .Compare (a , b )
236
126
}
237
127
238
- func numericCompare (a , b int ) compareResult {
239
- var (
240
- isValuesInvalid = a < 0 || b < 0
241
- isZeroValuesBoth = a == 0 && b == 0
242
- isEqual = a == b
243
- isZeroValueInA = b > 0 && a == 0
244
- isZeroValueInB = a > 0 && b == 0
245
- )
246
-
247
- switch {
248
- case isZeroValuesBoth || isEqual :
128
+ func numericCompare (a , b int ) int {
129
+ // Negative values and zeros are skipped (equal) because they either invalid or "neutral" (default int value).
130
+ if a <= 0 || b <= 0 {
249
131
return equal
250
- case isValuesInvalid || isZeroValueInA || isZeroValueInB :
251
- return none
252
- case a > b :
253
- return greater
254
- case a < b :
255
- return less
256
132
}
257
133
258
- return equal
134
+ return cmp .Compare (a , b )
135
+ }
136
+
137
+ func mergeComparators (comps ... issueComparator ) issueComparator {
138
+ return func (a , b * result.Issue ) int {
139
+ for _ , comp := range comps {
140
+ i := comp (a , b )
141
+ if i != equal {
142
+ return i
143
+ }
144
+ }
145
+
146
+ return equal
147
+ }
259
148
}
0 commit comments