.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / source / 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         var prefix, suffix string
127
128         // Prepend "&" or "*" operator as appropriate.
129         if cand.takeAddress {
130                 prefix = "&"
131         } else if cand.makePointer {
132                 prefix = "*"
133         } else if cand.dereference > 0 {
134                 prefix = strings.Repeat("*", cand.dereference)
135         }
136
137         // Include "*" and "&" prefixes in the label.
138         label = prefix + label
139
140         if cand.convertTo != nil {
141                 typeName := types.TypeString(cand.convertTo, c.qf)
142
143                 switch cand.convertTo.(type) {
144                 // We need extra parens when casting to these types. For example,
145                 // we need "(*int)(foo)", not "*int(foo)".
146                 case *types.Pointer, *types.Signature:
147                         typeName = "(" + typeName + ")"
148                 }
149
150                 prefix = typeName + "(" + prefix
151                 suffix = ")"
152         }
153         // Add variadic "..." only if snippets if enabled or cand is not a function
154         if cand.variadic && (c.opts.snippets || !cand.expandFuncCall) {
155                 suffix += "..."
156         }
157
158         if prefix != "" {
159                 // If we are in a selector, add an edit to place prefix before selector.
160                 if sel := enclosingSelector(c.path, c.pos); sel != nil {
161                         edits, err := prependEdit(c.snapshot.FileSet(), c.mapper, sel, prefix)
162                         if err != nil {
163                                 return CompletionItem{}, err
164                         }
165                         protocolEdits = append(protocolEdits, edits...)
166                 } else {
167                         // If there is no selector, just stick the prefix at the start.
168                         insert = prefix + insert
169                         if snip != nil {
170                                 snip.PrependText(prefix)
171                         }
172                 }
173         }
174
175         if suffix != "" {
176                 insert += suffix
177                 if snip != nil {
178                         snip.WriteText(suffix)
179                 }
180         }
181
182         detail = strings.TrimPrefix(detail, "untyped ")
183         // override computed detail with provided detail, if something is provided.
184         if cand.detail != "" {
185                 detail = cand.detail
186         }
187         item := CompletionItem{
188                 Label:               label,
189                 InsertText:          insert,
190                 AdditionalTextEdits: protocolEdits,
191                 Detail:              detail,
192                 Kind:                kind,
193                 Score:               cand.score,
194                 Depth:               len(cand.path),
195                 snippet:             snip,
196                 obj:                 obj,
197         }
198         // If the user doesn't want documentation for completion items.
199         if !c.opts.documentation {
200                 return item, nil
201         }
202         pos := c.snapshot.FileSet().Position(obj.Pos())
203
204         // We ignore errors here, because some types, like "unsafe" or "error",
205         // may not have valid positions that we can use to get documentation.
206         if !pos.IsValid() {
207                 return item, nil
208         }
209         uri := span.URIFromPath(pos.Filename)
210
211         // Find the source file of the candidate, starting from a package
212         // that should have it in its dependencies.
213         searchPkg := c.pkg
214         if cand.imp != nil && cand.imp.pkg != nil {
215                 searchPkg = cand.imp.pkg
216         }
217
218         pgf, pkg, err := source.FindPosInPackage(c.snapshot, searchPkg, obj.Pos())
219         if err != nil {
220                 return item, nil
221         }
222
223         posToDecl, err := c.snapshot.PosToDecl(ctx, pgf)
224         if err != nil {
225                 return CompletionItem{}, err
226         }
227         decl := posToDecl[obj.Pos()]
228         if decl == nil {
229                 return item, nil
230         }
231
232         hover, err := source.HoverInfo(ctx, pkg, obj, decl)
233         if err != nil {
234                 event.Error(ctx, "failed to find Hover", err, tag.URI.Of(uri))
235                 return item, nil
236         }
237         item.Documentation = hover.Synopsis
238         if c.opts.fullDocumentation {
239                 item.Documentation = hover.FullDocumentation
240         }
241
242         return item, nil
243 }
244
245 // importEdits produces the text edits necessary to add the given import to the current file.
246 func (c *completer) importEdits(imp *importInfo) ([]protocol.TextEdit, error) {
247         if imp == nil {
248                 return nil, nil
249         }
250
251         pgf, err := c.pkg.File(span.URIFromPath(c.filename))
252         if err != nil {
253                 return nil, err
254         }
255
256         return source.ComputeOneImportFixEdits(c.snapshot, pgf, &imports.ImportFix{
257                 StmtInfo: imports.ImportInfo{
258                         ImportPath: imp.importPath,
259                         Name:       imp.name,
260                 },
261                 // IdentName is unused on this path and is difficult to get.
262                 FixType: imports.AddImport,
263         })
264 }
265
266 func (c *completer) formatBuiltin(ctx context.Context, cand candidate) (CompletionItem, error) {
267         obj := cand.obj
268         item := CompletionItem{
269                 Label:      obj.Name(),
270                 InsertText: obj.Name(),
271                 Score:      cand.score,
272         }
273         switch obj.(type) {
274         case *types.Const:
275                 item.Kind = protocol.ConstantCompletion
276         case *types.Builtin:
277                 item.Kind = protocol.FunctionCompletion
278                 sig, err := source.NewBuiltinSignature(ctx, c.snapshot, obj.Name())
279                 if err != nil {
280                         return CompletionItem{}, err
281                 }
282                 item.Detail = "func" + sig.Format()
283                 item.snippet = c.functionCallSnippet(obj.Name(), sig.Params())
284         case *types.TypeName:
285                 if types.IsInterface(obj.Type()) {
286                         item.Kind = protocol.InterfaceCompletion
287                 } else {
288                         item.Kind = protocol.ClassCompletion
289                 }
290         case *types.Nil:
291                 item.Kind = protocol.VariableCompletion
292         }
293         return item, nil
294 }