@@ -3,18 +3,23 @@ package main
3
3
import (
4
4
"fmt"
5
5
"go/ast"
6
+ "go/token"
6
7
"strings"
7
8
)
8
9
9
- func newDeclComparer (summary * packageSummary ) * declComparer {
10
+ func newDeclComparer (fset * token. FileSet , path string , summary * packageSummary ) * declComparer {
10
11
return & declComparer {
12
+ fset : fset ,
13
+ path : path ,
11
14
head : summary ,
12
15
}
13
16
}
14
17
15
18
// declComparer is an ast.Visitor which ensures that all encountered
16
19
// declarations have been unmodified in the provided summary.
17
20
type declComparer struct {
21
+ fset * token.FileSet
22
+ path string // relative folder
18
23
head * packageSummary
19
24
report strings.Builder
20
25
}
@@ -47,20 +52,26 @@ func (c *declComparer) Visit(node ast.Node) ast.Visitor {
47
52
func (c * declComparer ) compareType (base * ast.TypeSpec ) {
48
53
head , ok := c .head .types [base .Name .Name ]
49
54
if ! ok {
50
- c .logf ("• removed: type %s" , base .Name .Name )
55
+ c .logf ("\n • Removed in working tree:" )
56
+ c .logPosition (base , true )
57
+ c .logf (" type %s" , base .Name .Name )
51
58
return
52
59
}
53
60
if x , ok := base .Type .(* ast.StructType ); ok {
54
61
// compare structs, allow adding new fields
55
62
y , ok := head .Type .(* ast.StructType )
56
63
if ! ok {
57
- c .logf ("• changed: struct %s type changed to %s" , base .Name .Name , describeType (head .Type ))
64
+ c .logf ("\n • Type changed to %s:" , describeType (head .Type ))
65
+ c .logPosition (base , true )
66
+ c .logf (" type %s" , base .Name .Name )
58
67
}
59
68
c .compareStructs (base .Name .Name , x , y )
60
69
return
61
70
}
62
71
if a , b := describeType (base .Type ), describeType (head .Type ); a != b {
63
- c .logf ("• changed: type %s from %s to %s" , base .Name .Name , a , b )
72
+ c .logf ("\n • Type changed from %s to %s:" , a , b )
73
+ c .logPosition (base , true )
74
+ c .logf (" type %s" , base .Name .Name )
64
75
}
65
76
}
66
77
@@ -70,13 +81,19 @@ func (c *declComparer) compareStructs(structName string, base, head *ast.StructT
70
81
for _ , n := range f .Names {
71
82
if n .Name == name {
72
83
if a , b := describeType (f .Type ), describeType (typ ); a != b {
73
- c .logf ("• changed: struct %s, field %s type from %s to %s" , structName , name , b , a )
84
+ c .logf ("\n • Struct field %q type changed from %s to %s:" , name , b , a )
85
+ c .logPosition (base , true )
86
+ c .logf (" %s" , structName )
74
87
}
75
88
return
76
89
}
77
90
}
78
91
}
79
- c .logf ("• removed: struct %s, field %s" , structName , name )
92
+ c .logf ("\n • Removed struct field %q:" , name )
93
+ c .logPosition (base , true )
94
+ c .logf (" struct %s" , structName )
95
+ c .logPosition (head , false )
96
+ c .logf (" struct %s" , structName )
80
97
}
81
98
for _ , field := range base .Fields .List {
82
99
for _ , name := range field .Names {
@@ -89,11 +106,15 @@ func (c *declComparer) compareValue(base *ast.ValueSpec) {
89
106
for _ , name := range base .Names {
90
107
head , ok := c .head .value [name .Name ]
91
108
if ! ok {
92
- c .logf ("• removed: %s" , printValue (base ))
109
+ c .logf ("\n • Value removed in working tree:" )
110
+ c .logPosition (base , true )
111
+ c .logf (" %s" , printValue (base ))
93
112
return
94
113
}
95
114
if a , b := describeType (head .Type ), describeType (base .Type ); a != b {
96
- c .logf ("• changed: value type %s from %s to %s" , name .Name , b , a )
115
+ c .logf ("\n • Value type changed from %s to %s in working tree:" , b , a )
116
+ c .logPosition (base , true )
117
+ c .logf (" %s" , name .Name )
97
118
}
98
119
if base .Type == nil {
99
120
// If the type is nil, this is likely an assignment where the type is inferred
@@ -111,7 +132,9 @@ func (c *declComparer) compareFunc(base *ast.FuncDecl) {
111
132
head , ok := c .head .funcs [name ]
112
133
if ! ok {
113
134
// func not found
114
- c .logf ("• removed: %s" , printFunc (base .Recv , base .Name , base .Type ))
135
+ c .logf ("\n • Func removed:" )
136
+ c .logPosition (base , true )
137
+ c .logf (" %s" , printFunc (base .Recv , base .Name , base .Type ))
115
138
return
116
139
}
117
140
headArgs := head .Type .Params .List
@@ -120,46 +143,61 @@ func (c *declComparer) compareFunc(base *ast.FuncDecl) {
120
143
// if there's only one new argument in base, and that argument
121
144
// is variadic, then this isn't a breaking change
122
145
if diff != 1 || ! strings .HasPrefix (describeType (headArgs [len (headArgs )- 1 ].Type ), "..." ) {
123
- c .logFuncChange (base , head , "change in argument count" )
146
+ c .logFuncChange (base , head , "Change in argument count" )
124
147
return
125
148
}
126
149
}
127
150
for i , arg := range baseArgs {
128
151
if a , b := describeType (arg .Type ), describeType (headArgs [i ].Type ); a != b {
129
- c .logFuncChange (base , head , fmt .Sprintf ("argument %d changed from %s to %s" , i , a , b ))
152
+ c .logFuncChange (base , head , fmt .Sprintf ("Argument (%d) changed from %s to %s" , i , a , b ))
130
153
return
131
154
}
132
155
}
133
156
baseResults := base .Type .Results
134
157
headResults := head .Type .Results
135
158
if baseResults == nil && headResults != nil {
136
- c .logFuncChange (base , head , "return values were added" )
159
+ c .logFuncChange (base , head , "Return values were added" )
137
160
return
138
161
}
139
162
if baseResults != nil && headResults == nil {
140
- c .logFuncChange (base , head , "return values were removed" )
163
+ c .logFuncChange (base , head , "Return values were removed" )
141
164
return
142
165
}
143
166
if baseResults == nil && headResults == nil {
144
167
// OK
145
168
return
146
169
}
147
170
if len (baseResults .List ) != len (headResults .List ) {
148
- c .logFuncChange (base , head , "change in return value count" )
171
+ c .logFuncChange (base , head , "Change in return value count" )
149
172
return
150
173
}
151
174
for i , arg := range baseResults .List {
152
175
if a , b := describeType (arg .Type ), describeType (headResults .List [i ].Type ); a != b {
153
- c .logFuncChange (base , head , fmt .Sprintf ("return value %d changed from %s to %s" , i , a , b ))
176
+ c .logFuncChange (base , head , fmt .Sprintf ("Return value (%d) changed from %s to %s" , i , a , b ))
154
177
return
155
178
}
156
179
}
157
180
}
158
181
182
+ func (c * declComparer ) logPosition (node ast.Node , base bool ) {
183
+ fset := c .fset
184
+ path := c .path
185
+ gitr := "@" + * baseRef
186
+ if ! base {
187
+ fset = c .head .fset
188
+ path = c .head .path
189
+ gitr = ""
190
+ }
191
+ pos := fset .Position (node .Pos ())
192
+ c .logf (" - %s:%d%s:" , strings .TrimPrefix (pos .Filename , path + "/" ), pos .Line , gitr )
193
+ }
194
+
159
195
func (c * declComparer ) logFuncChange (base , head * ast.FuncDecl , reason string ) {
160
- c .logf ("• before: %s" , printFunc (base .Recv , base .Name , base .Type ))
161
- c .logf (" now: %s" , printFunc (head .Recv , head .Name , head .Type ))
162
- c .logf (" (%s)" , reason )
196
+ c .logf ("\n • %s:" , reason )
197
+ c .logPosition (base , true )
198
+ c .logf (" %s" , printFunc (base .Recv , base .Name , base .Type ))
199
+ c .logPosition (head , false )
200
+ c .logf (" %s" , printFunc (head .Recv , head .Name , head .Type ))
163
201
}
164
202
165
203
func (c * declComparer ) logf (format string , args ... interface {}) {
@@ -168,7 +206,7 @@ func (c *declComparer) logf(format string, args ...interface{}) {
168
206
c .report .WriteByte (':' )
169
207
c .report .WriteByte ('\n' )
170
208
}
171
- c .report .WriteByte ( '\t' )
209
+ c .report .WriteString ( " " )
172
210
c .report .WriteString (fmt .Sprintf (format , args ... ))
173
211
c .report .WriteByte ('\n' )
174
212
}
0 commit comments