Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / source / completion / completion_format.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 completion
6
7 import (
8         "context"
9         "fmt"
10         "go/types"
11         "strings"
12
13         "golang.org/x/tools/internal/event"
14         "golang.org/x/tools/internal/imports"
15         "golang.org/x/tools/internal/lsp/debug/tag"
16         "golang.org/x/tools/internal/lsp/protocol"
17         "golang.org/x/tools/internal/lsp/snippet"
18         "golang.org/x/tools/internal/lsp/source"
19         "golang.org/x/tools/internal/span"
20         errors "golang.org/x/xerrors"
21 )
22
23 // item formats a candidate to a CompletionItem.
24 func (c *completer) item(ctx context.Context, cand candidate) (CompletionItem, error) {
25         obj := cand.obj
26
27         // if the object isn't a valid match against the surrounding, return early.
28         matchScore := c.matcher.Score(cand.name)
29         if matchScore <= 0 {
30                 return CompletionItem{}, errors.New("not a surrounding match")
31         }
32         cand.score *= float64(matchScore)
33
34         // Ignore deep candidates that wont be in the MaxDeepCompletions anyway.
35         if len(cand.path) != 0 && !c.deepState.isHighScore(cand.score) {
36                 return CompletionItem{}, errors.New("not a high scoring candidate")
37         }
38
39         // Handle builtin types separately.
40         if obj.Parent() == types.Universe {
41                 return c.formatBuiltin(ctx, cand)
42         }
43
44         var (
45                 label         = cand.name
46                 detail        = types.TypeString(obj.Type(), c.qf)
47                 insert        = label
48                 kind          = protocol.TextCompletion
49                 snip          *snippet.Builder
50                 protocolEdits []protocol.TextEdit
51         )
52         if obj.Type() == nil {
53                 detail = ""
54         }
55
56         // expandFuncCall mutates the completion label, detail, and snippet
57         // to that of an invocation of sig.
58         expandFuncCall := func(sig *types.Signature) {
59                 s := source.NewSignature(ctx, c.snapshot, c.pkg, sig, nil, c.qf)
60                 snip = c.functionCallSnippet(label, s.Params())
61                 detail = "func" + s.Format()
62         }
63
64         switch obj := obj.(type) {
65         case *types.TypeName:
66                 detail, kind = source.FormatType(obj.Type(), c.qf)
67         case *types.Const:
68                 kind = protocol.ConstantCompletion
69         case *types.Var:
70                 if _, ok := obj.Type().(*types.Struct); ok {
71                         detail = "struct{...}" // for anonymous structs
72                 } else if obj.IsField() {
73                         detail = source.FormatVarType(ctx, c.snapshot, c.pkg, obj, c.qf)
74                 }
75                 if obj.IsField() {
76                         kind = protocol.FieldCompletion
77                         snip = c.structFieldSnippet(cand, label, detail)
78                 } else {
79                         kind = protocol.VariableCompletion
80                 }
81                 if obj.Type() == nil {
82                         break
83                 }
84
85                 if sig, ok := obj.Type().Underlying().(*types.Signature); ok && cand.expandFuncCall {
86                         expandFuncCall(sig)
87                 }
88         case *types.Func:
89                 sig, ok := obj.Type().Underlying().(*types.Signature)
90                 if !ok {
91                         break
92                 }
93                 kind = protocol.FunctionCompletion
94                 if sig != nil && sig.Recv() != nil {
95                         kind = protocol.MethodCompletion
96                 }
97
98                 if cand.expandFuncCall {
99                         expandFuncCall(sig)
100                 }
101         case *types.PkgName:
102                 kind = protocol.ModuleCompletion
103                 detail = fmt.Sprintf("%q", obj.Imported().Path())
104         case *types.Label:
105                 kind = protocol.ConstantCompletion
106                 detail = "label"
107         }
108
109         // If this candidate needs an additional import statement,
110         // add the additional text edits needed.
111         if cand.imp != nil {
112                 addlEdits, err := c.importEdits(cand.imp)
113                 if err != nil {
114                         return CompletionItem{}, err
115                 }
116
117                 protocolEdits = append(protocolEdits, addlEdits...)
118                 if kind != protocol.ModuleCompletion {
119                         if detail != "" {
120                                 detail += " "
121                         }
122                         detail += fmt.Sprintf("(from %q)", cand.imp.importPath)
123                 }
124         }
125
126         // Prepend "&" or "*" operator as appropriate.
127         var prefixOp string
128         if cand.takeAddress {
129                 prefixOp = "&"
130         } else if cand.makePointer {
131                 prefixOp = "*"
132         } else if cand.dereference > 0 {
133                 prefixOp = strings.Repeat("*", cand.dereference)
134         }
135
136         if prefixOp != "" {
137                 // If we are in a selector, add an edit to place prefix before selector.
138                 if sel := enclosingSelector(c.path, c.pos); sel != nil {
139                         edits, err := prependEdit(c.snapshot.FileSet(), c.mapper, sel, prefixOp)
140                         if err != nil {
141                                 return CompletionItem{}, err
142                         }
143                         protocolEdits = append(protocolEdits, edits...)
144                 } else {
145                         // If there is no selector, just stick the prefix at the start.
146                         insert = prefixOp + insert
147                 }
148
149                 label = prefixOp + label
150         }
151
152         // Add variadic "..." if we are filling in a variadic param.
153         if cand.variadic {
154                 insert += "..."
155                 if snip != nil {
156                         snip.WriteText("...")
157                 }
158         }
159
160         detail = strings.TrimPrefix(detail, "untyped ")
161         // override computed detail with provided detail, if something is provided.
162         if cand.detail != "" {
163                 detail = cand.detail
164         }
165         item := CompletionItem{
166                 Label:               label,
167                 InsertText:          insert,
168                 AdditionalTextEdits: protocolEdits,
169                 Detail:              detail,
170                 Kind:                kind,
171                 Score:               cand.score,
172                 Depth:               len(cand.path),
173                 snippet:             snip,
174                 obj:                 obj,
175         }
176         // If the user doesn't want documentation for completion items.
177         if !c.opts.documentation {
178                 return item, nil
179         }
180         pos := c.snapshot.FileSet().Position(obj.Pos())
181
182         // We ignore errors here, because some types, like "unsafe" or "error",
183         // may not have valid positions that we can use to get documentation.
184         if !pos.IsValid() {
185                 return item, nil
186         }
187         uri := span.URIFromPath(pos.Filename)
188
189         // Find the source file of the candidate, starting from a package
190         // that should have it in its dependencies.
191         searchPkg := c.pkg
192         if cand.imp != nil && cand.imp.pkg != nil {
193                 searchPkg = cand.imp.pkg
194         }
195
196         pgf, pkg, err := source.FindPosInPackage(c.snapshot, searchPkg, obj.Pos())
197         if err != nil {
198                 return item, nil
199         }
200
201         posToDecl, err := c.snapshot.PosToDecl(ctx, pgf)
202         if err != nil {
203                 return CompletionItem{}, err
204         }
205         decl := posToDecl[obj.Pos()]
206         if decl == nil {
207                 return item, nil
208         }
209
210         hover, err := source.HoverInfo(ctx, pkg, obj, decl)
211         if err != nil {
212                 event.Error(ctx, "failed to find Hover", err, tag.URI.Of(uri))
213                 return item, nil
214         }
215         item.Documentation = hover.Synopsis
216         if c.opts.fullDocumentation {
217                 item.Documentation = hover.FullDocumentation
218         }
219
220         return item, nil
221 }
222
223 // importEdits produces the text edits necessary to add the given import to the current file.
224 func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
225         if imp == nil {
226                 return nil, nil
227         }
228
229         pgf, err := c.pkg.File(span.URIFromPath(c.filename))
230         if err != nil {
231                 return nil, err
232         }
233
234         return source.ComputeOneImportFixEdits(c.snapshot, pgf, &imports.ImportFix{
235                 StmtInfo: imports.ImportInfo{
236                         ImportPath: imp.importPath,
237                         Name:       imp.name,
238                 },
239                 // IdentName is unused on this path and is difficult to get.
240                 FixType: imports.AddImport,
241         })
242 }
243
244 func (c *completer) formatBuiltin(ctx context.Context, cand candidate) (CompletionItem, error) {
245         obj := cand.obj
246         item := CompletionItem{
247                 Label:      obj.Name(),
248                 InsertText: obj.Name(),
249                 Score:      cand.score,
250         }
251         switch obj.(type) {
252         case *types.Const:
253                 item.Kind = protocol.ConstantCompletion
254         case *types.Builtin:
255                 item.Kind = protocol.FunctionCompletion
256                 sig, err := source.NewBuiltinSignature(ctx, c.snapshot, obj.Name())
257                 if err != nil {
258                         return CompletionItem{}, err
259                 }
260                 item.Detail = "func" + sig.Format()
261                 item.snippet = c.functionCallSnippet(obj.Name(), sig.Params())
262         case *types.TypeName:
263                 if types.IsInterface(obj.Type()) {
264                         item.Kind = protocol.InterfaceCompletion
265                 } else {
266                         item.Kind = protocol.ClassCompletion
267                 }
268         case *types.Nil:
269                 item.Kind = protocol.VariableCompletion
270         }
271         return item, nil
272 }