.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / internal / apidiff / compatibility.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package apidiff
6
7 import (
8         "fmt"
9         "go/types"
10         "reflect"
11 )
12
13 func (d *differ) checkCompatible(otn *types.TypeName, old, new types.Type) {
14         switch old := old.(type) {
15         case *types.Interface:
16                 if new, ok := new.(*types.Interface); ok {
17                         d.checkCompatibleInterface(otn, old, new)
18                         return
19                 }
20
21         case *types.Struct:
22                 if new, ok := new.(*types.Struct); ok {
23                         d.checkCompatibleStruct(otn, old, new)
24                         return
25                 }
26
27         case *types.Chan:
28                 if new, ok := new.(*types.Chan); ok {
29                         d.checkCompatibleChan(otn, old, new)
30                         return
31                 }
32
33         case *types.Basic:
34                 if new, ok := new.(*types.Basic); ok {
35                         d.checkCompatibleBasic(otn, old, new)
36                         return
37                 }
38
39         case *types.Named:
40                 panic("unreachable")
41
42         default:
43                 d.checkCorrespondence(otn, "", old, new)
44                 return
45
46         }
47         // Here if old and new are different kinds of types.
48         d.typeChanged(otn, "", old, new)
49 }
50
51 func (d *differ) checkCompatibleChan(otn *types.TypeName, old, new *types.Chan) {
52         d.checkCorrespondence(otn, ", element type", old.Elem(), new.Elem())
53         if old.Dir() != new.Dir() {
54                 if new.Dir() == types.SendRecv {
55                         d.compatible(otn, "", "removed direction")
56                 } else {
57                         d.incompatible(otn, "", "changed direction")
58                 }
59         }
60 }
61
62 func (d *differ) checkCompatibleBasic(otn *types.TypeName, old, new *types.Basic) {
63         // Certain changes to numeric types are compatible. Approximately, the info must
64         // be the same, and the new values must be a superset of the old.
65         if old.Kind() == new.Kind() {
66                 // old and new are identical
67                 return
68         }
69         if compatibleBasics[[2]types.BasicKind{old.Kind(), new.Kind()}] {
70                 d.compatible(otn, "", "changed from %s to %s", old, new)
71         } else {
72                 d.typeChanged(otn, "", old, new)
73         }
74 }
75
76 // All pairs (old, new) of compatible basic types.
77 var compatibleBasics = map[[2]types.BasicKind]bool{
78         {types.Uint8, types.Uint16}:         true,
79         {types.Uint8, types.Uint32}:         true,
80         {types.Uint8, types.Uint}:           true,
81         {types.Uint8, types.Uint64}:         true,
82         {types.Uint16, types.Uint32}:        true,
83         {types.Uint16, types.Uint}:          true,
84         {types.Uint16, types.Uint64}:        true,
85         {types.Uint32, types.Uint}:          true,
86         {types.Uint32, types.Uint64}:        true,
87         {types.Uint, types.Uint64}:          true,
88         {types.Int8, types.Int16}:           true,
89         {types.Int8, types.Int32}:           true,
90         {types.Int8, types.Int}:             true,
91         {types.Int8, types.Int64}:           true,
92         {types.Int16, types.Int32}:          true,
93         {types.Int16, types.Int}:            true,
94         {types.Int16, types.Int64}:          true,
95         {types.Int32, types.Int}:            true,
96         {types.Int32, types.Int64}:          true,
97         {types.Int, types.Int64}:            true,
98         {types.Float32, types.Float64}:      true,
99         {types.Complex64, types.Complex128}: true,
100 }
101
102 // Interface compatibility:
103 // If the old interface has an unexported method, the new interface is compatible
104 // if its exported method set is a superset of the old. (Users could not implement,
105 // only embed.)
106 //
107 // If the old interface did not have an unexported method, the new interface is
108 // compatible if its exported method set is the same as the old, and it has no
109 // unexported methods. (Adding an unexported method makes the interface
110 // unimplementable outside the package.)
111 //
112 // TODO: must also check that if any methods were added or removed, every exposed
113 // type in the package that implemented the interface in old still implements it in
114 // new. Otherwise external assignments could fail.
115 func (d *differ) checkCompatibleInterface(otn *types.TypeName, old, new *types.Interface) {
116         // Method sets are checked in checkCompatibleDefined.
117
118         // Does the old interface have an unexported method?
119         if unexportedMethod(old) != nil {
120                 d.checkMethodSet(otn, old, new, additionsCompatible)
121         } else {
122                 // Perform an equivalence check, but with more information.
123                 d.checkMethodSet(otn, old, new, additionsIncompatible)
124                 if u := unexportedMethod(new); u != nil {
125                         d.incompatible(otn, u.Name(), "added unexported method")
126                 }
127         }
128 }
129
130 // Return an unexported method from the method set of t, or nil if there are none.
131 func unexportedMethod(t *types.Interface) *types.Func {
132         for i := 0; i < t.NumMethods(); i++ {
133                 if m := t.Method(i); !m.Exported() {
134                         return m
135                 }
136         }
137         return nil
138 }
139
140 // We need to check three things for structs:
141 // 1. The set of exported fields must be compatible. This ensures that keyed struct
142 //    literals continue to compile. (There is no compatibility guarantee for unkeyed
143 //    struct literals.)
144 // 2. The set of exported *selectable* fields must be compatible. This includes the exported
145 //    fields of all embedded structs. This ensures that selections continue to compile.
146 // 3. If the old struct is comparable, so must the new one be. This ensures that equality
147 //    expressions and uses of struct values as map keys continue to compile.
148 //
149 // An unexported embedded struct can't appear in a struct literal outside the
150 // package, so it doesn't have to be present, or have the same name, in the new
151 // struct.
152 //
153 // Field tags are ignored: they have no compile-time implications.
154 func (d *differ) checkCompatibleStruct(obj types.Object, old, new *types.Struct) {
155         d.checkCompatibleObjectSets(obj, exportedFields(old), exportedFields(new))
156         d.checkCompatibleObjectSets(obj, exportedSelectableFields(old), exportedSelectableFields(new))
157         // Removing comparability from a struct is an incompatible change.
158         if types.Comparable(old) && !types.Comparable(new) {
159                 d.incompatible(obj, "", "old is comparable, new is not")
160         }
161 }
162
163 // exportedFields collects all the immediate fields of the struct that are exported.
164 // This is also the set of exported keys for keyed struct literals.
165 func exportedFields(s *types.Struct) map[string]types.Object {
166         m := map[string]types.Object{}
167         for i := 0; i < s.NumFields(); i++ {
168                 f := s.Field(i)
169                 if f.Exported() {
170                         m[f.Name()] = f
171                 }
172         }
173         return m
174 }
175
176 // exportedSelectableFields collects all the exported fields of the struct, including
177 // exported fields of embedded structs.
178 //
179 // We traverse the struct breadth-first, because of the rule that a lower-depth field
180 // shadows one at a higher depth.
181 func exportedSelectableFields(s *types.Struct) map[string]types.Object {
182         var (
183                 m    = map[string]types.Object{}
184                 next []*types.Struct // embedded structs at the next depth
185                 seen []*types.Struct // to handle recursive embedding
186         )
187         for cur := []*types.Struct{s}; len(cur) > 0; cur, next = next, nil {
188                 seen = append(seen, cur...)
189                 // We only want to consider unambiguous fields. Ambiguous fields (where there
190                 // is more than one field of the same name at the same level) are legal, but
191                 // cannot be selected.
192                 for name, f := range unambiguousFields(cur) {
193                         // Record an exported field we haven't seen before. If we have seen it,
194                         // it occurred a lower depth, so it shadows this field.
195                         if f.Exported() && m[name] == nil {
196                                 m[name] = f
197                         }
198                         // Remember embedded structs for processing at the next depth,
199                         // but only if we haven't seen the struct at this depth or above.
200                         if !f.Anonymous() {
201                                 continue
202                         }
203                         t := f.Type().Underlying()
204                         if p, ok := t.(*types.Pointer); ok {
205                                 t = p.Elem().Underlying()
206                         }
207                         if t, ok := t.(*types.Struct); ok && !contains(seen, t) {
208                                 next = append(next, t)
209                         }
210                 }
211         }
212         return m
213 }
214
215 func contains(ts []*types.Struct, t *types.Struct) bool {
216         for _, s := range ts {
217                 if types.Identical(s, t) {
218                         return true
219                 }
220         }
221         return false
222 }
223
224 // Given a set of structs at the same depth, the unambiguous fields are the ones whose
225 // names appear exactly once.
226 func unambiguousFields(structs []*types.Struct) map[string]*types.Var {
227         fields := map[string]*types.Var{}
228         seen := map[string]bool{}
229         for _, s := range structs {
230                 for i := 0; i < s.NumFields(); i++ {
231                         f := s.Field(i)
232                         name := f.Name()
233                         if seen[name] {
234                                 delete(fields, name)
235                         } else {
236                                 seen[name] = true
237                                 fields[name] = f
238                         }
239                 }
240         }
241         return fields
242 }
243
244 // Anything removed or change from the old set is an incompatible change.
245 // Anything added to the new set is a compatible change.
246 func (d *differ) checkCompatibleObjectSets(obj types.Object, old, new map[string]types.Object) {
247         for name, oldo := range old {
248                 newo := new[name]
249                 if newo == nil {
250                         d.incompatible(obj, name, "removed")
251                 } else {
252                         d.checkCorrespondence(obj, name, oldo.Type(), newo.Type())
253                 }
254         }
255         for name := range new {
256                 if old[name] == nil {
257                         d.compatible(obj, name, "added")
258                 }
259         }
260 }
261
262 func (d *differ) checkCompatibleDefined(otn *types.TypeName, old *types.Named, new types.Type) {
263         // We've already checked that old and new correspond.
264         d.checkCompatible(otn, old.Underlying(), new.Underlying())
265         // If there are different kinds of types (e.g. struct and interface), don't bother checking
266         // the method sets.
267         if reflect.TypeOf(old.Underlying()) != reflect.TypeOf(new.Underlying()) {
268                 return
269         }
270         // Interface method sets are checked in checkCompatibleInterface.
271         if _, ok := old.Underlying().(*types.Interface); ok {
272                 return
273         }
274
275         // A new method set is compatible with an old if the new exported methods are a superset of the old.
276         d.checkMethodSet(otn, old, new, additionsCompatible)
277         d.checkMethodSet(otn, types.NewPointer(old), types.NewPointer(new), additionsCompatible)
278 }
279
280 const (
281         additionsCompatible   = true
282         additionsIncompatible = false
283 )
284
285 func (d *differ) checkMethodSet(otn *types.TypeName, oldt, newt types.Type, addcompat bool) {
286         // TODO: find a way to use checkCompatibleObjectSets for this.
287         oldMethodSet := exportedMethods(oldt)
288         newMethodSet := exportedMethods(newt)
289         msname := otn.Name()
290         if _, ok := oldt.(*types.Pointer); ok {
291                 msname = "*" + msname
292         }
293         for name, oldMethod := range oldMethodSet {
294                 newMethod := newMethodSet[name]
295                 if newMethod == nil {
296                         var part string
297                         // Due to embedding, it's possible that the method's receiver type is not
298                         // the same as the defined type whose method set we're looking at. So for
299                         // a type T with removed method M that is embedded in some other type U,
300                         // we will generate two "removed" messages for T.M, one for its own type
301                         // T and one for the embedded type U. We want both messages to appear,
302                         // but the messageSet dedup logic will allow only one message for a given
303                         // object. So use the part string to distinguish them.
304                         if receiverNamedType(oldMethod).Obj() != otn {
305                                 part = fmt.Sprintf(", method set of %s", msname)
306                         }
307                         d.incompatible(oldMethod, part, "removed")
308                 } else {
309                         obj := oldMethod
310                         // If a value method is changed to a pointer method and has a signature
311                         // change, then we can get two messages for the same method definition: one
312                         // for the value method set that says it's removed, and another for the
313                         // pointer method set that says it changed. To keep both messages (since
314                         // messageSet dedups), use newMethod for the second. (Slight hack.)
315                         if !hasPointerReceiver(oldMethod) && hasPointerReceiver(newMethod) {
316                                 obj = newMethod
317                         }
318                         d.checkCorrespondence(obj, "", oldMethod.Type(), newMethod.Type())
319                 }
320         }
321
322         // Check for added methods.
323         for name, newMethod := range newMethodSet {
324                 if oldMethodSet[name] == nil {
325                         if addcompat {
326                                 d.compatible(newMethod, "", "added")
327                         } else {
328                                 d.incompatible(newMethod, "", "added")
329                         }
330                 }
331         }
332 }
333
334 // exportedMethods collects all the exported methods of type's method set.
335 func exportedMethods(t types.Type) map[string]types.Object {
336         m := map[string]types.Object{}
337         ms := types.NewMethodSet(t)
338         for i := 0; i < ms.Len(); i++ {
339                 obj := ms.At(i).Obj()
340                 if obj.Exported() {
341                         m[obj.Name()] = obj
342                 }
343         }
344         return m
345 }
346
347 func receiverType(method types.Object) types.Type {
348         return method.Type().(*types.Signature).Recv().Type()
349 }
350
351 func receiverNamedType(method types.Object) *types.Named {
352         switch t := receiverType(method).(type) {
353         case *types.Pointer:
354                 return t.Elem().(*types.Named)
355         case *types.Named:
356                 return t
357         default:
358                 panic("unreachable")
359         }
360 }
361
362 func hasPointerReceiver(method types.Object) bool {
363         _, ok := receiverType(method).(*types.Pointer)
364         return ok
365 }