1 package apidiff
2
3 import (
4 "fmt"
5 "go/types"
6 "sort"
7 )
8
9
10
11
12
13
14
15
16
17 func (d *differ) correspond(old, new types.Type) bool {
18 return d.corr(old, new, nil)
19 }
20
21
22
23
24
25
26
27
28
29 func (d *differ) corr(old, new types.Type, p *ifacePair) bool {
30
31 switch old := old.(type) {
32 case *types.Basic:
33 if new, ok := new.(*types.Basic); ok {
34 return old.Kind() == new.Kind()
35 }
36
37 case *types.Array:
38 if new, ok := new.(*types.Array); ok {
39 return d.corr(old.Elem(), new.Elem(), p) && old.Len() == new.Len()
40 }
41
42 case *types.Slice:
43 if new, ok := new.(*types.Slice); ok {
44 return d.corr(old.Elem(), new.Elem(), p)
45 }
46
47 case *types.Map:
48 if new, ok := new.(*types.Map); ok {
49 return d.corr(old.Key(), new.Key(), p) && d.corr(old.Elem(), new.Elem(), p)
50 }
51
52 case *types.Chan:
53 if new, ok := new.(*types.Chan); ok {
54 return d.corr(old.Elem(), new.Elem(), p) && old.Dir() == new.Dir()
55 }
56
57 case *types.Pointer:
58 if new, ok := new.(*types.Pointer); ok {
59 return d.corr(old.Elem(), new.Elem(), p)
60 }
61
62 case *types.Signature:
63 if new, ok := new.(*types.Signature); ok {
64 pe := d.corr(old.Params(), new.Params(), p)
65 re := d.corr(old.Results(), new.Results(), p)
66 return old.Variadic() == new.Variadic() && pe && re
67 }
68
69 case *types.Tuple:
70 if new, ok := new.(*types.Tuple); ok {
71 for i := 0; i < old.Len(); i++ {
72 if i >= new.Len() || !d.corr(old.At(i).Type(), new.At(i).Type(), p) {
73 return false
74 }
75 }
76 return old.Len() == new.Len()
77 }
78
79 case *types.Struct:
80 if new, ok := new.(*types.Struct); ok {
81 for i := 0; i < old.NumFields(); i++ {
82 if i >= new.NumFields() {
83 return false
84 }
85 of := old.Field(i)
86 nf := new.Field(i)
87 if of.Anonymous() != nf.Anonymous() ||
88 old.Tag(i) != new.Tag(i) ||
89 !d.corr(of.Type(), nf.Type(), p) ||
90 !d.corrFieldNames(of, nf) {
91 return false
92 }
93 }
94 return old.NumFields() == new.NumFields()
95 }
96
97 case *types.Interface:
98 if new, ok := new.(*types.Interface); ok {
99
100 q := &ifacePair{old, new, p}
101 for p != nil {
102 if p.identical(q) {
103 return true
104 }
105 p = p.prev
106 }
107 oldms := d.sortedMethods(old)
108 newms := d.sortedMethods(new)
109 for i, om := range oldms {
110 if i >= len(newms) {
111 return false
112 }
113 nm := newms[i]
114 if d.methodID(om) != d.methodID(nm) || !d.corr(om.Type(), nm.Type(), q) {
115 return false
116 }
117 }
118 return old.NumMethods() == new.NumMethods()
119 }
120
121 case *types.Named:
122 return d.establishCorrespondence(old, new)
123
124 case *types.TypeParam:
125 if new, ok := new.(*types.TypeParam); ok {
126 if old.Index() == new.Index() {
127 return true
128 }
129 }
130
131 default:
132 panic(fmt.Sprintf("unknown type kind %T", old))
133 }
134 return false
135 }
136
137
138
139
140
141
142 func (d *differ) corrFieldNames(of, nf *types.Var) bool {
143 if of.Anonymous() && nf.Anonymous() && !of.Exported() && !nf.Exported() {
144 if on, ok := of.Type().(*types.Named); ok {
145 nn := nf.Type().(*types.Named)
146 return d.establishCorrespondence(on, nn)
147 }
148 }
149 return of.Name() == nf.Name()
150 }
151
152
153
154
155
156
157
158
159 func (d *differ) establishCorrespondence(old *types.Named, new types.Type) bool {
160 oldname := old.Obj()
161
162
163 if c := d.correspondMap.At(old); c != nil {
164 return types.Identical(c.(types.Type), new)
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 switch new := new.(type) {
189 case *types.Named:
190 newn := new
191 oobj := old.Obj()
192 nobj := newn.Obj()
193 if oobj.Pkg() != d.old || nobj.Pkg() != d.new {
194
195
196
197
198
199 var opath, npath string
200 if oobj.Pkg() != nil {
201 opath = oobj.Pkg().Path()
202 }
203 if nobj.Pkg() != nil {
204 npath = nobj.Pkg().Path()
205 }
206 return oobj.Name() == nobj.Name() && opath == npath
207 }
208
209
210
211 oldOrigin := old.Origin()
212 newOrigin := newn.Origin()
213 if oldOrigin != old {
214
215 if newOrigin == newn {
216
217 return false
218 }
219
220
221 if !d.correspond(oldOrigin, newOrigin) {
222 return false
223 }
224 if !d.typeListsCorrespond(old.TypeArgs(), newn.TypeArgs()) {
225 return false
226 }
227 } else {
228 if !d.typeParamListsCorrespond(old.TypeParams(), newn.TypeParams()) {
229 return false
230 }
231 }
232 case *types.Basic:
233 if old.Obj().Pkg() != d.old {
234
235 return false
236 }
237 default:
238
239 return false
240 }
241
242 d.correspondMap.Set(old, new)
243
244 d.checkCompatibleDefined(oldname, old, new)
245 return true
246 }
247
248 func (d *differ) typeListsCorrespond(tl1, tl2 *types.TypeList) bool {
249 if tl1.Len() != tl2.Len() {
250 return false
251 }
252 for i := 0; i < tl1.Len(); i++ {
253 if !d.correspond(tl1.At(i), tl2.At(i)) {
254 return false
255 }
256 }
257 return true
258 }
259
260
261
262 func (d *differ) typeParamListsCorrespond(tps1, tps2 *types.TypeParamList) bool {
263 if tps1.Len() != tps2.Len() {
264 return false
265 }
266 for i := 0; i < tps1.Len(); i++ {
267 if !d.correspond(tps1.At(i).Constraint(), tps2.At(i).Constraint()) {
268 return false
269 }
270 }
271 return true
272 }
273
274 func (d *differ) sortedMethods(iface *types.Interface) []*types.Func {
275 ms := make([]*types.Func, iface.NumMethods())
276 for i := 0; i < iface.NumMethods(); i++ {
277 ms[i] = iface.Method(i)
278 }
279 sort.Slice(ms, func(i, j int) bool { return d.methodID(ms[i]) < d.methodID(ms[j]) })
280 return ms
281 }
282
283 func (d *differ) methodID(m *types.Func) string {
284
285
286
287 if m.Pkg() == d.old || m.Pkg() == d.new {
288 return m.Name()
289 }
290 return m.Id()
291 }
292
293
294
295
296 type ifacePair struct {
297 x, y *types.Interface
298 prev *ifacePair
299 }
300
301 func (p *ifacePair) identical(q *ifacePair) bool {
302 return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
303 }
304
View as plain text