Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / godoc / analysis / typeinfo.go
1 // Copyright 2014 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 analysis
6
7 // This file computes the markup for information from go/types:
8 // IMPORTS, identifier RESOLUTION, METHOD SETS, size/alignment, and
9 // the IMPLEMENTS relation.
10 //
11 // IMPORTS links connect import specs to the documentation for the
12 // imported package.
13 //
14 // RESOLUTION links referring identifiers to their defining
15 // identifier, and adds tooltips for kind and type.
16 //
17 // METHOD SETS, size/alignment, and the IMPLEMENTS relation are
18 // displayed in the lower pane when a type's defining identifier is
19 // clicked.
20
21 import (
22         "fmt"
23         "go/types"
24         "reflect"
25         "strconv"
26         "strings"
27
28         "golang.org/x/tools/go/loader"
29         "golang.org/x/tools/go/types/typeutil"
30 )
31
32 // TODO(adonovan): audit to make sure it's safe on ill-typed packages.
33
34 // TODO(adonovan): use same Sizes as loader.Config.
35 var sizes = types.StdSizes{WordSize: 8, MaxAlign: 8}
36
37 func (a *analysis) doTypeInfo(info *loader.PackageInfo, implements map[*types.Named]implementsFacts) {
38         // We must not assume the corresponding SSA packages were
39         // created (i.e. were transitively error-free).
40
41         // IMPORTS
42         for _, f := range info.Files {
43                 // Package decl.
44                 fi, offset := a.fileAndOffset(f.Name.Pos())
45                 fi.addLink(aLink{
46                         start: offset,
47                         end:   offset + len(f.Name.Name),
48                         title: "Package docs for " + info.Pkg.Path(),
49                         // TODO(adonovan): fix: we're putting the untrusted Path()
50                         // into a trusted field.  What's the appropriate sanitizer?
51                         href: "/pkg/" + info.Pkg.Path(),
52                 })
53
54                 // Import specs.
55                 for _, imp := range f.Imports {
56                         // Remove quotes.
57                         L := int(imp.End()-imp.Path.Pos()) - len(`""`)
58                         path, _ := strconv.Unquote(imp.Path.Value)
59                         fi, offset := a.fileAndOffset(imp.Path.Pos())
60                         fi.addLink(aLink{
61                                 start: offset + 1,
62                                 end:   offset + 1 + L,
63                                 title: "Package docs for " + path,
64                                 // TODO(adonovan): fix: we're putting the untrusted path
65                                 // into a trusted field.  What's the appropriate sanitizer?
66                                 href: "/pkg/" + path,
67                         })
68                 }
69         }
70
71         // RESOLUTION
72         qualifier := types.RelativeTo(info.Pkg)
73         for id, obj := range info.Uses {
74                 // Position of the object definition.
75                 pos := obj.Pos()
76                 Len := len(obj.Name())
77
78                 // Correct the position for non-renaming import specs.
79                 //  import "sync/atomic"
80                 //          ^^^^^^^^^^^
81                 if obj, ok := obj.(*types.PkgName); ok && id.Name == obj.Imported().Name() {
82                         // Assume this is a non-renaming import.
83                         // NB: not true for degenerate renamings: `import foo "foo"`.
84                         pos++
85                         Len = len(obj.Imported().Path())
86                 }
87
88                 if obj.Pkg() == nil {
89                         continue // don't mark up built-ins.
90                 }
91
92                 fi, offset := a.fileAndOffset(id.NamePos)
93                 fi.addLink(aLink{
94                         start: offset,
95                         end:   offset + len(id.Name),
96                         title: types.ObjectString(obj, qualifier),
97                         href:  a.posURL(pos, Len),
98                 })
99         }
100
101         // IMPLEMENTS & METHOD SETS
102         for _, obj := range info.Defs {
103                 if obj, ok := obj.(*types.TypeName); ok {
104                         if named, ok := obj.Type().(*types.Named); ok {
105                                 a.namedType(named, implements)
106                         }
107                 }
108         }
109 }
110
111 func (a *analysis) namedType(T *types.Named, implements map[*types.Named]implementsFacts) {
112         obj := T.Obj()
113         qualifier := types.RelativeTo(obj.Pkg())
114         v := &TypeInfoJSON{
115                 Name:    obj.Name(),
116                 Size:    sizes.Sizeof(T),
117                 Align:   sizes.Alignof(T),
118                 Methods: []anchorJSON{}, // (JS wants non-nil)
119         }
120
121         // addFact adds the fact "is implemented by T" (by) or
122         // "implements T" (!by) to group.
123         addFact := func(group *implGroupJSON, T types.Type, by bool) {
124                 Tobj := deref(T).(*types.Named).Obj()
125                 var byKind string
126                 if by {
127                         // Show underlying kind of implementing type,
128                         // e.g. "slice", "array", "struct".
129                         s := reflect.TypeOf(T.Underlying()).String()
130                         byKind = strings.ToLower(strings.TrimPrefix(s, "*types."))
131                 }
132                 group.Facts = append(group.Facts, implFactJSON{
133                         ByKind: byKind,
134                         Other: anchorJSON{
135                                 Href: a.posURL(Tobj.Pos(), len(Tobj.Name())),
136                                 Text: types.TypeString(T, qualifier),
137                         },
138                 })
139         }
140
141         // IMPLEMENTS
142         if r, ok := implements[T]; ok {
143                 if isInterface(T) {
144                         // "T is implemented by <conc>" ...
145                         // "T is implemented by <iface>"...
146                         // "T implements        <iface>"...
147                         group := implGroupJSON{
148                                 Descr: types.TypeString(T, qualifier),
149                         }
150                         // Show concrete types first; use two passes.
151                         for _, sub := range r.to {
152                                 if !isInterface(sub) {
153                                         addFact(&group, sub, true)
154                                 }
155                         }
156                         for _, sub := range r.to {
157                                 if isInterface(sub) {
158                                         addFact(&group, sub, true)
159                                 }
160                         }
161                         for _, super := range r.from {
162                                 addFact(&group, super, false)
163                         }
164                         v.ImplGroups = append(v.ImplGroups, group)
165                 } else {
166                         // T is concrete.
167                         if r.from != nil {
168                                 // "T implements <iface>"...
169                                 group := implGroupJSON{
170                                         Descr: types.TypeString(T, qualifier),
171                                 }
172                                 for _, super := range r.from {
173                                         addFact(&group, super, false)
174                                 }
175                                 v.ImplGroups = append(v.ImplGroups, group)
176                         }
177                         if r.fromPtr != nil {
178                                 // "*C implements <iface>"...
179                                 group := implGroupJSON{
180                                         Descr: "*" + types.TypeString(T, qualifier),
181                                 }
182                                 for _, psuper := range r.fromPtr {
183                                         addFact(&group, psuper, false)
184                                 }
185                                 v.ImplGroups = append(v.ImplGroups, group)
186                         }
187                 }
188         }
189
190         // METHOD SETS
191         for _, sel := range typeutil.IntuitiveMethodSet(T, &a.prog.MethodSets) {
192                 meth := sel.Obj().(*types.Func)
193                 pos := meth.Pos() // may be 0 for error.Error
194                 v.Methods = append(v.Methods, anchorJSON{
195                         Href: a.posURL(pos, len(meth.Name())),
196                         Text: types.SelectionString(sel, qualifier),
197                 })
198         }
199
200         // Since there can be many specs per decl, we
201         // can't attach the link to the keyword 'type'
202         // (as we do with 'func'); we use the Ident.
203         fi, offset := a.fileAndOffset(obj.Pos())
204         fi.addLink(aLink{
205                 start:   offset,
206                 end:     offset + len(obj.Name()),
207                 title:   fmt.Sprintf("type info for %s", obj.Name()),
208                 onclick: fmt.Sprintf("onClickTypeInfo(%d)", fi.addData(v)),
209         })
210
211         // Add info for exported package-level types to the package info.
212         if obj.Exported() && isPackageLevel(obj) {
213                 // TODO(adonovan): Path is not unique!
214                 // It is possible to declare a non-test package called x_test.
215                 a.result.pkgInfo(obj.Pkg().Path()).addType(v)
216         }
217 }
218
219 // -- utilities --------------------------------------------------------
220
221 func isInterface(T types.Type) bool { return types.IsInterface(T) }
222
223 // deref returns a pointer's element type; otherwise it returns typ.
224 func deref(typ types.Type) types.Type {
225         if p, ok := typ.Underlying().(*types.Pointer); ok {
226                 return p.Elem()
227         }
228         return typ
229 }
230
231 // isPackageLevel reports whether obj is a package-level object.
232 func isPackageLevel(obj types.Object) bool {
233         return obj.Pkg().Scope().Lookup(obj.Name()) == obj
234 }