@@ -22,13 +22,24 @@ import (
22
22
// It classifies each difference as either compatible or incompatible (breaking.) For
23
23
// a detailed discussion of what constitutes an incompatible change, see the README.
24
24
func Changes (old , new * types.Package ) Report {
25
+ return changesInternal (old , new , old .Path (), new .Path ())
26
+ }
27
+
28
+ // changesInternal contains the core logic for comparing a single package, shared
29
+ // between Changes and ModuleChanges. The root package path arguments refer to the
30
+ // context of this apidiff invocation - when diffing a single package, they will be
31
+ // that package, but when diffing a whole module, they will be the root path of the
32
+ // module. This is used to give change messages appropriate context for object names.
33
+ // The old and new root must be tracked independently, since each side of the diff
34
+ // operation may be a different path.
35
+ func changesInternal (old , new * types.Package , oldRootPackagePath , newRootPackagePath string ) Report {
25
36
d := newDiffer (old , new )
26
- d .checkPackage ()
37
+ d .checkPackage (oldRootPackagePath )
27
38
r := Report {}
28
- for _ , m := range d .incompatibles .collect () {
39
+ for _ , m := range d .incompatibles .collect (oldRootPackagePath , newRootPackagePath ) {
29
40
r .Changes = append (r .Changes , Change {Message : m , Compatible : false })
30
41
}
31
- for _ , m := range d .compatibles .collect () {
42
+ for _ , m := range d .compatibles .collect (oldRootPackagePath , newRootPackagePath ) {
32
43
r .Changes = append (r .Changes , Change {Message : m , Compatible : true })
33
44
}
34
45
return r
@@ -54,7 +65,7 @@ func ModuleChanges(old, new *Module) Report {
54
65
for n , op := range oldPkgs {
55
66
if np , ok := newPkgs [n ]; ok {
56
67
// shared package, compare surfaces
57
- rr := Changes (op , np )
68
+ rr := changesInternal (op , np , old . Path , new . Path )
58
69
r .Changes = append (r .Changes , rr .Changes ... )
59
70
} else {
60
71
// old package was removed
@@ -114,19 +125,19 @@ func newDiffer(old, new *types.Package) *differ {
114
125
}
115
126
}
116
127
117
- func (d * differ ) incompatible (obj types. Object , part , format string , args ... interface {}) {
128
+ func (d * differ ) incompatible (obj objectWithSide , part , format string , args ... interface {}) {
118
129
addMessage (d .incompatibles , obj , part , format , args )
119
130
}
120
131
121
- func (d * differ ) compatible (obj types. Object , part , format string , args ... interface {}) {
132
+ func (d * differ ) compatible (obj objectWithSide , part , format string , args ... interface {}) {
122
133
addMessage (d .compatibles , obj , part , format , args )
123
134
}
124
135
125
- func addMessage (ms messageSet , obj types. Object , part , format string , args []interface {}) {
136
+ func addMessage (ms messageSet , obj objectWithSide , part , format string , args []interface {}) {
126
137
ms .add (obj , part , fmt .Sprintf (format , args ... ))
127
138
}
128
139
129
- func (d * differ ) checkPackage () {
140
+ func (d * differ ) checkPackage (oldRootPackagePath string ) {
130
141
// Old changes.
131
142
for _ , name := range d .old .Scope ().Names () {
132
143
oldobj := d .old .Scope ().Lookup (name )
@@ -135,7 +146,7 @@ func (d *differ) checkPackage() {
135
146
}
136
147
newobj := d .new .Scope ().Lookup (name )
137
148
if newobj == nil {
138
- d .incompatible (oldobj , "" , "removed" )
149
+ d .incompatible (objectWithSide { oldobj , false } , "" , "removed" )
139
150
continue
140
151
}
141
152
d .checkObjects (oldobj , newobj )
@@ -144,7 +155,7 @@ func (d *differ) checkPackage() {
144
155
for _ , name := range d .new .Scope ().Names () {
145
156
newobj := d .new .Scope ().Lookup (name )
146
157
if newobj .Exported () && d .old .Scope ().Lookup (name ) == nil {
147
- d .compatible (newobj , "" , "added" )
158
+ d .compatible (objectWithSide { newobj , true } , "" , "added" )
148
159
}
149
160
}
150
161
@@ -168,7 +179,7 @@ func (d *differ) checkPackage() {
168
179
continue
169
180
}
170
181
if types .Implements (otn2 .Type (), oIface ) && ! types .Implements (nt2 , nIface ) {
171
- d .incompatible (otn2 , "" , "no longer implements %s" , objectString (otn1 ))
182
+ d .incompatible (objectWithSide { otn2 , false }, "" , "no longer implements %s" , objectString (otn1 , oldRootPackagePath ))
172
183
}
173
184
}
174
185
}
@@ -183,30 +194,30 @@ func (d *differ) checkObjects(old, new types.Object) {
183
194
}
184
195
case * types.Var :
185
196
if new , ok := new .(* types.Var ); ok {
186
- d .checkCorrespondence (old , "" , old .Type (), new .Type ())
197
+ d .checkCorrespondence (objectWithSide { old , false } , "" , old .Type (), new .Type ())
187
198
return
188
199
}
189
200
case * types.Func :
190
201
switch new := new .(type ) {
191
202
case * types.Func :
192
- d .checkCorrespondence (old , "" , old .Type (), new .Type ())
203
+ d .checkCorrespondence (objectWithSide { old , false } , "" , old .Type (), new .Type ())
193
204
return
194
205
case * types.Var :
195
- d .compatible (old , "" , "changed from func to var" )
196
- d .checkCorrespondence (old , "" , old .Type (), new .Type ())
206
+ d .compatible (objectWithSide { old , false } , "" , "changed from func to var" )
207
+ d .checkCorrespondence (objectWithSide { old , false } , "" , old .Type (), new .Type ())
197
208
return
198
209
199
210
}
200
211
case * types.TypeName :
201
212
if new , ok := new .(* types.TypeName ); ok {
202
- d .checkCorrespondence (old , "" , old .Type (), new .Type ())
213
+ d .checkCorrespondence (objectWithSide { old , false } , "" , old .Type (), new .Type ())
203
214
return
204
215
}
205
216
default :
206
217
panic ("unexpected obj type" )
207
218
}
208
219
// Here if kind of type changed.
209
- d .incompatible (old , "" , "changed from %s to %s" ,
220
+ d .incompatible (objectWithSide { old , false } , "" , "changed from %s to %s" ,
210
221
objectKindString (old ), objectKindString (new ))
211
222
}
212
223
@@ -216,13 +227,13 @@ func (d *differ) constChanges(old, new *types.Const) {
216
227
nt := new .Type ()
217
228
// Check for change of type.
218
229
if ! d .correspond (ot , nt ) {
219
- d .typeChanged (old , "" , ot , nt )
230
+ d .typeChanged (objectWithSide { old , false } , "" , ot , nt )
220
231
return
221
232
}
222
233
// Check for change of value.
223
234
// We know the types are the same, so constant.Compare shouldn't panic.
224
235
if ! constant .Compare (old .Val (), token .EQL , new .Val ()) {
225
- d .incompatible (old , "" , "value changed from %s to %s" , old .Val (), new .Val ())
236
+ d .incompatible (objectWithSide { old , false } , "" , "value changed from %s to %s" , old .Val (), new .Val ())
226
237
}
227
238
}
228
239
@@ -241,13 +252,13 @@ func objectKindString(obj types.Object) string {
241
252
}
242
253
}
243
254
244
- func (d * differ ) checkCorrespondence (obj types. Object , part string , old , new types.Type ) {
255
+ func (d * differ ) checkCorrespondence (obj objectWithSide , part string , old , new types.Type ) {
245
256
if ! d .correspond (old , new ) {
246
257
d .typeChanged (obj , part , old , new )
247
258
}
248
259
}
249
260
250
- func (d * differ ) typeChanged (obj types. Object , part string , old , new types.Type ) {
261
+ func (d * differ ) typeChanged (obj objectWithSide , part string , old , new types.Type ) {
251
262
old = removeNamesFromSignature (old )
252
263
new = removeNamesFromSignature (new )
253
264
olds := types .TypeString (old , types .RelativeTo (d .old ))
0 commit comments