11package processors
22
33import (
4- "errors "
4+ "cmp "
55 "fmt"
66 "slices"
7- "sort"
87 "strings"
98
109 "github.com/golangci/golangci-lint/pkg/config"
@@ -22,24 +21,32 @@ const (
2221 orderNameSeverity = "severity"
2322)
2423
24+ const (
25+ less = iota - 1
26+ equal
27+ greater
28+ )
29+
2530var _ Processor = (* SortResults )(nil )
2631
32+ type issueComparator func (a , b * result.Issue ) int
33+
2734type SortResults struct {
28- cmps map [string ]* comparator
35+ cmps map [string ][] issueComparator
2936
3037 cfg * config.Output
3138}
3239
3340func NewSortResults (cfg * config.Config ) * SortResults {
3441 return & SortResults {
35- cmps : map [string ]* comparator {
42+ cmps : map [string ][] issueComparator {
3643 // For sorting we are comparing (in next order):
3744 // file names, line numbers, position, and finally - giving up.
38- orderNameFile : byFileName (). SetNext ( byLine (). SetNext ( byColumn ())) ,
45+ orderNameFile : { byFileName , byLine , byColumn } ,
3946 // For sorting we are comparing: linter name
40- orderNameLinter : byLinter () ,
47+ orderNameLinter : { byLinter } ,
4148 // For sorting we are comparing: severity
42- orderNameSeverity : bySeverity () ,
49+ orderNameSeverity : { bySeverity } ,
4350 },
4451 cfg : & cfg .Output ,
4552 }
@@ -57,171 +64,54 @@ func (p SortResults) Process(issues []result.Issue) ([]result.Issue, error) {
5764 p .cfg .SortOrder = []string {orderNameFile }
5865 }
5966
60- var cmps []* comparator
67+ var cmps []issueComparator
68+
6169 for _ , name := range p .cfg .SortOrder {
6270 c , ok := p .cmps [name ]
6371 if ! ok {
6472 return nil , fmt .Errorf ("unsupported sort-order name %q" , name )
6573 }
6674
67- cmps = append (cmps , c )
75+ cmps = append (cmps , c ... )
6876 }
6977
70- cmp , err := mergeComparators (cmps )
71- if err != nil {
72- return nil , err
73- }
78+ comp := mergeComparators (cmps ... )
7479
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 )
7782 })
7883
7984 return issues , nil
8085}
8186
8287func (SortResults ) Finish () {}
8388
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 ())
12391}
12492
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 ())
13295}
13396
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 ())
14599}
146100
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 )
154103}
155104
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 )
163107}
164108
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 {
213110 // The position inside the slice define the importance (lower to higher).
214111 classic := []string {"low" , "medium" , "high" , "warning" , "error" }
215112
216113 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 ))
225115 }
226116
227117 if slices .Contains (classic , a ) {
@@ -232,28 +122,27 @@ func severityCompare(a, b string) compareResult {
232122 return less
233123 }
234124
235- return compareResult ( strings .Compare (a , b ) )
125+ return strings .Compare (a , b )
236126}
237127
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 {
249131 return equal
250- case isValuesInvalid || isZeroValueInA || isZeroValueInB :
251- return none
252- case a > b :
253- return greater
254- case a < b :
255- return less
256132 }
257133
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+ }
259148}
0 commit comments