1
2
3
4
5 package cmp
6
7 import (
8 "fmt"
9 "reflect"
10 "strings"
11 "unicode"
12 "unicode/utf8"
13
14 "github.com/google/go-cmp/cmp/internal/value"
15 )
16
17
18
19
20
21
22
23
24
25
26 type Path []PathStep
27
28
29
30
31
32
33
34
35
36
37
38
39 type PathStep interface {
40 String() string
41
42
43 Type() reflect.Type
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 Values() (vx, vy reflect.Value)
59 }
60
61 var (
62 _ PathStep = StructField{}
63 _ PathStep = SliceIndex{}
64 _ PathStep = MapIndex{}
65 _ PathStep = Indirect{}
66 _ PathStep = TypeAssertion{}
67 _ PathStep = Transform{}
68 )
69
70 func (pa *Path) push(s PathStep) {
71 *pa = append(*pa, s)
72 }
73
74 func (pa *Path) pop() {
75 *pa = (*pa)[:len(*pa)-1]
76 }
77
78
79
80
81 func (pa Path) Last() PathStep {
82 return pa.Index(-1)
83 }
84
85
86
87
88
89
90 func (pa Path) Index(i int) PathStep {
91 if i < 0 {
92 i = len(pa) + i
93 }
94 if i < 0 || i >= len(pa) {
95 return pathStep{}
96 }
97 return pa[i]
98 }
99
100
101
102
103
104
105
106 func (pa Path) String() string {
107 var ss []string
108 for _, s := range pa {
109 if _, ok := s.(StructField); ok {
110 ss = append(ss, s.String())
111 }
112 }
113 return strings.TrimPrefix(strings.Join(ss, ""), ".")
114 }
115
116
117
118
119
120
121 func (pa Path) GoString() string {
122 var ssPre, ssPost []string
123 var numIndirect int
124 for i, s := range pa {
125 var nextStep PathStep
126 if i+1 < len(pa) {
127 nextStep = pa[i+1]
128 }
129 switch s := s.(type) {
130 case Indirect:
131 numIndirect++
132 pPre, pPost := "(", ")"
133 switch nextStep.(type) {
134 case Indirect:
135 continue
136 case StructField:
137 numIndirect--
138 case nil:
139 pPre, pPost = "", ""
140 }
141 if numIndirect > 0 {
142 ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect))
143 ssPost = append(ssPost, pPost)
144 }
145 numIndirect = 0
146 continue
147 case Transform:
148 ssPre = append(ssPre, s.trans.name+"(")
149 ssPost = append(ssPost, ")")
150 continue
151 }
152 ssPost = append(ssPost, s.String())
153 }
154 for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 {
155 ssPre[i], ssPre[j] = ssPre[j], ssPre[i]
156 }
157 return strings.Join(ssPre, "") + strings.Join(ssPost, "")
158 }
159
160 type pathStep struct {
161 typ reflect.Type
162 vx, vy reflect.Value
163 }
164
165 func (ps pathStep) Type() reflect.Type { return ps.typ }
166 func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy }
167 func (ps pathStep) String() string {
168 if ps.typ == nil {
169 return "<nil>"
170 }
171 s := value.TypeString(ps.typ, false)
172 if s == "" || strings.ContainsAny(s, "{}\n") {
173 return "root"
174 }
175 return fmt.Sprintf("{%s}", s)
176 }
177
178
179
180 type StructField struct{ *structField }
181 type structField struct {
182 pathStep
183 name string
184 idx int
185
186
187
188 unexported bool
189 mayForce bool
190 paddr bool
191 pvx, pvy reflect.Value
192 field reflect.StructField
193 }
194
195 func (sf StructField) Type() reflect.Type { return sf.typ }
196 func (sf StructField) Values() (vx, vy reflect.Value) {
197 if !sf.unexported {
198 return sf.vx, sf.vy
199 }
200
201
202 if sf.mayForce {
203 vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr)
204 vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr)
205 return vx, vy
206 }
207 return sf.vx, sf.vy
208 }
209 func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) }
210
211
212 func (sf StructField) Name() string { return sf.name }
213
214
215
216 func (sf StructField) Index() int { return sf.idx }
217
218
219
220 type SliceIndex struct{ *sliceIndex }
221 type sliceIndex struct {
222 pathStep
223 xkey, ykey int
224 isSlice bool
225 }
226
227 func (si SliceIndex) Type() reflect.Type { return si.typ }
228 func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy }
229 func (si SliceIndex) String() string {
230 switch {
231 case si.xkey == si.ykey:
232 return fmt.Sprintf("[%d]", si.xkey)
233 case si.ykey == -1:
234
235 return fmt.Sprintf("[%d->?]", si.xkey)
236 case si.xkey == -1:
237
238 return fmt.Sprintf("[?->%d]", si.ykey)
239 default:
240
241 return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey)
242 }
243 }
244
245
246 func (si SliceIndex) Key() int {
247 if si.xkey != si.ykey {
248 return -1
249 }
250 return si.xkey
251 }
252
253
254
255
256
257
258
259
260
261
262 func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey }
263
264
265 type MapIndex struct{ *mapIndex }
266 type mapIndex struct {
267 pathStep
268 key reflect.Value
269 }
270
271 func (mi MapIndex) Type() reflect.Type { return mi.typ }
272 func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy }
273 func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) }
274
275
276 func (mi MapIndex) Key() reflect.Value { return mi.key }
277
278
279 type Indirect struct{ *indirect }
280 type indirect struct {
281 pathStep
282 }
283
284 func (in Indirect) Type() reflect.Type { return in.typ }
285 func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy }
286 func (in Indirect) String() string { return "*" }
287
288
289 type TypeAssertion struct{ *typeAssertion }
290 type typeAssertion struct {
291 pathStep
292 }
293
294 func (ta TypeAssertion) Type() reflect.Type { return ta.typ }
295 func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy }
296 func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) }
297
298
299
300 type Transform struct{ *transform }
301 type transform struct {
302 pathStep
303 trans *transformer
304 }
305
306 func (tf Transform) Type() reflect.Type { return tf.typ }
307 func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy }
308 func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) }
309
310
311 func (tf Transform) Name() string { return tf.trans.name }
312
313
314 func (tf Transform) Func() reflect.Value { return tf.trans.fnc }
315
316
317
318 func (tf Transform) Option() Option { return tf.trans }
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 type pointerPath struct {
348
349 mx map[value.Pointer]value.Pointer
350
351 my map[value.Pointer]value.Pointer
352 }
353
354 func (p *pointerPath) Init() {
355 p.mx = make(map[value.Pointer]value.Pointer)
356 p.my = make(map[value.Pointer]value.Pointer)
357 }
358
359
360
361
362
363
364
365
366 func (p pointerPath) Push(vx, vy reflect.Value) (equal, visited bool) {
367 px := value.PointerOf(vx)
368 py := value.PointerOf(vy)
369 _, ok1 := p.mx[px]
370 _, ok2 := p.my[py]
371 if ok1 || ok2 {
372 equal = p.mx[px] == py && p.my[py] == px
373 return equal, true
374 }
375 p.mx[px] = py
376 p.my[py] = px
377 return false, false
378 }
379
380
381 func (p pointerPath) Pop(vx, vy reflect.Value) {
382 delete(p.mx, value.PointerOf(vx))
383 delete(p.my, value.PointerOf(vy))
384 }
385
386
387 func isExported(id string) bool {
388 r, _ := utf8.DecodeRuneInString(id)
389 return unicode.IsUpper(r)
390 }
391
View as plain text