/
diff.go
150 lines (117 loc) · 2.79 KB
/
diff.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
144
145
146
147
148
149
150
package checkstyle
import (
"regexp"
)
// DiffOptions are the options for the Diff command
type DiffOptions struct {
MaxLineDiff int
}
// Diff runs a diff operation on two checkstyle structs and returns two
// new checkstyle structs of fixed and created errors
func Diff(left, right *Checkstyle, opt DiffOptions) (*Checkstyle, *Checkstyle) {
lout := &Checkstyle{}
rout := &Checkstyle{}
names := allNames(left, right)
for n, s := range names {
if s == sideLeft {
lout.File = append(lout.File, left.File.FromName(n))
continue
}
if s == sideRight {
rout.File = append(rout.File, right.File.FromName(n))
continue
}
lf := left.File.FromName(n)
rf := right.File.FromName(n)
lfe := lf.Error
rfe := rf.Error
// lfe := lf.Error
// rfe := rf.Error
// running through zero first prevernts accidental lose equality where
// actual equality exists several lines below
lfe, rfe = fileErrorWoExactEq(lfe, rfe, 0)
if opt.MaxLineDiff > 0 {
lfe, rfe = fileErrorWoExactEq(lfe, rfe, opt.MaxLineDiff)
}
if len(lfe) > 0 {
lout.File = append(lout.File, File{
Name: n,
Error: lfe,
})
}
if len(rfe) > 0 {
rout.File = append(rout.File, File{
Name: n,
Error: rfe,
})
}
}
return lout, rout
}
type side int
const (
sideLeft side = iota + 1
sideRight
sideBoth
)
func fileErrorWoExactEq(left, right []FileError, maxLineDiff int) ([]FileError, []FileError) {
lout := []FileError{}
rout := []FileError{}
leftloop:
for _, l := range left {
for _, r := range right {
if fileErrorEq(l, r, maxLineDiff) {
continue leftloop
}
}
lout = append(lout, l)
}
rightloop:
for _, r := range right {
for _, l := range left {
if fileErrorEq(l, r, maxLineDiff) {
continue rightloop
}
}
rout = append(rout, r)
}
return lout, rout
}
func fileErrorEq(lfile, rfile FileError, maxLineDiff int) bool {
if lfile.Severity != rfile.Severity || lfile.Source != rfile.Source || !msgEq(lfile.Message, rfile.Message) {
return false
}
if abs(lfile.Line-rfile.Line) <= maxLineDiff {
return true
}
return false
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
var msgClean = regexp.MustCompile(`[^\p{L}?:().]+`)
// This is an initial attempt at this and should be reworked later to consider
// things like the line number difference in parts of this that perhaps include
// line numbers
func msgEq(left, right string) bool {
left = msgClean.ReplaceAllString(left, "|")
right = msgClean.ReplaceAllString(right, "|")
return left == right
}
func allNames(left, right *Checkstyle) map[string]side {
ret := map[string]side{}
for _, c := range left.File {
ret[c.Name] = sideLeft
}
for _, c := range right.File {
if _, ok := ret[c.Name]; ok {
ret[c.Name] = sideBoth
} else {
ret[c.Name] = sideRight
}
}
return ret
}