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 / internal / lsp / source / types_format.go
1 // Copyright 2020 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 source
6
7 import (
8         "bytes"
9         "context"
10         "fmt"
11         "go/ast"
12         "go/doc"
13         "go/printer"
14         "go/token"
15         "go/types"
16         "strings"
17
18         "golang.org/x/tools/internal/event"
19         "golang.org/x/tools/internal/lsp/debug/tag"
20         "golang.org/x/tools/internal/lsp/protocol"
21 )
22
23 // FormatType returns the detail and kind for a types.Type.
24 func FormatType(typ types.Type, qf types.Qualifier) (detail string, kind protocol.CompletionItemKind) {
25         if types.IsInterface(typ) {
26                 detail = "interface{...}"
27                 kind = protocol.InterfaceCompletion
28         } else if _, ok := typ.(*types.Struct); ok {
29                 detail = "struct{...}"
30                 kind = protocol.StructCompletion
31         } else if typ != typ.Underlying() {
32                 detail, kind = FormatType(typ.Underlying(), qf)
33         } else {
34                 detail = types.TypeString(typ, qf)
35                 kind = protocol.ClassCompletion
36         }
37         return detail, kind
38 }
39
40 type signature struct {
41         name, doc        string
42         params, results  []string
43         variadic         bool
44         needResultParens bool
45 }
46
47 func (s *signature) Format() string {
48         var b strings.Builder
49         b.WriteByte('(')
50         for i, p := range s.params {
51                 if i > 0 {
52                         b.WriteString(", ")
53                 }
54                 b.WriteString(p)
55         }
56         b.WriteByte(')')
57
58         // Add space between parameters and results.
59         if len(s.results) > 0 {
60                 b.WriteByte(' ')
61         }
62         if s.needResultParens {
63                 b.WriteByte('(')
64         }
65         for i, r := range s.results {
66                 if i > 0 {
67                         b.WriteString(", ")
68                 }
69                 b.WriteString(r)
70         }
71         if s.needResultParens {
72                 b.WriteByte(')')
73         }
74         return b.String()
75 }
76
77 func (s *signature) Params() []string {
78         return s.params
79 }
80
81 // NewBuiltinSignature returns signature for the builtin object with a given
82 // name, if a builtin object with the name exists.
83 func NewBuiltinSignature(ctx context.Context, s Snapshot, name string) (*signature, error) {
84         builtin, err := s.BuiltinPackage(ctx)
85         if err != nil {
86                 return nil, err
87         }
88         obj := builtin.Package.Scope.Lookup(name)
89         if obj == nil {
90                 return nil, fmt.Errorf("no builtin object for %s", name)
91         }
92         decl, ok := obj.Decl.(*ast.FuncDecl)
93         if !ok {
94                 return nil, fmt.Errorf("no function declaration for builtin: %s", name)
95         }
96         if decl.Type == nil {
97                 return nil, fmt.Errorf("no type for builtin decl %s", decl.Name)
98         }
99         var variadic bool
100         if decl.Type.Params.List != nil {
101                 numParams := len(decl.Type.Params.List)
102                 lastParam := decl.Type.Params.List[numParams-1]
103                 if _, ok := lastParam.Type.(*ast.Ellipsis); ok {
104                         variadic = true
105                 }
106         }
107         params, _ := formatFieldList(ctx, s, decl.Type.Params, variadic)
108         results, needResultParens := formatFieldList(ctx, s, decl.Type.Results, false)
109         d := decl.Doc.Text()
110         switch s.View().Options().HoverKind {
111         case SynopsisDocumentation:
112                 d = doc.Synopsis(d)
113         case NoDocumentation:
114                 d = ""
115         }
116         return &signature{
117                 doc:              d,
118                 name:             name,
119                 needResultParens: needResultParens,
120                 params:           params,
121                 results:          results,
122                 variadic:         variadic,
123         }, nil
124 }
125
126 var replacer = strings.NewReplacer(
127         `ComplexType`, `complex128`,
128         `FloatType`, `float64`,
129         `IntegerType`, `int`,
130 )
131
132 func formatFieldList(ctx context.Context, snapshot Snapshot, list *ast.FieldList, variadic bool) ([]string, bool) {
133         if list == nil {
134                 return nil, false
135         }
136         var writeResultParens bool
137         var result []string
138         for i := 0; i < len(list.List); i++ {
139                 if i >= 1 {
140                         writeResultParens = true
141                 }
142                 p := list.List[i]
143                 cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 4}
144                 b := &bytes.Buffer{}
145                 if err := cfg.Fprint(b, snapshot.FileSet(), p.Type); err != nil {
146                         event.Error(ctx, "unable to print type", nil, tag.Type.Of(p.Type))
147                         continue
148                 }
149                 typ := replacer.Replace(b.String())
150                 if len(p.Names) == 0 {
151                         result = append(result, typ)
152                 }
153                 for _, name := range p.Names {
154                         if name.Name != "" {
155                                 if i == 0 {
156                                         writeResultParens = true
157                                 }
158                                 result = append(result, fmt.Sprintf("%s %s", name.Name, typ))
159                         } else {
160                                 result = append(result, typ)
161                         }
162                 }
163         }
164         if variadic {
165                 result[len(result)-1] = strings.Replace(result[len(result)-1], "[]", "...", 1)
166         }
167         return result, writeResultParens
168 }
169
170 // NewSignature returns formatted signature for a types.Signature struct.
171 func NewSignature(ctx context.Context, s Snapshot, pkg Package, sig *types.Signature, comment *ast.CommentGroup, qf types.Qualifier) *signature {
172         params := make([]string, 0, sig.Params().Len())
173         for i := 0; i < sig.Params().Len(); i++ {
174                 el := sig.Params().At(i)
175                 typ := FormatVarType(ctx, s, pkg, el, qf)
176                 p := typ
177                 if el.Name() != "" {
178                         p = el.Name() + " " + typ
179                 }
180                 params = append(params, p)
181         }
182         var needResultParens bool
183         results := make([]string, 0, sig.Results().Len())
184         for i := 0; i < sig.Results().Len(); i++ {
185                 if i >= 1 {
186                         needResultParens = true
187                 }
188                 el := sig.Results().At(i)
189                 typ := FormatVarType(ctx, s, pkg, el, qf)
190                 if el.Name() == "" {
191                         results = append(results, typ)
192                 } else {
193                         if i == 0 {
194                                 needResultParens = true
195                         }
196                         results = append(results, el.Name()+" "+typ)
197                 }
198         }
199         var d string
200         if comment != nil {
201                 d = comment.Text()
202         }
203         switch s.View().Options().HoverKind {
204         case SynopsisDocumentation:
205                 d = doc.Synopsis(d)
206         case NoDocumentation:
207                 d = ""
208         }
209         return &signature{
210                 doc:              d,
211                 params:           params,
212                 results:          results,
213                 variadic:         sig.Variadic(),
214                 needResultParens: needResultParens,
215         }
216 }
217
218 // FormatVarType formats a *types.Var, accounting for type aliases.
219 // To do this, it looks in the AST of the file in which the object is declared.
220 // On any errors, it always fallbacks back to types.TypeString.
221 func FormatVarType(ctx context.Context, snapshot Snapshot, srcpkg Package, obj *types.Var, qf types.Qualifier) string {
222         pgf, pkg, err := FindPosInPackage(snapshot, srcpkg, obj.Pos())
223         if err != nil {
224                 return types.TypeString(obj.Type(), qf)
225         }
226
227         expr, err := varType(ctx, snapshot, pgf, obj)
228         if err != nil {
229                 return types.TypeString(obj.Type(), qf)
230         }
231
232         // The type names in the AST may not be correctly qualified.
233         // Determine the package name to use based on the package that originated
234         // the query and the package in which the type is declared.
235         // We then qualify the value by cloning the AST node and editing it.
236         clonedInfo := make(map[token.Pos]*types.PkgName)
237         qualified := cloneExpr(expr, pkg.GetTypesInfo(), clonedInfo)
238
239         // If the request came from a different package than the one in which the
240         // types are defined, we may need to modify the qualifiers.
241         qualified = qualifyExpr(qualified, srcpkg, pkg, clonedInfo, qf)
242         fmted := FormatNode(snapshot.FileSet(), qualified)
243         return fmted
244 }
245
246 // varType returns the type expression for a *types.Var.
247 func varType(ctx context.Context, snapshot Snapshot, pgf *ParsedGoFile, obj *types.Var) (ast.Expr, error) {
248         posToField, err := snapshot.PosToField(ctx, pgf)
249         if err != nil {
250                 return nil, err
251         }
252         field := posToField[obj.Pos()]
253         if field == nil {
254                 return nil, fmt.Errorf("no declaration for object %s", obj.Name())
255         }
256         typ, ok := field.Type.(ast.Expr)
257         if !ok {
258                 return nil, fmt.Errorf("unexpected type for node (%T)", field.Type)
259         }
260         return typ, nil
261 }
262
263 // qualifyExpr applies the "pkgName." prefix to any *ast.Ident in the expr.
264 func qualifyExpr(expr ast.Expr, srcpkg, pkg Package, clonedInfo map[token.Pos]*types.PkgName, qf types.Qualifier) ast.Expr {
265         ast.Inspect(expr, func(n ast.Node) bool {
266                 switch n := n.(type) {
267                 case *ast.ArrayType, *ast.ChanType, *ast.Ellipsis,
268                         *ast.FuncType, *ast.MapType, *ast.ParenExpr,
269                         *ast.StarExpr, *ast.StructType:
270                         // These are the only types that are cloned by cloneExpr below,
271                         // so these are the only types that we can traverse and potentially
272                         // modify. This is not an ideal approach, but it works for now.
273                         return true
274                 case *ast.SelectorExpr:
275                         // We may need to change any selectors in which the X is a package
276                         // name and the Sel is exported.
277                         x, ok := n.X.(*ast.Ident)
278                         if !ok {
279                                 return false
280                         }
281                         obj, ok := clonedInfo[x.Pos()]
282                         if !ok {
283                                 return false
284                         }
285                         pkgName := qf(obj.Imported())
286                         if pkgName != "" {
287                                 x.Name = pkgName
288                         }
289                         return false
290                 case *ast.Ident:
291                         if srcpkg == pkg {
292                                 return false
293                         }
294                         // Only add the qualifier if the identifier is exported.
295                         if ast.IsExported(n.Name) {
296                                 pkgName := qf(pkg.GetTypes())
297                                 n.Name = pkgName + "." + n.Name
298                         }
299                 }
300                 return false
301         })
302         return expr
303 }
304
305 // cloneExpr only clones expressions that appear in the parameters or return
306 // values of a function declaration. The original expression may be returned
307 // to the caller in 2 cases:
308 //    (1) The expression has no pointer fields.
309 //    (2) The expression cannot appear in an *ast.FuncType, making it
310 //        unnecessary to clone.
311 // This function also keeps track of selector expressions in which the X is a
312 // package name and marks them in a map along with their type information, so
313 // that this information can be used when rewriting the expression.
314 //
315 // NOTE: This function is tailored to the use case of qualifyExpr, and should
316 // be used with caution.
317 func cloneExpr(expr ast.Expr, info *types.Info, clonedInfo map[token.Pos]*types.PkgName) ast.Expr {
318         switch expr := expr.(type) {
319         case *ast.ArrayType:
320                 return &ast.ArrayType{
321                         Lbrack: expr.Lbrack,
322                         Elt:    cloneExpr(expr.Elt, info, clonedInfo),
323                         Len:    expr.Len,
324                 }
325         case *ast.ChanType:
326                 return &ast.ChanType{
327                         Arrow: expr.Arrow,
328                         Begin: expr.Begin,
329                         Dir:   expr.Dir,
330                         Value: cloneExpr(expr.Value, info, clonedInfo),
331                 }
332         case *ast.Ellipsis:
333                 return &ast.Ellipsis{
334                         Ellipsis: expr.Ellipsis,
335                         Elt:      cloneExpr(expr.Elt, info, clonedInfo),
336                 }
337         case *ast.FuncType:
338                 return &ast.FuncType{
339                         Func:    expr.Func,
340                         Params:  cloneFieldList(expr.Params, info, clonedInfo),
341                         Results: cloneFieldList(expr.Results, info, clonedInfo),
342                 }
343         case *ast.Ident:
344                 return cloneIdent(expr)
345         case *ast.MapType:
346                 return &ast.MapType{
347                         Map:   expr.Map,
348                         Key:   cloneExpr(expr.Key, info, clonedInfo),
349                         Value: cloneExpr(expr.Value, info, clonedInfo),
350                 }
351         case *ast.ParenExpr:
352                 return &ast.ParenExpr{
353                         Lparen: expr.Lparen,
354                         Rparen: expr.Rparen,
355                         X:      cloneExpr(expr.X, info, clonedInfo),
356                 }
357         case *ast.SelectorExpr:
358                 s := &ast.SelectorExpr{
359                         Sel: cloneIdent(expr.Sel),
360                         X:   cloneExpr(expr.X, info, clonedInfo),
361                 }
362                 if x, ok := expr.X.(*ast.Ident); ok && ast.IsExported(expr.Sel.Name) {
363                         if obj, ok := info.ObjectOf(x).(*types.PkgName); ok {
364                                 clonedInfo[s.X.Pos()] = obj
365                         }
366                 }
367                 return s
368         case *ast.StarExpr:
369                 return &ast.StarExpr{
370                         Star: expr.Star,
371                         X:    cloneExpr(expr.X, info, clonedInfo),
372                 }
373         case *ast.StructType:
374                 return &ast.StructType{
375                         Struct:     expr.Struct,
376                         Fields:     cloneFieldList(expr.Fields, info, clonedInfo),
377                         Incomplete: expr.Incomplete,
378                 }
379         default:
380                 return expr
381         }
382 }
383
384 func cloneFieldList(fl *ast.FieldList, info *types.Info, clonedInfo map[token.Pos]*types.PkgName) *ast.FieldList {
385         if fl == nil {
386                 return nil
387         }
388         if fl.List == nil {
389                 return &ast.FieldList{
390                         Closing: fl.Closing,
391                         Opening: fl.Opening,
392                 }
393         }
394         list := make([]*ast.Field, 0, len(fl.List))
395         for _, f := range fl.List {
396                 var names []*ast.Ident
397                 for _, n := range f.Names {
398                         names = append(names, cloneIdent(n))
399                 }
400                 list = append(list, &ast.Field{
401                         Comment: f.Comment,
402                         Doc:     f.Doc,
403                         Names:   names,
404                         Tag:     f.Tag,
405                         Type:    cloneExpr(f.Type, info, clonedInfo),
406                 })
407         }
408         return &ast.FieldList{
409                 Closing: fl.Closing,
410                 Opening: fl.Opening,
411                 List:    list,
412         }
413 }
414
415 func cloneIdent(ident *ast.Ident) *ast.Ident {
416         return &ast.Ident{
417                 NamePos: ident.NamePos,
418                 Name:    ident.Name,
419                 Obj:     ident.Obj,
420         }
421 }