1
2
3
4
5 package apidiff
6
7 import (
8 "go/types"
9 "sort"
10
11 "golang.org/x/tools/internal/aliases"
12 )
13
14
15
16
17
18
19
20
21
22 func (d *differ) correspond(old, new types.Type) bool {
23 return d.corr(old, new, nil)
24 }
25
26
27
28
29
30
31
32
33
34 func (d *differ) corr(old, new types.Type, p *ifacePair) bool {
35
36 old = aliases.Unalias(old)
37 new = aliases.Unalias(new)
38 switch old := old.(type) {
39 case *types.Basic:
40 return types.Identical(old, new)
41
42 case *types.Array:
43 if new, ok := new.(*types.Array); ok {
44 return d.corr(old.Elem(), new.Elem(), p) && old.Len() == new.Len()
45 }
46
47 case *types.Slice:
48 if new, ok := new.(*types.Slice); ok {
49 return d.corr(old.Elem(), new.Elem(), p)
50 }
51
52 case *types.Map:
53 if new, ok := new.(*types.Map); ok {
54 return d.corr(old.Key(), new.Key(), p) && d.corr(old.Elem(), new.Elem(), p)
55 }
56
57 case *types.Chan:
58 if new, ok := new.(*types.Chan); ok {
59 return d.corr(old.Elem(), new.Elem(), p) && old.Dir() == new.Dir()
60 }
61
62 case *types.Pointer:
63 if new, ok := new.(*types.Pointer); ok {
64 return d.corr(old.Elem(), new.Elem(), p)
65 }
66
67 case *types.Signature:
68 if new, ok := new.(*types.Signature); ok {
69 pe := d.corr(old.Params(), new.Params(), p)
70 re := d.corr(old.Results(), new.Results(), p)
71 return old.Variadic() == new.Variadic() && pe && re
72 }
73
74 case *types.Tuple:
75 if new, ok := new.(*types.Tuple); ok {
76 for i := 0; i < old.Len(); i++ {
77 if i >= new.Len() || !d.corr(old.At(i).Type(), new.At(i).Type(), p) {
78 return false
79 }
80 }
81 return old.Len() == new.Len()
82 }
83
84 case *types.Struct:
85 if new, ok := new.(*types.Struct); ok {
86 for i := 0; i < old.NumFields(); i++ {
87 if i >= new.NumFields() {
88 return false
89 }
90 of := old.Field(i)
91 nf := new.Field(i)
92 if of.Anonymous() != nf.Anonymous() ||
93 old.Tag(i) != new.Tag(i) ||
94 !d.corr(of.Type(), nf.Type(), p) ||
95 !d.corrFieldNames(of, nf) {
96 return false
97 }
98 }
99 return old.NumFields() == new.NumFields()
100 }
101
102 case *types.Interface:
103 if new, ok := new.(*types.Interface); ok {
104
105 q := &ifacePair{old, new, p}
106 for p != nil {
107 if p.identical(q) {
108 return true
109 }
110 p = p.prev
111 }
112 oldms := d.sortedMethods(old)
113 newms := d.sortedMethods(new)
114 for i, om := range oldms {
115 if i >= len(newms) {
116 return false
117 }
118 nm := newms[i]
119 if d.methodID(om) != d.methodID(nm) || !d.corr(om.Type(), nm.Type(), q) {
120 return false
121 }
122 }
123 return old.NumMethods() == new.NumMethods()
124 }
125
126 case *types.Named:
127 if new, ok := new.(*types.Named); ok {
128 return d.establishCorrespondence(old, new)
129 }
130 if new, ok := new.(*types.Basic); ok {
131
132
133 return d.establishCorrespondence(old, new)
134 }
135
136 default:
137 panic("unknown type kind")
138 }
139 return false
140 }
141
142
143
144
145
146
147 func (d *differ) corrFieldNames(of, nf *types.Var) bool {
148 if of.Anonymous() && nf.Anonymous() && !of.Exported() && !nf.Exported() {
149 if on, ok := of.Type().(*types.Named); ok {
150 nn := nf.Type().(*types.Named)
151 return d.establishCorrespondence(on, nn)
152 }
153 }
154 return of.Name() == nf.Name()
155 }
156
157
158
159 func (d *differ) establishCorrespondence(old *types.Named, new types.Type) bool {
160 oldname := old.Obj()
161 oldc := d.correspondMap[oldname]
162 if oldc == nil {
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 if newn, ok := new.(*types.Named); ok {
185 if old.Obj().Pkg() != d.old || newn.Obj().Pkg() != d.new {
186 return old.Obj().Id() == newn.Obj().Id()
187 }
188 }
189
190 d.correspondMap[oldname] = new
191
192 d.checkCompatibleDefined(oldname, old, new)
193 return true
194 }
195 return types.Identical(oldc, new)
196 }
197
198 func (d *differ) sortedMethods(iface *types.Interface) []*types.Func {
199 ms := make([]*types.Func, iface.NumMethods())
200 for i := 0; i < iface.NumMethods(); i++ {
201 ms[i] = iface.Method(i)
202 }
203 sort.Slice(ms, func(i, j int) bool { return d.methodID(ms[i]) < d.methodID(ms[j]) })
204 return ms
205 }
206
207 func (d *differ) methodID(m *types.Func) string {
208
209
210
211 if m.Pkg() == d.old || m.Pkg() == d.new {
212 return m.Name()
213 }
214 return m.Id()
215 }
216
217
218
219
220 type ifacePair struct {
221 x, y *types.Interface
222 prev *ifacePair
223 }
224
225 func (p *ifacePair) identical(q *ifacePair) bool {
226 return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
227 }
228
View as plain text