forked from golangci/golangci-lint
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsort_results.go
143 lines (111 loc) · 3.04 KB
/
sort_results.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package processors
import (
"cmp"
"fmt"
"slices"
"strings"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/result"
)
const (
orderNameFile = "file"
orderNameLinter = "linter"
orderNameSeverity = "severity"
)
const (
less = iota - 1
equal
greater
)
var _ Processor = (*SortResults)(nil)
type issueComparator func(a, b *result.Issue) int
// SortResults sorts reports based on criteria:
// - file names, line numbers, positions
// - linter names
// - severity names
type SortResults struct {
cmps map[string][]issueComparator
cfg *config.Output
}
func NewSortResults(cfg *config.Output) *SortResults {
return &SortResults{
cmps: map[string][]issueComparator{
// For sorting we are comparing (in next order):
// file names, line numbers, position, and finally - giving up.
orderNameFile: {byFileName, byLine, byColumn},
// For sorting we are comparing: linter name
orderNameLinter: {byLinter},
// For sorting we are comparing: severity
orderNameSeverity: {bySeverity},
},
cfg: cfg,
}
}
func (SortResults) Name() string { return "sort_results" }
// Process is performing sorting of the result issues.
func (p SortResults) Process(issues []result.Issue) ([]result.Issue, error) {
if len(p.cfg.SortOrder) == 0 {
p.cfg.SortOrder = []string{orderNameLinter, orderNameFile}
}
var cmps []issueComparator
for _, name := range p.cfg.SortOrder {
c, ok := p.cmps[name]
if !ok {
return nil, fmt.Errorf("unsupported sort-order name %q", name)
}
cmps = append(cmps, c...)
}
comp := mergeComparators(cmps...)
slices.SortFunc(issues, func(a, b result.Issue) int {
return comp(&a, &b)
})
return issues, nil
}
func (SortResults) Finish() {}
func byFileName(a, b *result.Issue) int {
return strings.Compare(a.FilePath(), b.FilePath())
}
func byLine(a, b *result.Issue) int {
return numericCompare(a.Line(), b.Line())
}
func byColumn(a, b *result.Issue) int {
return numericCompare(a.Column(), b.Column())
}
func byLinter(a, b *result.Issue) int {
return strings.Compare(a.FromLinter, b.FromLinter)
}
func bySeverity(a, b *result.Issue) int {
return severityCompare(a.Severity, b.Severity)
}
func severityCompare(a, b string) int {
// The position inside the slice define the importance (lower to higher).
classic := []string{"low", "medium", "high", "warning", "error"}
if slices.Contains(classic, a) && slices.Contains(classic, b) {
return cmp.Compare(slices.Index(classic, a), slices.Index(classic, b))
}
if slices.Contains(classic, a) {
return greater
}
if slices.Contains(classic, b) {
return less
}
return strings.Compare(a, b)
}
func numericCompare(a, b int) int {
// Negative values and zeros are skipped (equal) because they either invalid or "neutral" (default int value).
if a <= 0 || b <= 0 {
return equal
}
return cmp.Compare(a, b)
}
func mergeComparators(comps ...issueComparator) issueComparator {
return func(a, b *result.Issue) int {
for _, comp := range comps {
i := comp(a, b)
if i != equal {
return i
}
}
return equal
}
}